]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Update eslint-config-chartjs to v0.3.0 (#8406)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Wed, 10 Feb 2021 13:21:39 +0000 (15:21 +0200)
committerGitHub <noreply@github.com>
Wed, 10 Feb 2021 13:21:39 +0000 (08:21 -0500)
365 files changed:
package-lock.json
package.json
samples/.eslintrc.yml
src/controllers/controller.bar.js
src/controllers/controller.bubble.js
src/controllers/controller.doughnut.js
src/controllers/controller.line.js
src/controllers/controller.pie.js
src/controllers/controller.polarArea.js
src/controllers/controller.radar.js
src/controllers/controller.scatter.js
src/core/core.adapters.js
src/core/core.animation.js
src/core/core.animations.js
src/core/core.animator.js
src/core/core.config.js
src/core/core.controller.js
src/core/core.datasetController.js
src/core/core.defaults.js
src/core/core.element.js
src/core/core.interaction.js
src/core/core.intl.js
src/core/core.layouts.js
src/core/core.plugins.js
src/core/core.registry.js
src/core/core.scale.js
src/core/core.ticks.js
src/core/core.typedRegistry.js
src/elements/element.arc.js
src/elements/element.bar.js
src/elements/element.line.js
src/elements/element.point.js
src/helpers/helpers.canvas.js
src/helpers/helpers.collection.js
src/helpers/helpers.color.js
src/helpers/helpers.core.js
src/helpers/helpers.curve.js
src/helpers/helpers.dom.js
src/helpers/helpers.easing.js
src/helpers/helpers.extras.js
src/helpers/helpers.interpolation.js
src/helpers/helpers.math.js
src/helpers/helpers.options.js
src/helpers/helpers.rtl.js
src/helpers/helpers.segment.js
src/index.js
src/platform/platform.base.js
src/platform/platform.basic.js
src/platform/platform.dom.js
src/plugins/plugin.decimation.js
src/plugins/plugin.filler.js
src/plugins/plugin.legend.js
src/plugins/plugin.title.js
src/plugins/plugin.tooltip.js
src/scales/scale.category.js
src/scales/scale.linear.js
src/scales/scale.linearbase.js
src/scales/scale.logarithmic.js
src/scales/scale.radialLinear.js
src/scales/scale.time.js
src/scales/scale.timeseries.js
test/BasicChartWebWorker.js
test/fixtures/controller.bar/backgroundColor/indexable.js
test/fixtures/controller.bar/backgroundColor/loopable.js
test/fixtures/controller.bar/backgroundColor/scriptable.js
test/fixtures/controller.bar/backgroundColor/value.js
test/fixtures/controller.bar/bar-base-value.js
test/fixtures/controller.bar/bar-default-begin-at-zero.js
test/fixtures/controller.bar/bar-skip-null-object-data.js
test/fixtures/controller.bar/bar-skip-null.js
test/fixtures/controller.bar/border-radius.js
test/fixtures/controller.bar/borderColor/indexable.js
test/fixtures/controller.bar/borderColor/scriptable.js
test/fixtures/controller.bar/borderColor/value.js
test/fixtures/controller.bar/borderSkipped/indexable.js
test/fixtures/controller.bar/borderSkipped/scriptable.js
test/fixtures/controller.bar/borderSkipped/value.js
test/fixtures/controller.bar/borderWidth/indexable-object.js
test/fixtures/controller.bar/borderWidth/indexable.js
test/fixtures/controller.bar/borderWidth/negative.js
test/fixtures/controller.bar/borderWidth/object.js
test/fixtures/controller.bar/borderWidth/scriptable-object.js
test/fixtures/controller.bar/borderWidth/scriptable.js
test/fixtures/controller.bar/borderWidth/value.js
test/fixtures/controller.bar/chart-area-clip.js
test/fixtures/controller.bar/data/object.js
test/fixtures/controller.bar/data/parsing.js
test/fixtures/controller.bar/floatBar/data-as-objects-horizontal.js
test/fixtures/controller.bar/floatBar/data-as-objects.js
test/fixtures/controller.bar/horizontal-borders.js
test/fixtures/controller.bar/minBarLength/horizontal-neg.js
test/fixtures/controller.bar/minBarLength/horizontal-pos.js
test/fixtures/controller.bar/minBarLength/horizontal.js
test/fixtures/controller.bar/minBarLength/vertical-neg.js
test/fixtures/controller.bar/minBarLength/vertical-pos.js
test/fixtures/controller.bar/minBarLength/vertical.js
test/fixtures/controller.bar/stacking/logarithmic-strings.js
test/fixtures/controller.bar/stacking/logarithmic.js
test/fixtures/controller.bubble/clip.js
test/fixtures/controller.bubble/radius-data.js
test/fixtures/controller.bubble/radius-scriptable.js
test/fixtures/controller.doughnut/backgroundColor/indexable.js
test/fixtures/controller.doughnut/backgroundColor/scriptable.js
test/fixtures/controller.doughnut/backgroundColor/value.js
test/fixtures/controller.doughnut/borderAlign/indexable.js
test/fixtures/controller.doughnut/borderAlign/scriptable.js
test/fixtures/controller.doughnut/borderAlign/value.js
test/fixtures/controller.doughnut/borderColor/indexable.js
test/fixtures/controller.doughnut/borderColor/scriptable.js
test/fixtures/controller.doughnut/borderColor/value.js
test/fixtures/controller.doughnut/borderWidth/indexable.js
test/fixtures/controller.doughnut/borderWidth/scriptable.js
test/fixtures/controller.doughnut/borderWidth/value.js
test/fixtures/controller.doughnut/doughnut-circumference-per-dataset.js
test/fixtures/controller.doughnut/doughnut-hidden.js
test/fixtures/controller.doughnut/doughnut-rotation-per-dataset.js
test/fixtures/controller.line/backgroundColor/scriptable.js
test/fixtures/controller.line/backgroundColor/value.js
test/fixtures/controller.line/borderCapStyle/scriptable.js
test/fixtures/controller.line/borderCapStyle/value.js
test/fixtures/controller.line/borderColor/scriptable.js
test/fixtures/controller.line/borderColor/value.js
test/fixtures/controller.line/borderDash/scriptable.js
test/fixtures/controller.line/borderDash/value.js
test/fixtures/controller.line/borderDashOffset/scriptable.js
test/fixtures/controller.line/borderDashOffset/value.js
test/fixtures/controller.line/borderJoinStyle/scriptable.js
test/fixtures/controller.line/borderJoinStyle/value.js
test/fixtures/controller.line/borderWidth/scriptable.js
test/fixtures/controller.line/borderWidth/value.js
test/fixtures/controller.line/borderWidth/zero.js
test/fixtures/controller.line/cubicInterpolationMode/scriptable.js
test/fixtures/controller.line/cubicInterpolationMode/value.js
test/fixtures/controller.line/fill/order-default.js
test/fixtures/controller.line/fill/order.js
test/fixtures/controller.line/fill/scriptable.js
test/fixtures/controller.line/fill/value.js
test/fixtures/controller.line/pointBackgroundColor/indexable.js
test/fixtures/controller.line/pointBackgroundColor/scriptable.js
test/fixtures/controller.line/pointBackgroundColor/value.js
test/fixtures/controller.line/pointBorderColor/indexable.js
test/fixtures/controller.line/pointBorderColor/scriptable.js
test/fixtures/controller.line/pointBorderColor/value.js
test/fixtures/controller.line/pointBorderWidth/indexable.js
test/fixtures/controller.line/pointBorderWidth/scriptable.js
test/fixtures/controller.line/pointBorderWidth/value.js
test/fixtures/controller.line/pointStyle/indexable.js
test/fixtures/controller.line/pointStyle/scriptable.js
test/fixtures/controller.line/pointStyle/value.js
test/fixtures/controller.line/radius/indexable.js
test/fixtures/controller.line/radius/scriptable.js
test/fixtures/controller.line/radius/value.js
test/fixtures/controller.line/rotation/indexable.js
test/fixtures/controller.line/rotation/scriptable.js
test/fixtures/controller.line/rotation/value.js
test/fixtures/controller.line/showLine/dataset.js
test/fixtures/controller.line/showLine/false.js
test/fixtures/controller.line/stacking/order-default.js
test/fixtures/controller.line/stacking/order-specified.js
test/fixtures/controller.line/stacking/stacked-scatter.js
test/fixtures/controller.polarArea/backgroundColor/indexable-dataset.js
test/fixtures/controller.polarArea/backgroundColor/indexable-element-options.js
test/fixtures/controller.polarArea/backgroundColor/scriptable-dataset.js
test/fixtures/controller.polarArea/backgroundColor/scriptable-element-options.js
test/fixtures/controller.polarArea/backgroundColor/value-dataset.js
test/fixtures/controller.polarArea/backgroundColor/value-element-options.js
test/fixtures/controller.polarArea/borderAlign/indexable-dataset.js
test/fixtures/controller.polarArea/borderAlign/indexable-element-options.js
test/fixtures/controller.polarArea/borderAlign/scriptable-dataset.js
test/fixtures/controller.polarArea/borderAlign/scriptable-element-options.js
test/fixtures/controller.polarArea/borderAlign/value-dataset.js
test/fixtures/controller.polarArea/borderAlign/value-element-options.js
test/fixtures/controller.polarArea/borderColor/indexable-dataset.js
test/fixtures/controller.polarArea/borderColor/indexable-element-options.js
test/fixtures/controller.polarArea/borderColor/scriptable-dataset.js
test/fixtures/controller.polarArea/borderColor/scriptable-element-options.js
test/fixtures/controller.polarArea/borderColor/value-dataset.js
test/fixtures/controller.polarArea/borderColor/value-element-options.js
test/fixtures/controller.polarArea/borderWidth/indexable-dataset.js
test/fixtures/controller.polarArea/borderWidth/indexable-element-options.js
test/fixtures/controller.polarArea/borderWidth/scriptable-dataset.js
test/fixtures/controller.polarArea/borderWidth/scriptable-element-options.js
test/fixtures/controller.polarArea/borderWidth/value-dataset.js
test/fixtures/controller.polarArea/borderWidth/value-element-options.js
test/fixtures/controller.radar/backgroundColor/scriptable.js
test/fixtures/controller.radar/backgroundColor/value.js
test/fixtures/controller.radar/borderCapStyle/scriptable.js
test/fixtures/controller.radar/borderCapStyle/value.js
test/fixtures/controller.radar/borderColor/scriptable.js
test/fixtures/controller.radar/borderColor/value.js
test/fixtures/controller.radar/borderDash/scriptable.js
test/fixtures/controller.radar/borderDash/value.js
test/fixtures/controller.radar/borderDashOffset/scriptable.js
test/fixtures/controller.radar/borderDashOffset/value.js
test/fixtures/controller.radar/borderJoinStyle/scriptable.js
test/fixtures/controller.radar/borderJoinStyle/value.js
test/fixtures/controller.radar/borderWidth/scriptable.js
test/fixtures/controller.radar/borderWidth/value.js
test/fixtures/controller.radar/borderWidth/zero.js
test/fixtures/controller.radar/fill/scriptable.js
test/fixtures/controller.radar/fill/value.js
test/fixtures/controller.radar/pointBackgroundColor/indexable.js
test/fixtures/controller.radar/pointBackgroundColor/scriptable.js
test/fixtures/controller.radar/pointBackgroundColor/value.js
test/fixtures/controller.radar/pointBorderColor/indexable.js
test/fixtures/controller.radar/pointBorderColor/scriptable.js
test/fixtures/controller.radar/pointBorderColor/value.js
test/fixtures/controller.radar/pointBorderWidth/indexable.js
test/fixtures/controller.radar/pointBorderWidth/scriptable.js
test/fixtures/controller.radar/pointBorderWidth/value.js
test/fixtures/controller.radar/pointStyle/indexable.js
test/fixtures/controller.radar/pointStyle/scriptable.js
test/fixtures/controller.radar/pointStyle/value.js
test/fixtures/controller.radar/radius/indexable.js
test/fixtures/controller.radar/radius/scriptable.js
test/fixtures/controller.radar/radius/value.js
test/fixtures/controller.radar/rotation/indexable.js
test/fixtures/controller.radar/rotation/scriptable.js
test/fixtures/controller.radar/rotation/value.js
test/fixtures/controller.radar/showLine/value.js
test/fixtures/controller.scatter/showLine/true.js
test/fixtures/controller.scatter/showLine/undefined.js
test/fixtures/core.layouts/long-labels.js
test/fixtures/core.layouts/scriptable.js
test/fixtures/core.scale/crossAlignment/cross-align-bottom-center.js
test/fixtures/core.scale/crossAlignment/cross-align-bottom-far.js
test/fixtures/core.scale/crossAlignment/cross-align-bottom-near.js
test/fixtures/core.scale/crossAlignment/cross-align-left-center.js
test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.js
test/fixtures/core.scale/crossAlignment/cross-align-left-far.js
test/fixtures/core.scale/crossAlignment/cross-align-left-near.js
test/fixtures/core.scale/crossAlignment/cross-align-right-center.js
test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.js
test/fixtures/core.scale/crossAlignment/cross-align-right-far.js
test/fixtures/core.scale/crossAlignment/cross-align-right-near.js
test/fixtures/core.scale/crossAlignment/cross-align-top-center.js
test/fixtures/core.scale/crossAlignment/cross-align-top-far.js
test/fixtures/core.scale/crossAlignment/cross-align-top-near.js
test/fixtures/core.scale/label-align-center.js
test/fixtures/core.scale/label-align-end.js
test/fixtures/core.scale/label-align-start.js
test/fixtures/element.line/default.js
test/fixtures/element.line/skip/all.js
test/fixtures/element.line/skip/first-span.js
test/fixtures/element.line/skip/first.js
test/fixtures/element.line/skip/last-span.js
test/fixtures/element.line/skip/last.js
test/fixtures/element.line/skip/middle-span.js
test/fixtures/element.line/skip/middle.js
test/fixtures/element.line/stepped/after.js
test/fixtures/element.line/stepped/before.js
test/fixtures/element.line/stepped/default.js
test/fixtures/element.line/stepped/middle.js
test/fixtures/element.line/tension/default.js
test/fixtures/element.line/tension/one.js
test/fixtures/element.line/tension/zero.js
test/fixtures/element.point/point-style-image.js
test/fixtures/element.point/rotation.js
test/fixtures/mixed/bar+line.js
test/fixtures/plugin.filler/fill-line-dataset-interpolated.js
test/fixtures/plugin.filler/fill-radar-dataset-order.js
test/fixtures/plugin.legend/title/bottom-center-center.js
test/fixtures/plugin.legend/title/bottom-end-end.js
test/fixtures/plugin.legend/title/bottom-start-start.js
test/fixtures/plugin.legend/title/left-center-center.js
test/fixtures/plugin.legend/title/left-end-end.js
test/fixtures/plugin.legend/title/left-start-start.js
test/fixtures/plugin.legend/title/right-center-center.js
test/fixtures/plugin.legend/title/right-end-end.js
test/fixtures/plugin.legend/title/right-start-start.js
test/fixtures/plugin.legend/title/top-center-center.js
test/fixtures/plugin.legend/title/top-end-end.js
test/fixtures/plugin.legend/title/top-start-start.js
test/fixtures/plugin.tooltip/opacity.js
test/fixtures/plugin.tooltip/point-style.js
test/fixtures/scale.category/ticks-from-data.js
test/fixtures/scale.linear/tiny-numbers.js
test/fixtures/scale.radialLinear/anglelines-indexable.js
test/fixtures/scale.radialLinear/anglelines-scriptable.js
test/fixtures/scale.radialLinear/gridlines-scriptable.js
test/fixtures/scale.time/autoskip-major.js
test/fixtures/scale.time/bar-large-gap-between-data.js
test/fixtures/scale.time/custom-parser.js
test/fixtures/scale.time/data-ty.js
test/fixtures/scale.time/data-xy.js
test/fixtures/scale.time/labels-date.js
test/fixtures/scale.time/labels-strings.js
test/fixtures/scale.time/labels.js
test/fixtures/scale.time/negative-times.js
test/fixtures/scale.time/source-auto-linear.js
test/fixtures/scale.time/source-data-linear.js
test/fixtures/scale.time/source-labels-linear-offset-min-max.js
test/fixtures/scale.time/source-labels-linear.js
test/fixtures/scale.time/ticks-capacity.js
test/fixtures/scale.time/ticks-minunit.js
test/fixtures/scale.time/ticks-reverse-linear-min-max.js
test/fixtures/scale.time/ticks-reverse-linear.js
test/fixtures/scale.time/ticks-reverse-offset.js
test/fixtures/scale.time/ticks-reverse.js
test/fixtures/scale.time/ticks-round.js
test/fixtures/scale.time/ticks-stepsize.js
test/fixtures/scale.time/ticks-unit.js
test/fixtures/scale.timeseries/financial-daily.js
test/fixtures/scale.timeseries/source-auto.js
test/fixtures/scale.timeseries/source-data-offset-min-max.js
test/fixtures/scale.timeseries/source-data.js
test/fixtures/scale.timeseries/source-labels-offset-min-max.js
test/fixtures/scale.timeseries/source-labels.js
test/fixtures/scale.timeseries/ticks-reverse-max.js
test/fixtures/scale.timeseries/ticks-reverse-min-max.js
test/fixtures/scale.timeseries/ticks-reverse-min.js
test/fixtures/scale.timeseries/ticks-reverse.js
test/index.js
test/specs/controller.bar.tests.js
test/specs/controller.bubble.tests.js
test/specs/controller.doughnut.tests.js
test/specs/controller.line.tests.js
test/specs/controller.polarArea.tests.js
test/specs/controller.radar.tests.js
test/specs/controller.scatter.tests.js
test/specs/core.animation.tests.js
test/specs/core.animations.tests.js
test/specs/core.animator.tests.js
test/specs/core.controller.tests.js
test/specs/core.datasetController.tests.js
test/specs/core.defaults.tests.js
test/specs/core.element.tests.js
test/specs/core.helpers.tests.js
test/specs/core.interaction.tests.js
test/specs/core.layouts.tests.js
test/specs/core.plugin.tests.js
test/specs/core.registry.tests.js
test/specs/core.scale.tests.js
test/specs/core.ticks.tests.js
test/specs/element.arc.tests.js
test/specs/element.bar.tests.js
test/specs/element.line.tests.js
test/specs/element.point.tests.js
test/specs/global.defaults.tests.js
test/specs/global.namespace.tests.js
test/specs/helpers.canvas.tests.js
test/specs/helpers.collection.tests.js
test/specs/helpers.color.tests.js
test/specs/helpers.core.tests.js
test/specs/helpers.curve.tests.js
test/specs/helpers.dom.tests.js
test/specs/helpers.easing.tests.js
test/specs/helpers.interpolation.tests.js
test/specs/helpers.math.tests.js
test/specs/helpers.options.tests.js
test/specs/helpers.segment.tests.js
test/specs/mixed.tests.js
test/specs/platform.basic.tests.js
test/specs/platform.dom.tests.js
test/specs/plugin.filler.tests.js
test/specs/plugin.legend.tests.js
test/specs/plugin.title.tests.js
test/specs/plugin.tooltip.tests.js
test/specs/scale.category.tests.js
test/specs/scale.linear.tests.js
test/specs/scale.logarithmic.tests.js
test/specs/scale.radialLinear.tests.js
test/specs/scale.time.tests.js
types/animation.d.ts
types/index.esm.d.ts

index 2b00449ca2c7c7a7db5284f24d628c279f4f4907..9c250497fa033bcb9fc00d7b66b3a0368fb44d8d 100644 (file)
       }
     },
     "eslint-config-chartjs": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/eslint-config-chartjs/-/eslint-config-chartjs-0.2.0.tgz",
-      "integrity": "sha512-9NbZlmn5clHbzFc+EK7zp7KhgU2vhcbJNb4OrSrm9nMOMTs7yVdzP00jqqfs7dhDkhT4CfVxQlV1DMfjhGBLIA==",
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-chartjs/-/eslint-config-chartjs-0.3.0.tgz",
+      "integrity": "sha512-L3AC5VSG8EBwwKkpOrxvBMjYzGF/XrGM+EjXgYO1KFUn3cMUFMKd562lSHdCSr4+ocw80vi+0fZhiFesUpqV3g==",
       "dev": true
     },
     "eslint-plugin-es": {
index d186333fa8b2d57a30b52d9eb1164f7a7e0db836..b3a560cadbf55589df855efc20f94090a23ec269 100644 (file)
@@ -58,7 +58,7 @@
     "coveralls": "^3.1.0",
     "cross-env": "^7.0.3",
     "eslint": "^7.16.0",
-    "eslint-config-chartjs": "^0.2.0",
+    "eslint-config-chartjs": "^0.3.0",
     "eslint-plugin-es": "^4.1.0",
     "eslint-plugin-html": "^6.1.1",
     "glob": "^7.1.6",
index bdf8eab325c1b54bcc848b09c1043368cff2a2ae..618932b79af967d633eb4c14bc11b65645f10324 100644 (file)
@@ -7,9 +7,5 @@ globals:
   randomScalingFactor: true
 
 rules:
-  no-new: 0
-  no-var: 0
-  object-shorthand: 0
-  prefer-arrow-callback: 0
-  no-invalid-this: 0
-  no-unneeded-ternary: 0
+  indent: ["error", "tab", {flatTernaryExpressions: true}]
+  no-new: "off"
index 24bd67566591624f805ec619873c064a6e85a483..165421209d189ead751b328207358c8e3cc8c8b6 100644 (file)
@@ -1,20 +1,20 @@
 import DatasetController from '../core/core.datasetController';
 import {
-       clipArea, unclipArea, _arrayUnique, isArray, isNullOrUndef,
-       valueOrDefault, resolveObjectKey, sign
+  clipArea, unclipArea, _arrayUnique, isArray, isNullOrUndef,
+  valueOrDefault, resolveObjectKey, sign
 } from '../helpers';
 
 function getAllScaleValues(scale) {
-       if (!scale._cache.$bar) {
-               const metas = scale.getMatchingVisibleMetas('bar');
-               let values = [];
-
-               for (let i = 0, ilen = metas.length; i < ilen; i++) {
-                       values = values.concat(metas[i].controller.getAllParsedValues(scale));
-               }
-               scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b));
-       }
-       return scale._cache.$bar;
+  if (!scale._cache.$bar) {
+    const metas = scale.getMatchingVisibleMetas('bar');
+    let values = [];
+
+    for (let i = 0, ilen = metas.length; i < ilen; i++) {
+      values = values.concat(metas[i].controller.getAllParsedValues(scale));
+    }
+    scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b));
+  }
+  return scale._cache.$bar;
 }
 
 /**
@@ -22,25 +22,25 @@ function getAllScaleValues(scale) {
  * @private
  */
 function computeMinSampleSize(scale) {
-       const values = getAllScaleValues(scale);
-       let min = scale._length;
-       let i, ilen, curr, prev;
-       const updateMinAndPrev = () => {
-               min = Math.min(min, i && Math.abs(curr - prev) || min);
-               prev = curr;
-       };
-
-       for (i = 0, ilen = values.length; i < ilen; ++i) {
-               curr = scale.getPixelForValue(values[i]);
-               updateMinAndPrev();
-       }
-
-       for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {
-               curr = scale.getPixelForTick(i);
-               updateMinAndPrev();
-       }
-
-       return min;
+  const values = getAllScaleValues(scale);
+  let min = scale._length;
+  let i, ilen, curr, prev;
+  const updateMinAndPrev = () => {
+    min = Math.min(min, i && Math.abs(curr - prev) || min);
+    prev = curr;
+  };
+
+  for (i = 0, ilen = values.length; i < ilen; ++i) {
+    curr = scale.getPixelForValue(values[i]);
+    updateMinAndPrev();
+  }
+
+  for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {
+    curr = scale.getPixelForTick(i);
+    updateMinAndPrev();
+  }
+
+  return min;
 }
 
 /**
@@ -50,25 +50,25 @@ function computeMinSampleSize(scale) {
  * @private
  */
 function computeFitCategoryTraits(index, ruler, options, stackCount) {
-       const thickness = options.barThickness;
-       let size, ratio;
-
-       if (isNullOrUndef(thickness)) {
-               size = ruler.min * options.categoryPercentage;
-               ratio = options.barPercentage;
-       } else {
-               // When bar thickness is enforced, category and bar percentages are ignored.
-               // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
-               // and deprecate barPercentage since this value is ignored when thickness is absolute.
-               size = thickness * stackCount;
-               ratio = 1;
-       }
-
-       return {
-               chunk: size / stackCount,
-               ratio,
-               start: ruler.pixels[index] - (size / 2)
-       };
+  const thickness = options.barThickness;
+  let size, ratio;
+
+  if (isNullOrUndef(thickness)) {
+    size = ruler.min * options.categoryPercentage;
+    ratio = options.barPercentage;
+  } else {
+    // When bar thickness is enforced, category and bar percentages are ignored.
+    // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
+    // and deprecate barPercentage since this value is ignored when thickness is absolute.
+    size = thickness * stackCount;
+    ratio = 1;
+  }
+
+  return {
+    chunk: size / stackCount,
+    ratio,
+    start: ruler.pixels[index] - (size / 2)
+  };
 }
 
 /**
@@ -78,427 +78,427 @@ function computeFitCategoryTraits(index, ruler, options, stackCount) {
  * @private
  */
 function computeFlexCategoryTraits(index, ruler, options, stackCount) {
-       const pixels = ruler.pixels;
-       const curr = pixels[index];
-       let prev = index > 0 ? pixels[index - 1] : null;
-       let next = index < pixels.length - 1 ? pixels[index + 1] : null;
-       const percent = options.categoryPercentage;
-
-       if (prev === null) {
-               // first data: its size is double based on the next point or,
-               // if it's also the last data, we use the scale size.
-               prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
-       }
-
-       if (next === null) {
-               // last data: its size is also double based on the previous point.
-               next = curr + curr - prev;
-       }
-
-       const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
-       const size = Math.abs(next - prev) / 2 * percent;
-
-       return {
-               chunk: size / stackCount,
-               ratio: options.barPercentage,
-               start
-       };
+  const pixels = ruler.pixels;
+  const curr = pixels[index];
+  let prev = index > 0 ? pixels[index - 1] : null;
+  let next = index < pixels.length - 1 ? pixels[index + 1] : null;
+  const percent = options.categoryPercentage;
+
+  if (prev === null) {
+    // first data: its size is double based on the next point or,
+    // if it's also the last data, we use the scale size.
+    prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
+  }
+
+  if (next === null) {
+    // last data: its size is also double based on the previous point.
+    next = curr + curr - prev;
+  }
+
+  const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
+  const size = Math.abs(next - prev) / 2 * percent;
+
+  return {
+    chunk: size / stackCount,
+    ratio: options.barPercentage,
+    start
+  };
 }
 
 function parseFloatBar(entry, item, vScale, i) {
-       const startValue = vScale.parse(entry[0], i);
-       const endValue = vScale.parse(entry[1], i);
-       const min = Math.min(startValue, endValue);
-       const max = Math.max(startValue, endValue);
-       let barStart = min;
-       let barEnd = max;
-
-       if (Math.abs(min) > Math.abs(max)) {
-               barStart = max;
-               barEnd = min;
-       }
-
-       // Store `barEnd` (furthest away from origin) as parsed value,
-       // to make stacking straight forward
-       item[vScale.axis] = barEnd;
-
-       item._custom = {
-               barStart,
-               barEnd,
-               start: startValue,
-               end: endValue,
-               min,
-               max
-       };
+  const startValue = vScale.parse(entry[0], i);
+  const endValue = vScale.parse(entry[1], i);
+  const min = Math.min(startValue, endValue);
+  const max = Math.max(startValue, endValue);
+  let barStart = min;
+  let barEnd = max;
+
+  if (Math.abs(min) > Math.abs(max)) {
+    barStart = max;
+    barEnd = min;
+  }
+
+  // Store `barEnd` (furthest away from origin) as parsed value,
+  // to make stacking straight forward
+  item[vScale.axis] = barEnd;
+
+  item._custom = {
+    barStart,
+    barEnd,
+    start: startValue,
+    end: endValue,
+    min,
+    max
+  };
 }
 
 function parseValue(entry, item, vScale, i) {
-       if (isArray(entry)) {
-               parseFloatBar(entry, item, vScale, i);
-       } else {
-               item[vScale.axis] = vScale.parse(entry, i);
-       }
-       return item;
+  if (isArray(entry)) {
+    parseFloatBar(entry, item, vScale, i);
+  } else {
+    item[vScale.axis] = vScale.parse(entry, i);
+  }
+  return item;
 }
 
 function parseArrayOrPrimitive(meta, data, start, count) {
-       const iScale = meta.iScale;
-       const vScale = meta.vScale;
-       const labels = iScale.getLabels();
-       const singleScale = iScale === vScale;
-       const parsed = [];
-       let i, ilen, item, entry;
-
-       for (i = start, ilen = start + count; i < ilen; ++i) {
-               entry = data[i];
-               item = {};
-               item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
-               parsed.push(parseValue(entry, item, vScale, i));
-       }
-       return parsed;
+  const iScale = meta.iScale;
+  const vScale = meta.vScale;
+  const labels = iScale.getLabels();
+  const singleScale = iScale === vScale;
+  const parsed = [];
+  let i, ilen, item, entry;
+
+  for (i = start, ilen = start + count; i < ilen; ++i) {
+    entry = data[i];
+    item = {};
+    item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
+    parsed.push(parseValue(entry, item, vScale, i));
+  }
+  return parsed;
 }
 
 function isFloatBar(custom) {
-       return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
+  return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
 }
 
 export default class BarController extends DatasetController {
 
-       /**
+  /**
         * Overriding primitive data parsing since we support mixed primitive/array
         * data for float bars
         * @protected
         */
-       parsePrimitiveData(meta, data, start, count) {
-               return parseArrayOrPrimitive(meta, data, start, count);
-       }
+  parsePrimitiveData(meta, data, start, count) {
+    return parseArrayOrPrimitive(meta, data, start, count);
+  }
 
-       /**
+  /**
         * Overriding array data parsing since we support mixed primitive/array
         * data for float bars
         * @protected
         */
-       parseArrayData(meta, data, start, count) {
-               return parseArrayOrPrimitive(meta, data, start, count);
-       }
+  parseArrayData(meta, data, start, count) {
+    return parseArrayOrPrimitive(meta, data, start, count);
+  }
 
-       /**
+  /**
         * Overriding object data parsing since we support mixed primitive/array
         * value-scale data for float bars
         * @protected
         */
-       parseObjectData(meta, data, start, count) {
-               const {iScale, vScale} = meta;
-               const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
-               const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
-               const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
-               const parsed = [];
-               let i, ilen, item, obj;
-               for (i = start, ilen = start + count; i < ilen; ++i) {
-                       obj = data[i];
-                       item = {};
-                       item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i);
-                       parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i));
-               }
-               return parsed;
-       }
-
-       /**
+  parseObjectData(meta, data, start, count) {
+    const {iScale, vScale} = meta;
+    const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
+    const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
+    const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
+    const parsed = [];
+    let i, ilen, item, obj;
+    for (i = start, ilen = start + count; i < ilen; ++i) {
+      obj = data[i];
+      item = {};
+      item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i);
+      parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i));
+    }
+    return parsed;
+  }
+
+  /**
         * @protected
         */
-       updateRangeFromParsed(range, scale, parsed, stack) {
-               super.updateRangeFromParsed(range, scale, parsed, stack);
-               const custom = parsed._custom;
-               if (custom && scale === this._cachedMeta.vScale) {
-                       // float bar: only one end of the bar is considered by `super`
-                       range.min = Math.min(range.min, custom.min);
-                       range.max = Math.max(range.max, custom.max);
-               }
-       }
-
-       /**
+  updateRangeFromParsed(range, scale, parsed, stack) {
+    super.updateRangeFromParsed(range, scale, parsed, stack);
+    const custom = parsed._custom;
+    if (custom && scale === this._cachedMeta.vScale) {
+      // float bar: only one end of the bar is considered by `super`
+      range.min = Math.min(range.min, custom.min);
+      range.max = Math.max(range.max, custom.max);
+    }
+  }
+
+  /**
         * @protected
         */
-       getLabelAndValue(index) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const {iScale, vScale} = meta;
-               const parsed = me.getParsed(index);
-               const custom = parsed._custom;
-               const value = isFloatBar(custom)
-                       ? '[' + custom.start + ', ' + custom.end + ']'
-                       : '' + vScale.getLabelForValue(parsed[vScale.axis]);
-
-               return {
-                       label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
-                       value
-               };
-       }
-
-       initialize() {
-               const me = this;
-               me.enableOptionSharing = true;
-
-               super.initialize();
-
-               const meta = me._cachedMeta;
-               meta.stack = me.getDataset().stack;
-       }
-
-       update(mode) {
-               const me = this;
-               const meta = me._cachedMeta;
-
-               me.updateElements(meta.data, 0, meta.data.length, mode);
-       }
-
-       updateElements(bars, start, count, mode) {
-               const me = this;
-               const reset = mode === 'reset';
-               const vscale = me._cachedMeta.vScale;
-               const base = vscale.getBasePixel();
-               const horizontal = vscale.isHorizontal();
-               const ruler = me._getRuler();
-               const firstOpts = me.resolveDataElementOptions(start, mode);
-               const sharedOptions = me.getSharedOptions(firstOpts);
-               const includeOptions = me.includeOptions(mode, sharedOptions);
-
-               me.updateSharedOptions(sharedOptions, mode, firstOpts);
-
-               for (let i = start; i < start + count; i++) {
-                       const options = sharedOptions || me.resolveDataElementOptions(i, mode);
-                       const vpixels = me._calculateBarValuePixels(i, options);
-                       const ipixels = me._calculateBarIndexPixels(i, ruler, options);
-
-                       const properties = {
-                               horizontal,
-                               base: reset ? base : vpixels.base,
-                               x: horizontal ? reset ? base : vpixels.head : ipixels.center,
-                               y: horizontal ? ipixels.center : reset ? base : vpixels.head,
-                               height: horizontal ? ipixels.size : undefined,
-                               width: horizontal ? undefined : ipixels.size
-                       };
-
-                       if (includeOptions) {
-                               properties.options = options;
-                       }
-                       me.updateElement(bars[i], i, properties, mode);
-               }
-       }
-
-       /**
+  getLabelAndValue(index) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const {iScale, vScale} = meta;
+    const parsed = me.getParsed(index);
+    const custom = parsed._custom;
+    const value = isFloatBar(custom)
+      ? '[' + custom.start + ', ' + custom.end + ']'
+      : '' + vScale.getLabelForValue(parsed[vScale.axis]);
+
+    return {
+      label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
+      value
+    };
+  }
+
+  initialize() {
+    const me = this;
+    me.enableOptionSharing = true;
+
+    super.initialize();
+
+    const meta = me._cachedMeta;
+    meta.stack = me.getDataset().stack;
+  }
+
+  update(mode) {
+    const me = this;
+    const meta = me._cachedMeta;
+
+    me.updateElements(meta.data, 0, meta.data.length, mode);
+  }
+
+  updateElements(bars, start, count, mode) {
+    const me = this;
+    const reset = mode === 'reset';
+    const vscale = me._cachedMeta.vScale;
+    const base = vscale.getBasePixel();
+    const horizontal = vscale.isHorizontal();
+    const ruler = me._getRuler();
+    const firstOpts = me.resolveDataElementOptions(start, mode);
+    const sharedOptions = me.getSharedOptions(firstOpts);
+    const includeOptions = me.includeOptions(mode, sharedOptions);
+
+    me.updateSharedOptions(sharedOptions, mode, firstOpts);
+
+    for (let i = start; i < start + count; i++) {
+      const options = sharedOptions || me.resolveDataElementOptions(i, mode);
+      const vpixels = me._calculateBarValuePixels(i, options);
+      const ipixels = me._calculateBarIndexPixels(i, ruler, options);
+
+      const properties = {
+        horizontal,
+        base: reset ? base : vpixels.base,
+        x: horizontal ? reset ? base : vpixels.head : ipixels.center,
+        y: horizontal ? ipixels.center : reset ? base : vpixels.head,
+        height: horizontal ? ipixels.size : undefined,
+        width: horizontal ? undefined : ipixels.size
+      };
+
+      if (includeOptions) {
+        properties.options = options;
+      }
+      me.updateElement(bars[i], i, properties, mode);
+    }
+  }
+
+  /**
         * Returns the stacks based on groups and bar visibility.
         * @param {number} [last] - The dataset index
         * @param {number} [dataIndex] - The data index of the ruler
         * @returns {string[]} The list of stack IDs
         * @private
         */
-       _getStacks(last, dataIndex) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const iScale = meta.iScale;
-               const metasets = iScale.getMatchingVisibleMetas(me._type);
-               const stacked = iScale.options.stacked;
-               const ilen = metasets.length;
-               const stacks = [];
-               let i, item;
-
-               for (i = 0; i < ilen; ++i) {
-                       item = metasets[i];
-
-                       if (typeof dataIndex !== 'undefined') {
-                               const val = item.controller.getParsed(dataIndex)[
-                                       item.controller._cachedMeta.vScale.axis
-                               ];
-
-                               if (isNullOrUndef(val) || isNaN(val)) {
-                                       continue;
-                               }
-                       }
-
-                       // stacked   | meta.stack
-                       //           | found | not found | undefined
-                       // false     |   x   |     x     |     x
-                       // true      |       |     x     |
-                       // undefined |       |     x     |     x
-                       if (stacked === false || stacks.indexOf(item.stack) === -1 ||
+  _getStacks(last, dataIndex) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const iScale = meta.iScale;
+    const metasets = iScale.getMatchingVisibleMetas(me._type);
+    const stacked = iScale.options.stacked;
+    const ilen = metasets.length;
+    const stacks = [];
+    let i, item;
+
+    for (i = 0; i < ilen; ++i) {
+      item = metasets[i];
+
+      if (typeof dataIndex !== 'undefined') {
+        const val = item.controller.getParsed(dataIndex)[
+          item.controller._cachedMeta.vScale.axis
+        ];
+
+        if (isNullOrUndef(val) || isNaN(val)) {
+          continue;
+        }
+      }
+
+      // stacked   | meta.stack
+      //           | found | not found | undefined
+      // false     |   x   |     x     |     x
+      // true      |       |     x     |
+      // undefined |       |     x     |     x
+      if (stacked === false || stacks.indexOf(item.stack) === -1 ||
                                (stacked === undefined && item.stack === undefined)) {
-                               stacks.push(item.stack);
-                       }
-                       if (item.index === last) {
-                               break;
-                       }
-               }
-
-               // No stacks? that means there is no visible data. Let's still initialize an `undefined`
-               // stack where possible invisible bars will be located.
-               // https://github.com/chartjs/Chart.js/issues/6368
-               if (!stacks.length) {
-                       stacks.push(undefined);
-               }
-
-               return stacks;
-       }
-
-       /**
+        stacks.push(item.stack);
+      }
+      if (item.index === last) {
+        break;
+      }
+    }
+
+    // No stacks? that means there is no visible data. Let's still initialize an `undefined`
+    // stack where possible invisible bars will be located.
+    // https://github.com/chartjs/Chart.js/issues/6368
+    if (!stacks.length) {
+      stacks.push(undefined);
+    }
+
+    return stacks;
+  }
+
+  /**
         * Returns the effective number of stacks based on groups and bar visibility.
         * @private
         */
-       _getStackCount(index) {
-               return this._getStacks(undefined, index).length;
-       }
+  _getStackCount(index) {
+    return this._getStacks(undefined, index).length;
+  }
 
-       /**
+  /**
         * Returns the stack index for the given dataset based on groups and bar visibility.
         * @param {number} [datasetIndex] - The dataset index
         * @param {string} [name] - The stack name to find
         * @returns {number} The stack index
         * @private
         */
-       _getStackIndex(datasetIndex, name) {
-               const stacks = this._getStacks(datasetIndex);
-               const index = (name !== undefined)
-                       ? stacks.indexOf(name)
-                       : -1; // indexOf returns -1 if element is not present
-
-               return (index === -1)
-                       ? stacks.length - 1
-                       : index;
-       }
-
-       /**
+  _getStackIndex(datasetIndex, name) {
+    const stacks = this._getStacks(datasetIndex);
+    const index = (name !== undefined)
+      ? stacks.indexOf(name)
+      : -1; // indexOf returns -1 if element is not present
+
+    return (index === -1)
+      ? stacks.length - 1
+      : index;
+  }
+
+  /**
         * @private
         */
-       _getRuler() {
-               const me = this;
-               const meta = me._cachedMeta;
-               const iScale = meta.iScale;
-               const pixels = [];
-               let i, ilen;
-
-               for (i = 0, ilen = meta.data.length; i < ilen; ++i) {
-                       pixels.push(iScale.getPixelForValue(me.getParsed(i)[iScale.axis], i));
-               }
-
-               // Note: a potential optimization would be to skip computing this
-               // only if the barThickness option is defined
-               // Since a scriptable option may return null or undefined that
-               // means the option would have to be of type number
-               const min = computeMinSampleSize(iScale);
-
-               return {
-                       min,
-                       pixels,
-                       start: iScale._startPixel,
-                       end: iScale._endPixel,
-                       stackCount: me._getStackCount(),
-                       scale: iScale
-               };
-       }
-
-       /**
+  _getRuler() {
+    const me = this;
+    const meta = me._cachedMeta;
+    const iScale = meta.iScale;
+    const pixels = [];
+    let i, ilen;
+
+    for (i = 0, ilen = meta.data.length; i < ilen; ++i) {
+      pixels.push(iScale.getPixelForValue(me.getParsed(i)[iScale.axis], i));
+    }
+
+    // Note: a potential optimization would be to skip computing this
+    // only if the barThickness option is defined
+    // Since a scriptable option may return null or undefined that
+    // means the option would have to be of type number
+    const min = computeMinSampleSize(iScale);
+
+    return {
+      min,
+      pixels,
+      start: iScale._startPixel,
+      end: iScale._endPixel,
+      stackCount: me._getStackCount(),
+      scale: iScale
+    };
+  }
+
+  /**
         * Note: pixel values are not clamped to the scale area.
         * @private
         */
-       _calculateBarValuePixels(index, options) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const vScale = meta.vScale;
-               const {base: baseValue, minBarLength} = options;
-               const parsed = me.getParsed(index);
-               const custom = parsed._custom;
-               const floating = isFloatBar(custom);
-               let value = parsed[vScale.axis];
-               let start = 0;
-               let length = meta._stacked ? me.applyStack(vScale, parsed) : value;
-               let head, size;
-
-               if (length !== value) {
-                       start = length - value;
-                       length = value;
-               }
-
-               if (floating) {
-                       value = custom.barStart;
-                       length = custom.barEnd - custom.barStart;
-                       // bars crossing origin are not stacked
-                       if (value !== 0 && sign(value) !== sign(custom.barEnd)) {
-                               start = 0;
-                       }
-                       start += value;
-               }
-
-               const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;
-               let base = vScale.getPixelForValue(startValue);
-
-               if (this.chart.getDataVisibility(index)) {
-                       head = vScale.getPixelForValue(start + length);
-               } else {
-                       // When not visible, no height
-                       head = base;
-               }
-
-               size = head - base;
-
-               if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
-                       size = size < 0 ? -minBarLength : minBarLength;
-                       if (value === 0) {
-                               base -= size / 2;
-                       }
-                       head = base + size;
-               }
-
-               return {
-                       size,
-                       base,
-                       head,
-                       center: head + size / 2
-               };
-       }
-
-       /**
+  _calculateBarValuePixels(index, options) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const vScale = meta.vScale;
+    const {base: baseValue, minBarLength} = options;
+    const parsed = me.getParsed(index);
+    const custom = parsed._custom;
+    const floating = isFloatBar(custom);
+    let value = parsed[vScale.axis];
+    let start = 0;
+    let length = meta._stacked ? me.applyStack(vScale, parsed) : value;
+    let head, size;
+
+    if (length !== value) {
+      start = length - value;
+      length = value;
+    }
+
+    if (floating) {
+      value = custom.barStart;
+      length = custom.barEnd - custom.barStart;
+      // bars crossing origin are not stacked
+      if (value !== 0 && sign(value) !== sign(custom.barEnd)) {
+        start = 0;
+      }
+      start += value;
+    }
+
+    const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;
+    let base = vScale.getPixelForValue(startValue);
+
+    if (this.chart.getDataVisibility(index)) {
+      head = vScale.getPixelForValue(start + length);
+    } else {
+      // When not visible, no height
+      head = base;
+    }
+
+    size = head - base;
+
+    if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
+      size = size < 0 ? -minBarLength : minBarLength;
+      if (value === 0) {
+        base -= size / 2;
+      }
+      head = base + size;
+    }
+
+    return {
+      size,
+      base,
+      head,
+      center: head + size / 2
+    };
+  }
+
+  /**
         * @private
         */
-       _calculateBarIndexPixels(index, ruler, options) {
-               const me = this;
-               const stackCount = me.chart.options.skipNull ? me._getStackCount(index) : ruler.stackCount;
-               const range = options.barThickness === 'flex'
-                       ? computeFlexCategoryTraits(index, ruler, options, stackCount)
-                       : computeFitCategoryTraits(index, ruler, options, stackCount);
-
-               const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack);
-               const center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
-               const size = Math.min(
-                       valueOrDefault(options.maxBarThickness, Infinity),
-                       range.chunk * range.ratio);
-
-               return {
-                       base: center - size / 2,
-                       head: center + size / 2,
-                       center,
-                       size
-               };
-       }
-
-       draw() {
-               const me = this;
-               const chart = me.chart;
-               const meta = me._cachedMeta;
-               const vScale = meta.vScale;
-               const rects = meta.data;
-               const ilen = rects.length;
-               let i = 0;
-
-               clipArea(chart.ctx, chart.chartArea);
-
-               for (; i < ilen; ++i) {
-                       if (!isNaN(me.getParsed(i)[vScale.axis])) {
-                               rects[i].draw(me._ctx);
-                       }
-               }
-
-               unclipArea(chart.ctx);
-       }
+  _calculateBarIndexPixels(index, ruler, options) {
+    const me = this;
+    const stackCount = me.chart.options.skipNull ? me._getStackCount(index) : ruler.stackCount;
+    const range = options.barThickness === 'flex'
+      ? computeFlexCategoryTraits(index, ruler, options, stackCount)
+      : computeFitCategoryTraits(index, ruler, options, stackCount);
+
+    const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack);
+    const center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
+    const size = Math.min(
+      valueOrDefault(options.maxBarThickness, Infinity),
+      range.chunk * range.ratio);
+
+    return {
+      base: center - size / 2,
+      head: center + size / 2,
+      center,
+      size
+    };
+  }
+
+  draw() {
+    const me = this;
+    const chart = me.chart;
+    const meta = me._cachedMeta;
+    const vScale = meta.vScale;
+    const rects = meta.data;
+    const ilen = rects.length;
+    let i = 0;
+
+    clipArea(chart.ctx, chart.chartArea);
+
+    for (; i < ilen; ++i) {
+      if (!isNaN(me.getParsed(i)[vScale.axis])) {
+        rects[i].draw(me._ctx);
+      }
+    }
+
+    unclipArea(chart.ctx);
+  }
 
 }
 
@@ -508,50 +508,50 @@ BarController.id = 'bar';
  * @type {any}
  */
 BarController.defaults = {
-       datasetElementType: false,
-       dataElementType: 'bar',
-       dataElementOptions: [
-               'backgroundColor',
-               'borderColor',
-               'borderSkipped',
-               'borderWidth',
-               'borderRadius',
-               'barPercentage',
-               'barThickness',
-               'base',
-               'categoryPercentage',
-               'maxBarThickness',
-               'minBarLength',
-               'pointStyle'
-       ],
-       interaction: {
-               mode: 'index'
-       },
-
-       hover: {},
-
-       datasets: {
-               categoryPercentage: 0.8,
-               barPercentage: 0.9,
-               animation: {
-                       numbers: {
-                               type: 'number',
-                               properties: ['x', 'y', 'base', 'width', 'height']
-                       }
-               }
-       },
-
-       scales: {
-               _index_: {
-                       type: 'category',
-                       offset: true,
-                       gridLines: {
-                               offsetGridLines: true
-                       }
-               },
-               _value_: {
-                       type: 'linear',
-                       beginAtZero: true,
-               }
-       }
+  datasetElementType: false,
+  dataElementType: 'bar',
+  dataElementOptions: [
+    'backgroundColor',
+    'borderColor',
+    'borderSkipped',
+    'borderWidth',
+    'borderRadius',
+    'barPercentage',
+    'barThickness',
+    'base',
+    'categoryPercentage',
+    'maxBarThickness',
+    'minBarLength',
+    'pointStyle'
+  ],
+  interaction: {
+    mode: 'index'
+  },
+
+  hover: {},
+
+  datasets: {
+    categoryPercentage: 0.8,
+    barPercentage: 0.9,
+    animation: {
+      numbers: {
+        type: 'number',
+        properties: ['x', 'y', 'base', 'width', 'height']
+      }
+    }
+  },
+
+  scales: {
+    _index_: {
+      type: 'category',
+      offset: true,
+      gridLines: {
+        offsetGridLines: true
+      }
+    },
+    _value_: {
+      type: 'linear',
+      beginAtZero: true,
+    }
+  }
 };
index d4b0e186c166797658e3a04101d3cd8f0f386011..7c8c7dcd7af04c338217b2e65ea2426f9ab52776 100644 (file)
@@ -3,136 +3,136 @@ import {resolve} from '../helpers/helpers.options';
 import {resolveObjectKey} from '../helpers/helpers.core';
 
 export default class BubbleController extends DatasetController {
-       initialize() {
-               this.enableOptionSharing = true;
-               super.initialize();
-       }
+  initialize() {
+    this.enableOptionSharing = true;
+    super.initialize();
+  }
 
-       /**
+  /**
         * Parse array of objects
         * @protected
         */
-       parseObjectData(meta, data, start, count) {
-               const {xScale, yScale} = meta;
-               const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
-               const parsed = [];
-               let i, ilen, item;
-               for (i = start, ilen = start + count; i < ilen; ++i) {
-                       item = data[i];
-                       parsed.push({
-                               x: xScale.parse(resolveObjectKey(item, xAxisKey), i),
-                               y: yScale.parse(resolveObjectKey(item, yAxisKey), i),
-                               _custom: item && item.r && +item.r
-                       });
-               }
-               return parsed;
-       }
-
-       /**
+  parseObjectData(meta, data, start, count) {
+    const {xScale, yScale} = meta;
+    const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
+    const parsed = [];
+    let i, ilen, item;
+    for (i = start, ilen = start + count; i < ilen; ++i) {
+      item = data[i];
+      parsed.push({
+        x: xScale.parse(resolveObjectKey(item, xAxisKey), i),
+        y: yScale.parse(resolveObjectKey(item, yAxisKey), i),
+        _custom: item && item.r && +item.r
+      });
+    }
+    return parsed;
+  }
+
+  /**
         * @protected
         */
-       getMaxOverflow() {
-               const me = this;
-               const meta = me._cachedMeta;
-               const data = meta.data;
-               let max = 0;
-               for (let i = data.length - 1; i >= 0; --i) {
-                       max = Math.max(max, data[i].size());
-               }
-               return max > 0 && max;
-       }
-
-       /**
+  getMaxOverflow() {
+    const me = this;
+    const meta = me._cachedMeta;
+    const data = meta.data;
+    let max = 0;
+    for (let i = data.length - 1; i >= 0; --i) {
+      max = Math.max(max, data[i].size());
+    }
+    return max > 0 && max;
+  }
+
+  /**
         * @protected
         */
-       getLabelAndValue(index) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const {xScale, yScale} = meta;
-               const parsed = me.getParsed(index);
-               const x = xScale.getLabelForValue(parsed.x);
-               const y = yScale.getLabelForValue(parsed.y);
-               const r = parsed._custom;
-
-               return {
-                       label: meta.label,
-                       value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
-               };
-       }
-
-       update(mode) {
-               const me = this;
-               const points = me._cachedMeta.data;
-
-               // Update Points
-               me.updateElements(points, 0, points.length, mode);
-       }
-
-       updateElements(points, start, count, mode) {
-               const me = this;
-               const reset = mode === 'reset';
-               const {xScale, yScale} = me._cachedMeta;
-               const firstOpts = me.resolveDataElementOptions(start, mode);
-               const sharedOptions = me.getSharedOptions(firstOpts);
-               const includeOptions = me.includeOptions(mode, sharedOptions);
-
-               for (let i = start; i < start + count; i++) {
-                       const point = points[i];
-                       const parsed = !reset && me.getParsed(i);
-                       const x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(parsed.x);
-                       const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(parsed.y);
-                       const properties = {
-                               x,
-                               y,
-                               skip: isNaN(x) || isNaN(y)
-                       };
-
-                       if (includeOptions) {
-                               properties.options = me.resolveDataElementOptions(i, mode);
-
-                               if (reset) {
-                                       properties.options.radius = 0;
-                               }
-                       }
-
-                       me.updateElement(point, i, properties, mode);
-               }
-
-               me.updateSharedOptions(sharedOptions, mode, firstOpts);
-       }
-
-       /**
+  getLabelAndValue(index) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const {xScale, yScale} = meta;
+    const parsed = me.getParsed(index);
+    const x = xScale.getLabelForValue(parsed.x);
+    const y = yScale.getLabelForValue(parsed.y);
+    const r = parsed._custom;
+
+    return {
+      label: meta.label,
+      value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
+    };
+  }
+
+  update(mode) {
+    const me = this;
+    const points = me._cachedMeta.data;
+
+    // Update Points
+    me.updateElements(points, 0, points.length, mode);
+  }
+
+  updateElements(points, start, count, mode) {
+    const me = this;
+    const reset = mode === 'reset';
+    const {xScale, yScale} = me._cachedMeta;
+    const firstOpts = me.resolveDataElementOptions(start, mode);
+    const sharedOptions = me.getSharedOptions(firstOpts);
+    const includeOptions = me.includeOptions(mode, sharedOptions);
+
+    for (let i = start; i < start + count; i++) {
+      const point = points[i];
+      const parsed = !reset && me.getParsed(i);
+      const x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(parsed.x);
+      const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(parsed.y);
+      const properties = {
+        x,
+        y,
+        skip: isNaN(x) || isNaN(y)
+      };
+
+      if (includeOptions) {
+        properties.options = me.resolveDataElementOptions(i, mode);
+
+        if (reset) {
+          properties.options.radius = 0;
+        }
+      }
+
+      me.updateElement(point, i, properties, mode);
+    }
+
+    me.updateSharedOptions(sharedOptions, mode, firstOpts);
+  }
+
+  /**
         * @param {number} index
         * @param {string} [mode]
         * @protected
         */
-       resolveDataElementOptions(index, mode) {
-               const me = this;
-               const chart = me.chart;
-               const parsed = me.getParsed(index);
-               let values = super.resolveDataElementOptions(index, mode);
-
-               // Scriptable options
-               const context = me.getContext(index, mode === 'active');
-
-               // In case values were cached (and thus frozen), we need to clone the values
-               if (values.$shared) {
-                       values = Object.assign({}, values, {$shared: false});
-               }
-
-
-               // Custom radius resolution
-               if (mode !== 'active') {
-                       values.radius = 0;
-               }
-               values.radius += resolve([
-                       parsed && parsed._custom,
-                       me._config.radius,
-                       chart.options.elements.point.radius
-               ], context, index);
-
-               return values;
-       }
+  resolveDataElementOptions(index, mode) {
+    const me = this;
+    const chart = me.chart;
+    const parsed = me.getParsed(index);
+    let values = super.resolveDataElementOptions(index, mode);
+
+    // Scriptable options
+    const context = me.getContext(index, mode === 'active');
+
+    // In case values were cached (and thus frozen), we need to clone the values
+    if (values.$shared) {
+      values = Object.assign({}, values, {$shared: false});
+    }
+
+
+    // Custom radius resolution
+    if (mode !== 'active') {
+      values.radius = 0;
+    }
+    values.radius += resolve([
+      parsed && parsed._custom,
+      me._config.radius,
+      chart.options.elements.point.radius
+    ], context, index);
+
+    return values;
+  }
 }
 
 BubbleController.id = 'bubble';
@@ -141,38 +141,38 @@ BubbleController.id = 'bubble';
  * @type {any}
  */
 BubbleController.defaults = {
-       datasetElementType: false,
-       dataElementType: 'point',
-       dataElementOptions: [
-               'backgroundColor',
-               'borderColor',
-               'borderWidth',
-               'hitRadius',
-               'radius',
-               'pointStyle',
-               'rotation'
-       ],
-       animation: {
-               numbers: {
-                       properties: ['x', 'y', 'borderWidth', 'radius']
-               }
-       },
-       scales: {
-               x: {
-                       type: 'linear'
-               },
-               y: {
-                       type: 'linear'
-               }
-       },
-       plugins: {
-               tooltip: {
-                       callbacks: {
-                               title() {
-                                       // Title doesn't make sense for scatter since we format the data as a point
-                                       return '';
-                               }
-                       }
-               }
-       }
+  datasetElementType: false,
+  dataElementType: 'point',
+  dataElementOptions: [
+    'backgroundColor',
+    'borderColor',
+    'borderWidth',
+    'hitRadius',
+    'radius',
+    'pointStyle',
+    'rotation'
+  ],
+  animation: {
+    numbers: {
+      properties: ['x', 'y', 'borderWidth', 'radius']
+    }
+  },
+  scales: {
+    x: {
+      type: 'linear'
+    },
+    y: {
+      type: 'linear'
+    }
+  },
+  plugins: {
+    tooltip: {
+      callbacks: {
+        title() {
+          // Title doesn't make sense for scatter since we format the data as a point
+          return '';
+        }
+      }
+    }
+  }
 };
index 2374fcd0e455015c650b0a4a5528a95a55c0d57f..24e242fa30ef2beb2ebb1d8243fa31d846aeb329 100644 (file)
@@ -9,315 +9,315 @@ import {toRadians, PI, TAU, HALF_PI} from '../helpers/helpers.math';
 
 
 function getRatioAndOffset(rotation, circumference, cutout) {
-       let ratioX = 1;
-       let ratioY = 1;
-       let offsetX = 0;
-       let offsetY = 0;
-       // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
-       if (circumference < TAU) {
-               let startAngle = rotation % TAU;
-               startAngle += startAngle >= PI ? -TAU : startAngle < -PI ? TAU : 0;
-               const endAngle = startAngle + circumference;
-               const startX = Math.cos(startAngle);
-               const startY = Math.sin(startAngle);
-               const endX = Math.cos(endAngle);
-               const endY = Math.sin(endAngle);
-               const contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= TAU;
-               const contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= TAU + HALF_PI;
-               const contains180 = startAngle === -PI || endAngle >= PI;
-               const contains270 = (startAngle <= -HALF_PI && endAngle >= -HALF_PI) || endAngle >= PI + HALF_PI;
-               const minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
-               const minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
-               const maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
-               const maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
-               ratioX = (maxX - minX) / 2;
-               ratioY = (maxY - minY) / 2;
-               offsetX = -(maxX + minX) / 2;
-               offsetY = -(maxY + minY) / 2;
-       }
-       return {ratioX, ratioY, offsetX, offsetY};
+  let ratioX = 1;
+  let ratioY = 1;
+  let offsetX = 0;
+  let offsetY = 0;
+  // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
+  if (circumference < TAU) {
+    let startAngle = rotation % TAU;
+    startAngle += startAngle >= PI ? -TAU : startAngle < -PI ? TAU : 0;
+    const endAngle = startAngle + circumference;
+    const startX = Math.cos(startAngle);
+    const startY = Math.sin(startAngle);
+    const endX = Math.cos(endAngle);
+    const endY = Math.sin(endAngle);
+    const contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= TAU;
+    const contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= TAU + HALF_PI;
+    const contains180 = startAngle === -PI || endAngle >= PI;
+    const contains270 = (startAngle <= -HALF_PI && endAngle >= -HALF_PI) || endAngle >= PI + HALF_PI;
+    const minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
+    const minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
+    const maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
+    const maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
+    ratioX = (maxX - minX) / 2;
+    ratioY = (maxY - minY) / 2;
+    offsetX = -(maxX + minX) / 2;
+    offsetY = -(maxY + minY) / 2;
+  }
+  return {ratioX, ratioY, offsetX, offsetY};
 }
 
 export default class DoughnutController extends DatasetController {
 
-       constructor(chart, datasetIndex) {
-               super(chart, datasetIndex);
+  constructor(chart, datasetIndex) {
+    super(chart, datasetIndex);
 
-               this.enableOptionSharing = true;
-               this.innerRadius = undefined;
-               this.outerRadius = undefined;
-               this.offsetX = undefined;
-               this.offsetY = undefined;
-       }
+    this.enableOptionSharing = true;
+    this.innerRadius = undefined;
+    this.outerRadius = undefined;
+    this.offsetX = undefined;
+    this.offsetY = undefined;
+  }
 
-       linkScales() {}
+  linkScales() {}
 
-       /**
+  /**
         * Override data parsing, since we are not using scales
         */
-       parse(start, count) {
-               const data = this.getDataset().data;
-               const meta = this._cachedMeta;
-               let i, ilen;
-               for (i = start, ilen = start + count; i < ilen; ++i) {
-                       meta._parsed[i] = +data[i];
-               }
-       }
-
-       // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
-       getRingIndex(datasetIndex) {
-               let ringIndex = 0;
-
-               for (let j = 0; j < datasetIndex; ++j) {
-                       if (this.chart.isDatasetVisible(j)) {
-                               ++ringIndex;
-                       }
-               }
-
-               return ringIndex;
-       }
-
-       /**
+  parse(start, count) {
+    const data = this.getDataset().data;
+    const meta = this._cachedMeta;
+    let i, ilen;
+    for (i = start, ilen = start + count; i < ilen; ++i) {
+      meta._parsed[i] = +data[i];
+    }
+  }
+
+  // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+  getRingIndex(datasetIndex) {
+    let ringIndex = 0;
+
+    for (let j = 0; j < datasetIndex; ++j) {
+      if (this.chart.isDatasetVisible(j)) {
+        ++ringIndex;
+      }
+    }
+
+    return ringIndex;
+  }
+
+  /**
         * @private
         */
-       _getRotation() {
-               return toRadians(valueOrDefault(this._config.rotation, this.chart.options.rotation) - 90);
-       }
+  _getRotation() {
+    return toRadians(valueOrDefault(this._config.rotation, this.chart.options.rotation) - 90);
+  }
 
-       /**
+  /**
         * @private
         */
-       _getCircumference() {
-               return toRadians(valueOrDefault(this._config.circumference, this.chart.options.circumference));
-       }
+  _getCircumference() {
+    return toRadians(valueOrDefault(this._config.circumference, this.chart.options.circumference));
+  }
 
-       /**
+  /**
         * Get the maximal rotation & circumference extents
         * across all visible datasets.
         */
-       _getRotationExtents() {
-               let min = TAU;
-               let max = -TAU;
-
-               const me = this;
-
-               for (let i = 0; i < me.chart.data.datasets.length; ++i) {
-                       if (me.chart.isDatasetVisible(i)) {
-                               const controller = me.chart.getDatasetMeta(i).controller;
-                               const rotation = controller._getRotation();
-                               const circumference = controller._getCircumference();
-
-                               min = Math.min(min, rotation);
-                               max = Math.max(max, rotation + circumference);
-                       }
-               }
-
-               return {
-                       rotation: min,
-                       circumference: max - min,
-               };
-       }
-
-       /**
+  _getRotationExtents() {
+    let min = TAU;
+    let max = -TAU;
+
+    const me = this;
+
+    for (let i = 0; i < me.chart.data.datasets.length; ++i) {
+      if (me.chart.isDatasetVisible(i)) {
+        const controller = me.chart.getDatasetMeta(i).controller;
+        const rotation = controller._getRotation();
+        const circumference = controller._getCircumference();
+
+        min = Math.min(min, rotation);
+        max = Math.max(max, rotation + circumference);
+      }
+    }
+
+    return {
+      rotation: min,
+      circumference: max - min,
+    };
+  }
+
+  /**
         * @param {string} mode
         */
-       update(mode) {
-               const me = this;
-               const chart = me.chart;
-               const {chartArea, options} = chart;
-               const meta = me._cachedMeta;
-               const arcs = meta.data;
-               const cutout = options.cutoutPercentage / 100 || 0;
-               const chartWeight = me._getRingWeight(me.index);
-
-               // Compute the maximal rotation & circumference limits.
-               // If we only consider our dataset, this can cause problems when two datasets
-               // are both less than a circle with different rotations (starting angles)
-               const {circumference, rotation} = me._getRotationExtents();
-               const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout);
-               const spacing = me.getMaxBorderWidth() + me.getMaxOffset(arcs);
-               const maxWidth = (chartArea.right - chartArea.left - spacing) / ratioX;
-               const maxHeight = (chartArea.bottom - chartArea.top - spacing) / ratioY;
-               const outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
-               const innerRadius = Math.max(outerRadius * cutout, 0);
-               const radiusLength = (outerRadius - innerRadius) / me._getVisibleDatasetWeightTotal();
-               me.offsetX = offsetX * outerRadius;
-               me.offsetY = offsetY * outerRadius;
-
-               meta.total = me.calculateTotal();
-
-               me.outerRadius = outerRadius - radiusLength * me._getRingWeightOffset(me.index);
-               me.innerRadius = Math.max(me.outerRadius - radiusLength * chartWeight, 0);
-
-               me.updateElements(arcs, 0, arcs.length, mode);
-       }
-
-       /**
+  update(mode) {
+    const me = this;
+    const chart = me.chart;
+    const {chartArea, options} = chart;
+    const meta = me._cachedMeta;
+    const arcs = meta.data;
+    const cutout = options.cutoutPercentage / 100 || 0;
+    const chartWeight = me._getRingWeight(me.index);
+
+    // Compute the maximal rotation & circumference limits.
+    // If we only consider our dataset, this can cause problems when two datasets
+    // are both less than a circle with different rotations (starting angles)
+    const {circumference, rotation} = me._getRotationExtents();
+    const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout);
+    const spacing = me.getMaxBorderWidth() + me.getMaxOffset(arcs);
+    const maxWidth = (chartArea.right - chartArea.left - spacing) / ratioX;
+    const maxHeight = (chartArea.bottom - chartArea.top - spacing) / ratioY;
+    const outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
+    const innerRadius = Math.max(outerRadius * cutout, 0);
+    const radiusLength = (outerRadius - innerRadius) / me._getVisibleDatasetWeightTotal();
+    me.offsetX = offsetX * outerRadius;
+    me.offsetY = offsetY * outerRadius;
+
+    meta.total = me.calculateTotal();
+
+    me.outerRadius = outerRadius - radiusLength * me._getRingWeightOffset(me.index);
+    me.innerRadius = Math.max(me.outerRadius - radiusLength * chartWeight, 0);
+
+    me.updateElements(arcs, 0, arcs.length, mode);
+  }
+
+  /**
         * @private
         */
-       _circumference(i, reset) {
-               const me = this;
-               const opts = me.chart.options;
-               const meta = me._cachedMeta;
-               const circumference = me._getCircumference();
-               return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * circumference / TAU) : 0;
-       }
-
-       updateElements(arcs, start, count, mode) {
-               const me = this;
-               const reset = mode === 'reset';
-               const chart = me.chart;
-               const chartArea = chart.chartArea;
-               const opts = chart.options;
-               const animationOpts = opts.animation;
-               const centerX = (chartArea.left + chartArea.right) / 2;
-               const centerY = (chartArea.top + chartArea.bottom) / 2;
-               const animateScale = reset && animationOpts.animateScale;
-               const innerRadius = animateScale ? 0 : me.innerRadius;
-               const outerRadius = animateScale ? 0 : me.outerRadius;
-               const firstOpts = me.resolveDataElementOptions(start, mode);
-               const sharedOptions = me.getSharedOptions(firstOpts);
-               const includeOptions = me.includeOptions(mode, sharedOptions);
-               let startAngle = me._getRotation();
-               let i;
-
-               for (i = 0; i < start; ++i) {
-                       startAngle += me._circumference(i, reset);
-               }
-
-               for (i = start; i < start + count; ++i) {
-                       const circumference = me._circumference(i, reset);
-                       const arc = arcs[i];
-                       const properties = {
-                               x: centerX + me.offsetX,
-                               y: centerY + me.offsetY,
-                               startAngle,
-                               endAngle: startAngle + circumference,
-                               circumference,
-                               outerRadius,
-                               innerRadius
-                       };
-                       if (includeOptions) {
-                               properties.options = sharedOptions || me.resolveDataElementOptions(i, mode);
-                       }
-                       startAngle += circumference;
-
-                       me.updateElement(arc, i, properties, mode);
-               }
-               me.updateSharedOptions(sharedOptions, mode, firstOpts);
-       }
-
-       calculateTotal() {
-               const meta = this._cachedMeta;
-               const metaData = meta.data;
-               let total = 0;
-               let i;
-
-               for (i = 0; i < metaData.length; i++) {
-                       const value = meta._parsed[i];
-                       if (!isNaN(value) && this.chart.getDataVisibility(i)) {
-                               total += Math.abs(value);
-                       }
-               }
-
-               return total;
-       }
-
-       calculateCircumference(value) {
-               const total = this._cachedMeta.total;
-               if (total > 0 && !isNaN(value)) {
-                       return TAU * (Math.abs(value) / total);
-               }
-               return 0;
-       }
-
-       getLabelAndValue(index) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const chart = me.chart;
-               const labels = chart.data.labels || [];
-               const value = formatNumber(meta._parsed[index], chart.options.locale);
-
-               return {
-                       label: labels[index] || '',
-                       value,
-               };
-       }
-
-       getMaxBorderWidth(arcs) {
-               const me = this;
-               let max = 0;
-               const chart = me.chart;
-               let i, ilen, meta, controller, options;
-
-               if (!arcs) {
-                       // Find the outmost visible dataset
-                       for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
-                               if (chart.isDatasetVisible(i)) {
-                                       meta = chart.getDatasetMeta(i);
-                                       arcs = meta.data;
-                                       controller = meta.controller;
-                                       if (controller !== me) {
-                                               controller.configure();
-                                       }
-                                       break;
-                               }
-                       }
-               }
-
-               if (!arcs) {
-                       return 0;
-               }
-
-               for (i = 0, ilen = arcs.length; i < ilen; ++i) {
-                       options = controller.resolveDataElementOptions(i);
-                       if (options.borderAlign !== 'inner') {
-                               max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
-                       }
-               }
-               return max;
-       }
-
-       getMaxOffset(arcs) {
-               let max = 0;
-
-               for (let i = 0, ilen = arcs.length; i < ilen; ++i) {
-                       const options = this.resolveDataElementOptions(i);
-                       max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
-               }
-               return max;
-       }
-
-       /**
+  _circumference(i, reset) {
+    const me = this;
+    const opts = me.chart.options;
+    const meta = me._cachedMeta;
+    const circumference = me._getCircumference();
+    return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * circumference / TAU) : 0;
+  }
+
+  updateElements(arcs, start, count, mode) {
+    const me = this;
+    const reset = mode === 'reset';
+    const chart = me.chart;
+    const chartArea = chart.chartArea;
+    const opts = chart.options;
+    const animationOpts = opts.animation;
+    const centerX = (chartArea.left + chartArea.right) / 2;
+    const centerY = (chartArea.top + chartArea.bottom) / 2;
+    const animateScale = reset && animationOpts.animateScale;
+    const innerRadius = animateScale ? 0 : me.innerRadius;
+    const outerRadius = animateScale ? 0 : me.outerRadius;
+    const firstOpts = me.resolveDataElementOptions(start, mode);
+    const sharedOptions = me.getSharedOptions(firstOpts);
+    const includeOptions = me.includeOptions(mode, sharedOptions);
+    let startAngle = me._getRotation();
+    let i;
+
+    for (i = 0; i < start; ++i) {
+      startAngle += me._circumference(i, reset);
+    }
+
+    for (i = start; i < start + count; ++i) {
+      const circumference = me._circumference(i, reset);
+      const arc = arcs[i];
+      const properties = {
+        x: centerX + me.offsetX,
+        y: centerY + me.offsetY,
+        startAngle,
+        endAngle: startAngle + circumference,
+        circumference,
+        outerRadius,
+        innerRadius
+      };
+      if (includeOptions) {
+        properties.options = sharedOptions || me.resolveDataElementOptions(i, mode);
+      }
+      startAngle += circumference;
+
+      me.updateElement(arc, i, properties, mode);
+    }
+    me.updateSharedOptions(sharedOptions, mode, firstOpts);
+  }
+
+  calculateTotal() {
+    const meta = this._cachedMeta;
+    const metaData = meta.data;
+    let total = 0;
+    let i;
+
+    for (i = 0; i < metaData.length; i++) {
+      const value = meta._parsed[i];
+      if (!isNaN(value) && this.chart.getDataVisibility(i)) {
+        total += Math.abs(value);
+      }
+    }
+
+    return total;
+  }
+
+  calculateCircumference(value) {
+    const total = this._cachedMeta.total;
+    if (total > 0 && !isNaN(value)) {
+      return TAU * (Math.abs(value) / total);
+    }
+    return 0;
+  }
+
+  getLabelAndValue(index) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const chart = me.chart;
+    const labels = chart.data.labels || [];
+    const value = formatNumber(meta._parsed[index], chart.options.locale);
+
+    return {
+      label: labels[index] || '',
+      value,
+    };
+  }
+
+  getMaxBorderWidth(arcs) {
+    const me = this;
+    let max = 0;
+    const chart = me.chart;
+    let i, ilen, meta, controller, options;
+
+    if (!arcs) {
+      // Find the outmost visible dataset
+      for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+        if (chart.isDatasetVisible(i)) {
+          meta = chart.getDatasetMeta(i);
+          arcs = meta.data;
+          controller = meta.controller;
+          if (controller !== me) {
+            controller.configure();
+          }
+          break;
+        }
+      }
+    }
+
+    if (!arcs) {
+      return 0;
+    }
+
+    for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+      options = controller.resolveDataElementOptions(i);
+      if (options.borderAlign !== 'inner') {
+        max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
+      }
+    }
+    return max;
+  }
+
+  getMaxOffset(arcs) {
+    let max = 0;
+
+    for (let i = 0, ilen = arcs.length; i < ilen; ++i) {
+      const options = this.resolveDataElementOptions(i);
+      max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
+    }
+    return max;
+  }
+
+  /**
         * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
         * @private
         */
-       _getRingWeightOffset(datasetIndex) {
-               let ringWeightOffset = 0;
+  _getRingWeightOffset(datasetIndex) {
+    let ringWeightOffset = 0;
 
-               for (let i = 0; i < datasetIndex; ++i) {
-                       if (this.chart.isDatasetVisible(i)) {
-                               ringWeightOffset += this._getRingWeight(i);
-                       }
-               }
+    for (let i = 0; i < datasetIndex; ++i) {
+      if (this.chart.isDatasetVisible(i)) {
+        ringWeightOffset += this._getRingWeight(i);
+      }
+    }
 
-               return ringWeightOffset;
-       }
+    return ringWeightOffset;
+  }
 
-       /**
+  /**
         * @private
         */
-       _getRingWeight(datasetIndex) {
-               return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);
-       }
+  _getRingWeight(datasetIndex) {
+    return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);
+  }
 
-       /**
+  /**
         * Returns the sum of all visible data set weights.
         * @private
         */
-       _getVisibleDatasetWeightTotal() {
-               return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
-       }
+  _getVisibleDatasetWeightTotal() {
+    return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
+  }
 }
 
 DoughnutController.id = 'doughnut';
@@ -326,89 +326,89 @@ DoughnutController.id = 'doughnut';
  * @type {any}
  */
 DoughnutController.defaults = {
-       datasetElementType: false,
-       dataElementType: 'arc',
-       dataElementOptions: [
-               'backgroundColor',
-               'borderColor',
-               'borderWidth',
-               'borderAlign',
-               'offset'
-       ],
-       animation: {
-               numbers: {
-                       type: 'number',
-                       properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth']
-               },
-               // Boolean - Whether we animate the rotation of the Doughnut
-               animateRotate: true,
-               // Boolean - Whether we animate scaling the Doughnut from the centre
-               animateScale: false
-       },
-       aspectRatio: 1,
-
-       // The percentage of the chart that we cut out of the middle.
-       cutoutPercentage: 50,
-
-       // The rotation of the chart, where the first data arc begins.
-       rotation: 0,
-
-       // The total circumference of the chart.
-       circumference: 360,
-
-       // Need to override these to give a nice default
-       plugins: {
-               legend: {
-                       labels: {
-                               generateLabels(chart) {
-                                       const data = chart.data;
-                                       if (data.labels.length && data.datasets.length) {
-                                               return data.labels.map((label, i) => {
-                                                       const meta = chart.getDatasetMeta(0);
-                                                       const style = meta.controller.getStyle(i);
-
-                                                       return {
-                                                               text: label,
-                                                               fillStyle: style.backgroundColor,
-                                                               strokeStyle: style.borderColor,
-                                                               lineWidth: style.borderWidth,
-                                                               hidden: !chart.getDataVisibility(i),
-
-                                                               // Extra data used for toggling the correct item
-                                                               index: i
-                                                       };
-                                               });
-                                       }
-                                       return [];
-                               }
-                       },
-
-                       onClick(e, legendItem, legend) {
-                               legend.chart.toggleDataVisibility(legendItem.index);
-                               legend.chart.update();
-                       }
-               },
-               tooltip: {
-                       callbacks: {
-                               title() {
-                                       return '';
-                               },
-                               label(tooltipItem) {
-                                       let dataLabel = tooltipItem.label;
-                                       const value = ': ' + tooltipItem.formattedValue;
-
-                                       if (isArray(dataLabel)) {
-                                               // show value on first line of multiline label
-                                               // need to clone because we are changing the value
-                                               dataLabel = dataLabel.slice();
-                                               dataLabel[0] += value;
-                                       } else {
-                                               dataLabel += value;
-                                       }
-
-                                       return dataLabel;
-                               }
-                       }
-               }
-       }
+  datasetElementType: false,
+  dataElementType: 'arc',
+  dataElementOptions: [
+    'backgroundColor',
+    'borderColor',
+    'borderWidth',
+    'borderAlign',
+    'offset'
+  ],
+  animation: {
+    numbers: {
+      type: 'number',
+      properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth']
+    },
+    // Boolean - Whether we animate the rotation of the Doughnut
+    animateRotate: true,
+    // Boolean - Whether we animate scaling the Doughnut from the centre
+    animateScale: false
+  },
+  aspectRatio: 1,
+
+  // The percentage of the chart that we cut out of the middle.
+  cutoutPercentage: 50,
+
+  // The rotation of the chart, where the first data arc begins.
+  rotation: 0,
+
+  // The total circumference of the chart.
+  circumference: 360,
+
+  // Need to override these to give a nice default
+  plugins: {
+    legend: {
+      labels: {
+        generateLabels(chart) {
+          const data = chart.data;
+          if (data.labels.length && data.datasets.length) {
+            return data.labels.map((label, i) => {
+              const meta = chart.getDatasetMeta(0);
+              const style = meta.controller.getStyle(i);
+
+              return {
+                text: label,
+                fillStyle: style.backgroundColor,
+                strokeStyle: style.borderColor,
+                lineWidth: style.borderWidth,
+                hidden: !chart.getDataVisibility(i),
+
+                // Extra data used for toggling the correct item
+                index: i
+              };
+            });
+          }
+          return [];
+        }
+      },
+
+      onClick(e, legendItem, legend) {
+        legend.chart.toggleDataVisibility(legendItem.index);
+        legend.chart.update();
+      }
+    },
+    tooltip: {
+      callbacks: {
+        title() {
+          return '';
+        },
+        label(tooltipItem) {
+          let dataLabel = tooltipItem.label;
+          const value = ': ' + tooltipItem.formattedValue;
+
+          if (isArray(dataLabel)) {
+            // show value on first line of multiline label
+            // need to clone because we are changing the value
+            dataLabel = dataLabel.slice();
+            dataLabel[0] += value;
+          } else {
+            dataLabel += value;
+          }
+
+          return dataLabel;
+        }
+      }
+    }
+  }
 };
index 3690fa90dbce24f7b1e39e1208ee0d5b927dc91f..ed3f9319ed1324b9e1bd79dd2ed6c683ee0a6a14 100644 (file)
@@ -6,123 +6,123 @@ import {_lookupByKey} from '../helpers/helpers.collection';
 
 export default class LineController extends DatasetController {
 
-       initialize() {
-               this.enableOptionSharing = true;
-               super.initialize();
-       }
-
-       update(mode) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const {dataset: line, data: points = []} = meta;
-               // @ts-ignore
-               const animationsDisabled = me.chart._animationsDisabled;
-               let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);
-
-               me._drawStart = start;
-               me._drawCount = count;
-
-               if (scaleRangesChanged(meta) && !animationsDisabled) {
-                       start = 0;
-                       count = points.length;
-               }
-
-               // Update Line
-               line.points = points;
-
-               // In resize mode only point locations change, so no need to set the options.
-               if (mode !== 'resize') {
-                       me.updateElement(line, undefined, {
-                               animated: !animationsDisabled,
-                               options: me.resolveDatasetElementOptions()
-                       }, mode);
-               }
-
-               // Update Points
-               me.updateElements(points, start, count, mode);
-       }
-
-       updateElements(points, start, count, mode) {
-               const me = this;
-               const reset = mode === 'reset';
-               const {xScale, yScale, _stacked} = me._cachedMeta;
-               const firstOpts = me.resolveDataElementOptions(start, mode);
-               const sharedOptions = me.getSharedOptions(firstOpts);
-               const includeOptions = me.includeOptions(mode, sharedOptions);
-               const spanGaps = valueOrDefault(me._config.spanGaps, me.chart.options.spanGaps);
-               const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
-               const directUpdate = me.chart._animationsDisabled || reset || mode === 'none';
-               let prevParsed = start > 0 && me.getParsed(start - 1);
-
-               for (let i = start; i < start + count; ++i) {
-                       const point = points[i];
-                       const parsed = me.getParsed(i);
-                       const properties = directUpdate ? point : {};
-                       const x = properties.x = xScale.getPixelForValue(parsed.x, i);
-                       const y = properties.y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed) : parsed.y, i);
-                       properties.skip = isNaN(x) || isNaN(y);
-                       properties.stop = i > 0 && (parsed.x - prevParsed.x) > maxGapLength;
-
-                       if (includeOptions) {
-                               properties.options = sharedOptions || me.resolveDataElementOptions(i, mode);
-                       }
-
-                       if (!directUpdate) {
-                               me.updateElement(point, i, properties, mode);
-                       }
-
-                       prevParsed = parsed;
-               }
-
-               me.updateSharedOptions(sharedOptions, mode, firstOpts);
-       }
-
-       /**
+  initialize() {
+    this.enableOptionSharing = true;
+    super.initialize();
+  }
+
+  update(mode) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const {dataset: line, data: points = []} = meta;
+    // @ts-ignore
+    const animationsDisabled = me.chart._animationsDisabled;
+    let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);
+
+    me._drawStart = start;
+    me._drawCount = count;
+
+    if (scaleRangesChanged(meta) && !animationsDisabled) {
+      start = 0;
+      count = points.length;
+    }
+
+    // Update Line
+    line.points = points;
+
+    // In resize mode only point locations change, so no need to set the options.
+    if (mode !== 'resize') {
+      me.updateElement(line, undefined, {
+        animated: !animationsDisabled,
+        options: me.resolveDatasetElementOptions()
+      }, mode);
+    }
+
+    // Update Points
+    me.updateElements(points, start, count, mode);
+  }
+
+  updateElements(points, start, count, mode) {
+    const me = this;
+    const reset = mode === 'reset';
+    const {xScale, yScale, _stacked} = me._cachedMeta;
+    const firstOpts = me.resolveDataElementOptions(start, mode);
+    const sharedOptions = me.getSharedOptions(firstOpts);
+    const includeOptions = me.includeOptions(mode, sharedOptions);
+    const spanGaps = valueOrDefault(me._config.spanGaps, me.chart.options.spanGaps);
+    const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
+    const directUpdate = me.chart._animationsDisabled || reset || mode === 'none';
+    let prevParsed = start > 0 && me.getParsed(start - 1);
+
+    for (let i = start; i < start + count; ++i) {
+      const point = points[i];
+      const parsed = me.getParsed(i);
+      const properties = directUpdate ? point : {};
+      const x = properties.x = xScale.getPixelForValue(parsed.x, i);
+      const y = properties.y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed) : parsed.y, i);
+      properties.skip = isNaN(x) || isNaN(y);
+      properties.stop = i > 0 && (parsed.x - prevParsed.x) > maxGapLength;
+
+      if (includeOptions) {
+        properties.options = sharedOptions || me.resolveDataElementOptions(i, mode);
+      }
+
+      if (!directUpdate) {
+        me.updateElement(point, i, properties, mode);
+      }
+
+      prevParsed = parsed;
+    }
+
+    me.updateSharedOptions(sharedOptions, mode, firstOpts);
+  }
+
+  /**
         * @param {boolean} [active]
         * @protected
         */
-       resolveDatasetElementOptions(active) {
-               const me = this;
-               const config = me._config;
-               const options = me.chart.options;
-               const lineOptions = options.elements.line;
-               const values = super.resolveDatasetElementOptions(active);
-               const showLine = valueOrDefault(config.showLine, options.showLine);
-
-               // The default behavior of lines is to break at null values, according
-               // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
-               // This option gives lines the ability to span gaps
-               values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps);
-               values.tension = valueOrDefault(config.tension, lineOptions.tension);
-               values.stepped = resolve([config.stepped, lineOptions.stepped]);
-
-               if (!showLine) {
-                       values.borderWidth = 0;
-               }
-
-               return values;
-       }
-
-       /**
+  resolveDatasetElementOptions(active) {
+    const me = this;
+    const config = me._config;
+    const options = me.chart.options;
+    const lineOptions = options.elements.line;
+    const values = super.resolveDatasetElementOptions(active);
+    const showLine = valueOrDefault(config.showLine, options.showLine);
+
+    // The default behavior of lines is to break at null values, according
+    // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
+    // This option gives lines the ability to span gaps
+    values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps);
+    values.tension = valueOrDefault(config.tension, lineOptions.tension);
+    values.stepped = resolve([config.stepped, lineOptions.stepped]);
+
+    if (!showLine) {
+      values.borderWidth = 0;
+    }
+
+    return values;
+  }
+
+  /**
         * @protected
         */
-       getMaxOverflow() {
-               const me = this;
-               const meta = me._cachedMeta;
-               const border = meta.dataset.options.borderWidth || 0;
-               const data = meta.data || [];
-               if (!data.length) {
-                       return border;
-               }
-               const firstPoint = data[0].size();
-               const lastPoint = data[data.length - 1].size();
-               return Math.max(border, firstPoint, lastPoint) / 2;
-       }
-
-       draw() {
-               this._cachedMeta.dataset.updateControlPoints(this.chart.chartArea);
-               super.draw();
-       }
+  getMaxOverflow() {
+    const me = this;
+    const meta = me._cachedMeta;
+    const border = meta.dataset.options.borderWidth || 0;
+    const data = meta.data || [];
+    if (!data.length) {
+      return border;
+    }
+    const firstPoint = data[0].size();
+    const lastPoint = data[data.length - 1].size();
+    return Math.max(border, firstPoint, lastPoint) / 2;
+  }
+
+  draw() {
+    this._cachedMeta.dataset.updateControlPoints(this.chart.chartArea);
+    super.draw();
+  }
 }
 
 LineController.id = 'line';
@@ -131,101 +131,101 @@ LineController.id = 'line';
  * @type {any}
  */
 LineController.defaults = {
-       datasetElementType: 'line',
-       datasetElementOptions: [
-               'backgroundColor',
-               'borderCapStyle',
-               'borderColor',
-               'borderDash',
-               'borderDashOffset',
-               'borderJoinStyle',
-               'borderWidth',
-               'capBezierPoints',
-               'cubicInterpolationMode',
-               'fill'
-       ],
-
-       dataElementType: 'point',
-       dataElementOptions: {
-               backgroundColor: 'pointBackgroundColor',
-               borderColor: 'pointBorderColor',
-               borderWidth: 'pointBorderWidth',
-               hitRadius: 'pointHitRadius',
-               hoverHitRadius: 'pointHitRadius',
-               hoverBackgroundColor: 'pointHoverBackgroundColor',
-               hoverBorderColor: 'pointHoverBorderColor',
-               hoverBorderWidth: 'pointHoverBorderWidth',
-               hoverRadius: 'pointHoverRadius',
-               pointStyle: 'pointStyle',
-               radius: 'pointRadius',
-               rotation: 'pointRotation'
-       },
-
-       showLine: true,
-       spanGaps: false,
-
-       interaction: {
-               mode: 'index'
-       },
-
-       hover: {},
-
-       scales: {
-               _index_: {
-                       type: 'category',
-               },
-               _value_: {
-                       type: 'linear',
-               },
-       }
+  datasetElementType: 'line',
+  datasetElementOptions: [
+    'backgroundColor',
+    'borderCapStyle',
+    'borderColor',
+    'borderDash',
+    'borderDashOffset',
+    'borderJoinStyle',
+    'borderWidth',
+    'capBezierPoints',
+    'cubicInterpolationMode',
+    'fill'
+  ],
+
+  dataElementType: 'point',
+  dataElementOptions: {
+    backgroundColor: 'pointBackgroundColor',
+    borderColor: 'pointBorderColor',
+    borderWidth: 'pointBorderWidth',
+    hitRadius: 'pointHitRadius',
+    hoverHitRadius: 'pointHitRadius',
+    hoverBackgroundColor: 'pointHoverBackgroundColor',
+    hoverBorderColor: 'pointHoverBorderColor',
+    hoverBorderWidth: 'pointHoverBorderWidth',
+    hoverRadius: 'pointHoverRadius',
+    pointStyle: 'pointStyle',
+    radius: 'pointRadius',
+    rotation: 'pointRotation'
+  },
+
+  showLine: true,
+  spanGaps: false,
+
+  interaction: {
+    mode: 'index'
+  },
+
+  hover: {},
+
+  scales: {
+    _index_: {
+      type: 'category',
+    },
+    _value_: {
+      type: 'linear',
+    },
+  }
 };
 
 function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
-       const pointCount = points.length;
-
-       let start = 0;
-       let count = pointCount;
-
-       if (meta._sorted) {
-               const {iScale, _parsed} = meta;
-               const axis = iScale.axis;
-               const {min, max, minDefined, maxDefined} = iScale.getUserBounds();
-               if (minDefined) {
-                       start = _limitValue(Math.min(
-                               _lookupByKey(_parsed, iScale.axis, min).lo,
-                               animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo),
-                       0, pointCount - 1);
-               }
-               if (maxDefined) {
-                       count = _limitValue(Math.max(
-                               _lookupByKey(_parsed, iScale.axis, max).hi + 1,
-                               animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1),
-                       start, pointCount) - start;
-               } else {
-                       count = pointCount - start;
-               }
-       }
-
-       return {start, count};
+  const pointCount = points.length;
+
+  let start = 0;
+  let count = pointCount;
+
+  if (meta._sorted) {
+    const {iScale, _parsed} = meta;
+    const axis = iScale.axis;
+    const {min, max, minDefined, maxDefined} = iScale.getUserBounds();
+    if (minDefined) {
+      start = _limitValue(Math.min(
+        _lookupByKey(_parsed, iScale.axis, min).lo,
+        animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo),
+      0, pointCount - 1);
+    }
+    if (maxDefined) {
+      count = _limitValue(Math.max(
+        _lookupByKey(_parsed, iScale.axis, max).hi + 1,
+        animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1),
+      start, pointCount) - start;
+    } else {
+      count = pointCount - start;
+    }
+  }
+
+  return {start, count};
 }
 
 function scaleRangesChanged(meta) {
-       const {xScale, yScale, _scaleRanges} = meta;
-       const newRanges = {
-               xmin: xScale.min,
-               xmax: xScale.max,
-               ymin: yScale.min,
-               ymax: yScale.max
-       };
-       if (!_scaleRanges) {
-               meta._scaleRanges = newRanges;
-               return true;
-       }
-       const changed = _scaleRanges.xmin !== xScale.min
+  const {xScale, yScale, _scaleRanges} = meta;
+  const newRanges = {
+    xmin: xScale.min,
+    xmax: xScale.max,
+    ymin: yScale.min,
+    ymax: yScale.max
+  };
+  if (!_scaleRanges) {
+    meta._scaleRanges = newRanges;
+    return true;
+  }
+  const changed = _scaleRanges.xmin !== xScale.min
                || _scaleRanges.xmax !== xScale.max
                || _scaleRanges.ymin !== yScale.min
                || _scaleRanges.ymax !== yScale.max;
 
-       Object.assign(_scaleRanges, newRanges);
-       return changed;
+  Object.assign(_scaleRanges, newRanges);
+  return changed;
 }
index de95a69ef5d4a71a65b5fb9620a1a0726d03bbdd..158590a18f0aacd9d180aabdca80736c1decc853 100644 (file)
@@ -11,5 +11,5 @@ PieController.id = 'pie';
  * @type {any}
  */
 PieController.defaults = {
-       cutoutPercentage: 0
+  cutoutPercentage: 0
 };
index 432268a240e299fcd4530966e34bc028b06e7001..d322e70a3e60e4784f256705224e9a73724d3fef 100644 (file)
@@ -2,130 +2,130 @@ import DatasetController from '../core/core.datasetController';
 import {resolve, toRadians, PI} from '../helpers/index';
 
 function getStartAngleRadians(deg) {
-       // radialLinear scale draws angleLines using startAngle. 0 is expected to be at top.
-       // Here we adjust to standard unit circle used in drawing, where 0 is at right.
-       return toRadians(deg) - 0.5 * PI;
+  // radialLinear scale draws angleLines using startAngle. 0 is expected to be at top.
+  // Here we adjust to standard unit circle used in drawing, where 0 is at right.
+  return toRadians(deg) - 0.5 * PI;
 }
 
 export default class PolarAreaController extends DatasetController {
 
-       constructor(chart, datasetIndex) {
-               super(chart, datasetIndex);
+  constructor(chart, datasetIndex) {
+    super(chart, datasetIndex);
 
-               this.innerRadius = undefined;
-               this.outerRadius = undefined;
-       }
+    this.innerRadius = undefined;
+    this.outerRadius = undefined;
+  }
 
-       update(mode) {
-               const arcs = this._cachedMeta.data;
+  update(mode) {
+    const arcs = this._cachedMeta.data;
 
-               this._updateRadius();
-               this.updateElements(arcs, 0, arcs.length, mode);
-       }
+    this._updateRadius();
+    this.updateElements(arcs, 0, arcs.length, mode);
+  }
 
-       /**
+  /**
         * @private
         */
-       _updateRadius() {
-               const me = this;
-               const chart = me.chart;
-               const chartArea = chart.chartArea;
-               const opts = chart.options;
-               const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
-
-               const outerRadius = Math.max(minSize / 2, 0);
-               const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
-               const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
-
-               me.outerRadius = outerRadius - (radiusLength * me.index);
-               me.innerRadius = me.outerRadius - radiusLength;
-       }
-
-       updateElements(arcs, start, count, mode) {
-               const me = this;
-               const reset = mode === 'reset';
-               const chart = me.chart;
-               const dataset = me.getDataset();
-               const opts = chart.options;
-               const animationOpts = opts.animation;
-               const scale = me._cachedMeta.rScale;
-               const centerX = scale.xCenter;
-               const centerY = scale.yCenter;
-               const datasetStartAngle = getStartAngleRadians(opts.startAngle);
-               let angle = datasetStartAngle;
-               let i;
-
-               me._cachedMeta.count = me.countVisibleElements();
-
-               for (i = 0; i < start; ++i) {
-                       angle += me._computeAngle(i, mode);
-               }
-               for (i = start; i < start + count; i++) {
-                       const arc = arcs[i];
-                       let startAngle = angle;
-                       let endAngle = angle + me._computeAngle(i, mode);
-                       let outerRadius = this.chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0;
-                       angle = endAngle;
-
-                       if (reset) {
-                               if (animationOpts.animateScale) {
-                                       outerRadius = 0;
-                               }
-                               if (animationOpts.animateRotate) {
-                                       startAngle = datasetStartAngle;
-                                       endAngle = datasetStartAngle;
-                               }
-                       }
-
-                       const properties = {
-                               x: centerX,
-                               y: centerY,
-                               innerRadius: 0,
-                               outerRadius,
-                               startAngle,
-                               endAngle,
-                               options: me.resolveDataElementOptions(i, mode)
-                       };
-
-                       me.updateElement(arc, i, properties, mode);
-               }
-       }
-
-       countVisibleElements() {
-               const dataset = this.getDataset();
-               const meta = this._cachedMeta;
-               let count = 0;
-
-               meta.data.forEach((element, index) => {
-                       if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) {
-                               count++;
-                       }
-               });
-
-               return count;
-       }
-
-       /**
+  _updateRadius() {
+    const me = this;
+    const chart = me.chart;
+    const chartArea = chart.chartArea;
+    const opts = chart.options;
+    const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+
+    const outerRadius = Math.max(minSize / 2, 0);
+    const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+    const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
+
+    me.outerRadius = outerRadius - (radiusLength * me.index);
+    me.innerRadius = me.outerRadius - radiusLength;
+  }
+
+  updateElements(arcs, start, count, mode) {
+    const me = this;
+    const reset = mode === 'reset';
+    const chart = me.chart;
+    const dataset = me.getDataset();
+    const opts = chart.options;
+    const animationOpts = opts.animation;
+    const scale = me._cachedMeta.rScale;
+    const centerX = scale.xCenter;
+    const centerY = scale.yCenter;
+    const datasetStartAngle = getStartAngleRadians(opts.startAngle);
+    let angle = datasetStartAngle;
+    let i;
+
+    me._cachedMeta.count = me.countVisibleElements();
+
+    for (i = 0; i < start; ++i) {
+      angle += me._computeAngle(i, mode);
+    }
+    for (i = start; i < start + count; i++) {
+      const arc = arcs[i];
+      let startAngle = angle;
+      let endAngle = angle + me._computeAngle(i, mode);
+      let outerRadius = this.chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0;
+      angle = endAngle;
+
+      if (reset) {
+        if (animationOpts.animateScale) {
+          outerRadius = 0;
+        }
+        if (animationOpts.animateRotate) {
+          startAngle = datasetStartAngle;
+          endAngle = datasetStartAngle;
+        }
+      }
+
+      const properties = {
+        x: centerX,
+        y: centerY,
+        innerRadius: 0,
+        outerRadius,
+        startAngle,
+        endAngle,
+        options: me.resolveDataElementOptions(i, mode)
+      };
+
+      me.updateElement(arc, i, properties, mode);
+    }
+  }
+
+  countVisibleElements() {
+    const dataset = this.getDataset();
+    const meta = this._cachedMeta;
+    let count = 0;
+
+    meta.data.forEach((element, index) => {
+      if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) {
+        count++;
+      }
+    });
+
+    return count;
+  }
+
+  /**
         * @private
         */
-       _computeAngle(index, mode) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const count = meta.count;
-               const dataset = me.getDataset();
-
-               if (isNaN(dataset.data[index]) || !this.chart.getDataVisibility(index)) {
-                       return 0;
-               }
-
-               // Scriptable options
-               const context = me.getContext(index, mode === 'active');
-
-               return toRadians(resolve([
-                       me.chart.options.elements.arc.angle,
-                       360 / count
-               ], context, index));
-       }
+  _computeAngle(index, mode) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const count = meta.count;
+    const dataset = me.getDataset();
+
+    if (isNaN(dataset.data[index]) || !this.chart.getDataVisibility(index)) {
+      return 0;
+    }
+
+    // Scriptable options
+    const context = me.getContext(index, mode === 'active');
+
+    return toRadians(resolve([
+      me.chart.options.elements.arc.angle,
+      360 / count
+    ], context, index));
+  }
 }
 
 PolarAreaController.id = 'polarArea';
@@ -134,87 +134,87 @@ PolarAreaController.id = 'polarArea';
  * @type {any}
  */
 PolarAreaController.defaults = {
-       dataElementType: 'arc',
-       dataElementOptions: [
-               'backgroundColor',
-               'borderColor',
-               'borderWidth',
-               'borderAlign',
-               'offset'
-       ],
-
-       animation: {
-               numbers: {
-                       type: 'number',
-                       properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
-               },
-               animateRotate: true,
-               animateScale: true
-       },
-       aspectRatio: 1,
-       datasets: {
-               indexAxis: 'r'
-       },
-       scales: {
-               r: {
-                       type: 'radialLinear',
-                       angleLines: {
-                               display: false
-                       },
-                       beginAtZero: true,
-                       gridLines: {
-                               circular: true
-                       },
-                       pointLabels: {
-                               display: false
-                       }
-               }
-       },
-
-       startAngle: 0,
-       plugins: {
-               legend: {
-                       labels: {
-                               generateLabels(chart) {
-                                       const data = chart.data;
-                                       if (data.labels.length && data.datasets.length) {
-                                               return data.labels.map((label, i) => {
-                                                       const meta = chart.getDatasetMeta(0);
-                                                       const style = meta.controller.getStyle(i);
-
-                                                       return {
-                                                               text: label,
-                                                               fillStyle: style.backgroundColor,
-                                                               strokeStyle: style.borderColor,
-                                                               lineWidth: style.borderWidth,
-                                                               hidden: !chart.getDataVisibility(i),
-
-                                                               // Extra data used for toggling the correct item
-                                                               index: i
-                                                       };
-                                               });
-                                       }
-                                       return [];
-                               }
-                       },
-
-                       onClick(e, legendItem, legend) {
-                               legend.chart.toggleDataVisibility(legendItem.index);
-                               legend.chart.update();
-                       }
-               },
-
-               // Need to override these to give a nice default
-               tooltip: {
-                       callbacks: {
-                               title() {
-                                       return '';
-                               },
-                               label(context) {
-                                       return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue;
-                               }
-                       }
-               }
-       }
+  dataElementType: 'arc',
+  dataElementOptions: [
+    'backgroundColor',
+    'borderColor',
+    'borderWidth',
+    'borderAlign',
+    'offset'
+  ],
+
+  animation: {
+    numbers: {
+      type: 'number',
+      properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
+    },
+    animateRotate: true,
+    animateScale: true
+  },
+  aspectRatio: 1,
+  datasets: {
+    indexAxis: 'r'
+  },
+  scales: {
+    r: {
+      type: 'radialLinear',
+      angleLines: {
+        display: false
+      },
+      beginAtZero: true,
+      gridLines: {
+        circular: true
+      },
+      pointLabels: {
+        display: false
+      }
+    }
+  },
+
+  startAngle: 0,
+  plugins: {
+    legend: {
+      labels: {
+        generateLabels(chart) {
+          const data = chart.data;
+          if (data.labels.length && data.datasets.length) {
+            return data.labels.map((label, i) => {
+              const meta = chart.getDatasetMeta(0);
+              const style = meta.controller.getStyle(i);
+
+              return {
+                text: label,
+                fillStyle: style.backgroundColor,
+                strokeStyle: style.borderColor,
+                lineWidth: style.borderWidth,
+                hidden: !chart.getDataVisibility(i),
+
+                // Extra data used for toggling the correct item
+                index: i
+              };
+            });
+          }
+          return [];
+        }
+      },
+
+      onClick(e, legendItem, legend) {
+        legend.chart.toggleDataVisibility(legendItem.index);
+        legend.chart.update();
+      }
+    },
+
+    // Need to override these to give a nice default
+    tooltip: {
+      callbacks: {
+        title() {
+          return '';
+        },
+        label(context) {
+          return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue;
+        }
+      }
+    }
+  }
 
 };
index 74f03fb92865ff97a0905bb5d255edbc5a2832d1..e197f32827863433197256df84d78089e036f9ab 100644 (file)
@@ -3,90 +3,90 @@ import {valueOrDefault} from '../helpers/helpers.core';
 
 export default class RadarController extends DatasetController {
 
-       /**
+  /**
         * @protected
         */
-       getLabelAndValue(index) {
-               const me = this;
-               const vScale = me._cachedMeta.vScale;
-               const parsed = me.getParsed(index);
-
-               return {
-                       label: vScale.getLabels()[index],
-                       value: '' + vScale.getLabelForValue(parsed[vScale.axis])
-               };
-       }
-
-       update(mode) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const line = meta.dataset;
-               const points = meta.data || [];
-               const labels = meta.iScale.getLabels();
-
-               // Update Line
-               line.points = points;
-               // In resize mode only point locations change, so no need to set the points or options.
-               if (mode !== 'resize') {
-                       const properties = {
-                               _loop: true,
-                               _fullLoop: labels.length === points.length,
-                               options: me.resolveDatasetElementOptions()
-                       };
-
-                       me.updateElement(line, undefined, properties, mode);
-               }
-
-               // Update Points
-               me.updateElements(points, 0, points.length, mode);
-       }
-
-       updateElements(points, start, count, mode) {
-               const me = this;
-               const dataset = me.getDataset();
-               const scale = me._cachedMeta.rScale;
-               const reset = mode === 'reset';
-
-               for (let i = start; i < start + count; i++) {
-                       const point = points[i];
-                       const options = me.resolveDataElementOptions(i, mode);
-                       const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);
-
-                       const x = reset ? scale.xCenter : pointPosition.x;
-                       const y = reset ? scale.yCenter : pointPosition.y;
-
-                       const properties = {
-                               x,
-                               y,
-                               angle: pointPosition.angle,
-                               skip: isNaN(x) || isNaN(y),
-                               options
-                       };
-
-                       me.updateElement(point, i, properties, mode);
-               }
-       }
-
-       /**
+  getLabelAndValue(index) {
+    const me = this;
+    const vScale = me._cachedMeta.vScale;
+    const parsed = me.getParsed(index);
+
+    return {
+      label: vScale.getLabels()[index],
+      value: '' + vScale.getLabelForValue(parsed[vScale.axis])
+    };
+  }
+
+  update(mode) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const line = meta.dataset;
+    const points = meta.data || [];
+    const labels = meta.iScale.getLabels();
+
+    // Update Line
+    line.points = points;
+    // In resize mode only point locations change, so no need to set the points or options.
+    if (mode !== 'resize') {
+      const properties = {
+        _loop: true,
+        _fullLoop: labels.length === points.length,
+        options: me.resolveDatasetElementOptions()
+      };
+
+      me.updateElement(line, undefined, properties, mode);
+    }
+
+    // Update Points
+    me.updateElements(points, 0, points.length, mode);
+  }
+
+  updateElements(points, start, count, mode) {
+    const me = this;
+    const dataset = me.getDataset();
+    const scale = me._cachedMeta.rScale;
+    const reset = mode === 'reset';
+
+    for (let i = start; i < start + count; i++) {
+      const point = points[i];
+      const options = me.resolveDataElementOptions(i, mode);
+      const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);
+
+      const x = reset ? scale.xCenter : pointPosition.x;
+      const y = reset ? scale.yCenter : pointPosition.y;
+
+      const properties = {
+        x,
+        y,
+        angle: pointPosition.angle,
+        skip: isNaN(x) || isNaN(y),
+        options
+      };
+
+      me.updateElement(point, i, properties, mode);
+    }
+  }
+
+  /**
         * @param {boolean} [active]
         * @protected
         */
-       resolveDatasetElementOptions(active) {
-               const me = this;
-               const config = me._config;
-               const options = me.chart.options;
-               const values = super.resolveDatasetElementOptions(active);
-               const showLine = valueOrDefault(config.showLine, options.showLine);
-
-               values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps);
-               values.tension = valueOrDefault(config.tension, options.elements.line.tension);
-
-               if (!showLine) {
-                       values.borderWidth = 0;
-               }
-
-               return values;
-       }
+  resolveDatasetElementOptions(active) {
+    const me = this;
+    const config = me._config;
+    const options = me.chart.options;
+    const values = super.resolveDatasetElementOptions(active);
+    const showLine = valueOrDefault(config.showLine, options.showLine);
+
+    values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps);
+    values.tension = valueOrDefault(config.tension, options.elements.line.tension);
+
+    if (!showLine) {
+      values.borderWidth = 0;
+    }
+
+    return values;
+  }
 }
 
 RadarController.id = 'radar';
@@ -95,47 +95,47 @@ RadarController.id = 'radar';
  * @type {any}
  */
 RadarController.defaults = {
-       datasetElementType: 'line',
-       datasetElementOptions: [
-               'backgroundColor',
-               'borderColor',
-               'borderCapStyle',
-               'borderDash',
-               'borderDashOffset',
-               'borderJoinStyle',
-               'borderWidth',
-               'fill'
-       ],
-
-       dataElementType: 'point',
-       dataElementOptions: {
-               backgroundColor: 'pointBackgroundColor',
-               borderColor: 'pointBorderColor',
-               borderWidth: 'pointBorderWidth',
-               hitRadius: 'pointHitRadius',
-               hoverBackgroundColor: 'pointHoverBackgroundColor',
-               hoverBorderColor: 'pointHoverBorderColor',
-               hoverBorderWidth: 'pointHoverBorderWidth',
-               hoverRadius: 'pointHoverRadius',
-               pointStyle: 'pointStyle',
-               radius: 'pointRadius',
-               rotation: 'pointRotation'
-       },
-
-       aspectRatio: 1,
-       spanGaps: false,
-       scales: {
-               r: {
-                       type: 'radialLinear',
-               }
-       },
-       datasets: {
-               indexAxis: 'r'
-       },
-       elements: {
-               line: {
-                       fill: 'start',
-                       tension: 0 // no bezier in radar
-               }
-       }
+  datasetElementType: 'line',
+  datasetElementOptions: [
+    'backgroundColor',
+    'borderColor',
+    'borderCapStyle',
+    'borderDash',
+    'borderDashOffset',
+    'borderJoinStyle',
+    'borderWidth',
+    'fill'
+  ],
+
+  dataElementType: 'point',
+  dataElementOptions: {
+    backgroundColor: 'pointBackgroundColor',
+    borderColor: 'pointBorderColor',
+    borderWidth: 'pointBorderWidth',
+    hitRadius: 'pointHitRadius',
+    hoverBackgroundColor: 'pointHoverBackgroundColor',
+    hoverBorderColor: 'pointHoverBorderColor',
+    hoverBorderWidth: 'pointHoverBorderWidth',
+    hoverRadius: 'pointHoverRadius',
+    pointStyle: 'pointStyle',
+    radius: 'pointRadius',
+    rotation: 'pointRotation'
+  },
+
+  aspectRatio: 1,
+  spanGaps: false,
+  scales: {
+    r: {
+      type: 'radialLinear',
+    }
+  },
+  datasets: {
+    indexAxis: 'r'
+  },
+  elements: {
+    line: {
+      fill: 'start',
+      tension: 0 // no bezier in radar
+    }
+  }
 };
index e13bf50c1a4e5273ac8aea5c4f4dc0a01a3ef604..cc9823f45852c38dd53b685df3f188aa5ba2aeb3 100644 (file)
@@ -10,34 +10,34 @@ ScatterController.id = 'scatter';
  * @type {any}
  */
 ScatterController.defaults = {
-       scales: {
-               x: {
-                       type: 'linear'
-               },
-               y: {
-                       type: 'linear'
-               }
-       },
+  scales: {
+    x: {
+      type: 'linear'
+    },
+    y: {
+      type: 'linear'
+    }
+  },
 
-       datasets: {
-               showLine: false,
-               fill: false
-       },
+  datasets: {
+    showLine: false,
+    fill: false
+  },
 
-       interaction: {
-               mode: 'point'
-       },
+  interaction: {
+    mode: 'point'
+  },
 
-       plugins: {
-               tooltip: {
-                       callbacks: {
-                               title() {
-                                       return '';     // doesn't make sense for scatter since data are formatted as a point
-                               },
-                               label(item) {
-                                       return '(' + item.label + ', ' + item.formattedValue + ')';
-                               }
-                       }
-               }
-       }
+  plugins: {
+    tooltip: {
+      callbacks: {
+        title() {
+          return '';     // doesn't make sense for scatter since data are formatted as a point
+        },
+        label(item) {
+          return '(' + item.label + ', ' + item.formattedValue + ')';
+        }
+      }
+    }
+  }
 };
index 5a13a8304b07c892a1a61b3a97652f0f210e291f..78fad868f080f918f6af50ea9a6720a2a45564a5 100644 (file)
@@ -8,7 +8,7 @@
  * @return {*}
  */
 function abstract() {
-       throw new Error('This method is not implemented: either no adapter can be found or an incomplete integration was provided.');
+  throw new Error('This method is not implemented: either no adapter can be found or an incomplete integration was provided.');
 }
 
 /**
@@ -26,62 +26,62 @@ function abstract() {
 
 export class DateAdapter {
 
-       constructor(options) {
-               this.options = options || {};
-       }
+  constructor(options) {
+    this.options = options || {};
+  }
 
-       /**
+  /**
         * Returns a map of time formats for the supported formatting units defined
         * in Unit as well as 'datetime' representing a detailed date/time string.
         * @returns {{string: string}}
         */
-       formats() {
-               return abstract();
-       }
+  formats() {
+    return abstract();
+  }
 
-       /**
+  /**
         * Parses the given `value` and return the associated timestamp.
         * @param {any} value - the value to parse (usually comes from the data)
         * @param {string} [format] - the expected data format
         * @returns {(number|null)}
         */
-       parse(value, format) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  parse(value, format) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
-       /**
+  /**
         * Returns the formatted date in the specified `format` for a given `timestamp`.
         * @param {number} timestamp - the timestamp to format
         * @param {string} format - the date/time token
         * @return {string}
         */
-       format(timestamp, format) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  format(timestamp, format) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
-       /**
+  /**
         * Adds the specified `amount` of `unit` to the given `timestamp`.
         * @param {number} timestamp - the input timestamp
         * @param {number} amount - the amount to add
         * @param {Unit} unit - the unit as string
         * @return {number}
         */
-       add(timestamp, amount, unit) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  add(timestamp, amount, unit) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
-       /**
+  /**
         * Returns the number of `unit` between the given timestamps.
         * @param {number} a - the input timestamp (reference)
         * @param {number} b - the timestamp to subtract
         * @param {Unit} unit - the unit as string
         * @return {number}
         */
-       diff(a, b, unit) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  diff(a, b, unit) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
-       /**
+  /**
         * Returns start of `unit` for the given `timestamp`.
         * @param {number} timestamp - the input timestamp
         * @param {Unit|'isoWeek'} unit - the unit as string
@@ -89,26 +89,26 @@ export class DateAdapter {
         * and 7 being Sunday (only needed if param *unit* is `isoWeek`).
         * @return {number}
         */
-       startOf(timestamp, unit, weekday) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  startOf(timestamp, unit, weekday) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
-       /**
+  /**
         * Returns end of `unit` for the given `timestamp`.
         * @param {number} timestamp - the input timestamp
         * @param {Unit|'isoWeek'} unit - the unit as string
         * @return {number}
         */
-       endOf(timestamp, unit) { // eslint-disable-line no-unused-vars
-               return abstract();
-       }
+  endOf(timestamp, unit) { // eslint-disable-line no-unused-vars
+    return abstract();
+  }
 
 }
 
 DateAdapter.override = function(members) {
-       Object.assign(DateAdapter.prototype, members);
+  Object.assign(DateAdapter.prototype, members);
 };
 
 export default {
-       _date: DateAdapter
+  _date: DateAdapter
 };
index 100784e59ccb7566a25cd518683382934b639f60..7be74bcef5dca029c427759a2f3677e798685562 100644 (file)
@@ -4,113 +4,113 @@ import {color as helpersColor} from '../helpers/helpers.color';
 
 const transparent = 'transparent';
 const interpolators = {
-       boolean(from, to, factor) {
-               return factor > 0.5 ? to : from;
-       },
-       color(from, to, factor) {
-               const c0 = helpersColor(from || transparent);
-               const c1 = c0.valid && helpersColor(to || transparent);
-               return c1 && c1.valid
-                       ? c1.mix(c0, factor).hexString()
-                       : to;
-       },
-       number(from, to, factor) {
-               return from + (to - from) * factor;
-       }
+  boolean(from, to, factor) {
+    return factor > 0.5 ? to : from;
+  },
+  color(from, to, factor) {
+    const c0 = helpersColor(from || transparent);
+    const c1 = c0.valid && helpersColor(to || transparent);
+    return c1 && c1.valid
+      ? c1.mix(c0, factor).hexString()
+      : to;
+  },
+  number(from, to, factor) {
+    return from + (to - from) * factor;
+  }
 };
 
 export default class Animation {
-       constructor(cfg, target, prop, to) {
-               const currentValue = target[prop];
-
-               to = resolve([cfg.to, to, currentValue, cfg.from]);
-               const from = resolve([cfg.from, currentValue, to]);
-
-               this._active = true;
-               this._fn = cfg.fn || interpolators[cfg.type || typeof from];
-               this._easing = effects[cfg.easing || 'linear'];
-               this._start = Math.floor(Date.now() + (cfg.delay || 0));
-               this._duration = Math.floor(cfg.duration);
-               this._loop = !!cfg.loop;
-               this._target = target;
-               this._prop = prop;
-               this._from = from;
-               this._to = to;
-               this._promises = undefined;
-       }
-
-       active() {
-               return this._active;
-       }
-
-       update(cfg, to, date) {
-               const me = this;
-               if (me._active) {
-                       me._notify(false);
-
-                       const currentValue = me._target[me._prop];
-                       const elapsed = date - me._start;
-                       const remain = me._duration - elapsed;
-                       me._start = date;
-                       me._duration = Math.floor(Math.max(remain, cfg.duration));
-                       me._loop = !!cfg.loop;
-                       me._to = resolve([cfg.to, to, currentValue, cfg.from]);
-                       me._from = resolve([cfg.from, currentValue, to]);
-               }
-       }
-
-       cancel() {
-               const me = this;
-               if (me._active) {
-                       // update current evaluated value, for smoother animations
-                       me.tick(Date.now());
-                       me._active = false;
-                       me._notify(false);
-               }
-       }
-
-       tick(date) {
-               const me = this;
-               const elapsed = date - me._start;
-               const duration = me._duration;
-               const prop = me._prop;
-               const from = me._from;
-               const loop = me._loop;
-               const to = me._to;
-               let factor;
-
-               me._active = from !== to && (loop || (elapsed < duration));
-
-               if (!me._active) {
-                       me._target[prop] = to;
-                       me._notify(true);
-                       return;
-               }
-
-               if (elapsed < 0) {
-                       me._target[prop] = from;
-                       return;
-               }
-
-               factor = (elapsed / duration) % 2;
-               factor = loop && factor > 1 ? 2 - factor : factor;
-               factor = me._easing(Math.min(1, Math.max(0, factor)));
-
-               me._target[prop] = me._fn(from, to, factor);
-       }
-
-       wait() {
-               const promises = this._promises || (this._promises = []);
-               return new Promise((res, rej) => {
-                       promises.push({res, rej});
-               });
-       }
-
-       _notify(resolved) {
-               const method = resolved ? 'res' : 'rej';
-               const promises = this._promises || [];
-               for (let i = 0; i < promises.length; i++) {
-                       promises[i][method]();
-               }
-       }
+  constructor(cfg, target, prop, to) {
+    const currentValue = target[prop];
+
+    to = resolve([cfg.to, to, currentValue, cfg.from]);
+    const from = resolve([cfg.from, currentValue, to]);
+
+    this._active = true;
+    this._fn = cfg.fn || interpolators[cfg.type || typeof from];
+    this._easing = effects[cfg.easing || 'linear'];
+    this._start = Math.floor(Date.now() + (cfg.delay || 0));
+    this._duration = Math.floor(cfg.duration);
+    this._loop = !!cfg.loop;
+    this._target = target;
+    this._prop = prop;
+    this._from = from;
+    this._to = to;
+    this._promises = undefined;
+  }
+
+  active() {
+    return this._active;
+  }
+
+  update(cfg, to, date) {
+    const me = this;
+    if (me._active) {
+      me._notify(false);
+
+      const currentValue = me._target[me._prop];
+      const elapsed = date - me._start;
+      const remain = me._duration - elapsed;
+      me._start = date;
+      me._duration = Math.floor(Math.max(remain, cfg.duration));
+      me._loop = !!cfg.loop;
+      me._to = resolve([cfg.to, to, currentValue, cfg.from]);
+      me._from = resolve([cfg.from, currentValue, to]);
+    }
+  }
+
+  cancel() {
+    const me = this;
+    if (me._active) {
+      // update current evaluated value, for smoother animations
+      me.tick(Date.now());
+      me._active = false;
+      me._notify(false);
+    }
+  }
+
+  tick(date) {
+    const me = this;
+    const elapsed = date - me._start;
+    const duration = me._duration;
+    const prop = me._prop;
+    const from = me._from;
+    const loop = me._loop;
+    const to = me._to;
+    let factor;
+
+    me._active = from !== to && (loop || (elapsed < duration));
+
+    if (!me._active) {
+      me._target[prop] = to;
+      me._notify(true);
+      return;
+    }
+
+    if (elapsed < 0) {
+      me._target[prop] = from;
+      return;
+    }
+
+    factor = (elapsed / duration) % 2;
+    factor = loop && factor > 1 ? 2 - factor : factor;
+    factor = me._easing(Math.min(1, Math.max(0, factor)));
+
+    me._target[prop] = me._fn(from, to, factor);
+  }
+
+  wait() {
+    const promises = this._promises || (this._promises = []);
+    return new Promise((res, rej) => {
+      promises.push({res, rej});
+    });
+  }
+
+  _notify(resolved) {
+    const method = resolved ? 'res' : 'rej';
+    const promises = this._promises || [];
+    for (let i = 0; i < promises.length; i++) {
+      promises[i][method]();
+    }
+  }
 }
index 94d2859503348a85241173405ba43728c818fbfc..285592db105a854791bc8821a59c777ca03c5181 100644 (file)
@@ -7,237 +7,237 @@ const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension'];
 const colors = ['borderColor', 'backgroundColor'];
 
 defaults.set('animation', {
-       // Plain properties can be overridden in each object
-       duration: 1000,
-       easing: 'easeOutQuart',
-       onProgress: noop,
-       onComplete: noop,
-
-       // Property sets
-       colors: {
-               type: 'color',
-               properties: colors
-       },
-       numbers: {
-               type: 'number',
-               properties: numbers
-       },
-
-       // Update modes. These are overrides / additions to the above animations.
-       active: {
-               duration: 400
-       },
-       resize: {
-               duration: 0
-       },
-       show: {
-               colors: {
-                       type: 'color',
-                       properties: colors,
-                       from: 'transparent'
-               },
-               visible: {
-                       type: 'boolean',
-                       duration: 0 // show immediately
-               },
-       },
-       hide: {
-               colors: {
-                       type: 'color',
-                       properties: colors,
-                       to: 'transparent'
-               },
-               visible: {
-                       type: 'boolean',
-                       easing: 'easeInExpo' // for keeping the dataset visible almost all the way through the animation
-               },
-       }
+  // Plain properties can be overridden in each object
+  duration: 1000,
+  easing: 'easeOutQuart',
+  onProgress: noop,
+  onComplete: noop,
+
+  // Property sets
+  colors: {
+    type: 'color',
+    properties: colors
+  },
+  numbers: {
+    type: 'number',
+    properties: numbers
+  },
+
+  // Update modes. These are overrides / additions to the above animations.
+  active: {
+    duration: 400
+  },
+  resize: {
+    duration: 0
+  },
+  show: {
+    colors: {
+      type: 'color',
+      properties: colors,
+      from: 'transparent'
+    },
+    visible: {
+      type: 'boolean',
+      duration: 0 // show immediately
+    },
+  },
+  hide: {
+    colors: {
+      type: 'color',
+      properties: colors,
+      to: 'transparent'
+    },
+    visible: {
+      type: 'boolean',
+      easing: 'easeInExpo' // for keeping the dataset visible almost all the way through the animation
+    },
+  }
 });
 
 function copyOptions(target, values) {
-       const oldOpts = target.options;
-       const newOpts = values.options;
-       if (!oldOpts || !newOpts) {
-               return;
-       }
-       if (oldOpts.$shared && !newOpts.$shared) {
-               target.options = Object.assign({}, oldOpts, newOpts, {$shared: false});
-       } else {
-               Object.assign(oldOpts, newOpts);
-       }
-       delete values.options;
+  const oldOpts = target.options;
+  const newOpts = values.options;
+  if (!oldOpts || !newOpts) {
+    return;
+  }
+  if (oldOpts.$shared && !newOpts.$shared) {
+    target.options = Object.assign({}, oldOpts, newOpts, {$shared: false});
+  } else {
+    Object.assign(oldOpts, newOpts);
+  }
+  delete values.options;
 }
 
 function extensibleConfig(animations) {
-       const result = {};
-       Object.keys(animations).forEach(key => {
-               const value = animations[key];
-               if (!isObject(value)) {
-                       result[key] = value;
-               }
-       });
-       return result;
+  const result = {};
+  Object.keys(animations).forEach(key => {
+    const value = animations[key];
+    if (!isObject(value)) {
+      result[key] = value;
+    }
+  });
+  return result;
 }
 
 export default class Animations {
-       constructor(chart, animations) {
-               this._chart = chart;
-               this._properties = new Map();
-               this.configure(animations);
-       }
-
-       configure(animations) {
-               if (!isObject(animations)) {
-                       return;
-               }
-
-               const animatedProps = this._properties;
-               const animDefaults = extensibleConfig(animations);
-
-               Object.keys(animations).forEach(key => {
-                       const cfg = animations[key];
-                       if (!isObject(cfg)) {
-                               return;
-                       }
-                       (cfg.properties || [key]).forEach((prop) => {
-                               // Can have only one config per animation.
-                               if (!animatedProps.has(prop)) {
-                                       animatedProps.set(prop, Object.assign({}, animDefaults, cfg));
-                               } else if (prop === key) {
-                                       // Single property targetting config wins over multi-targetting.
-                                       // eslint-disable-next-line no-unused-vars
-                                       const {properties, ...inherited} = animatedProps.get(prop);
-                                       animatedProps.set(prop, Object.assign({}, inherited, cfg));
-                               }
-                       });
-               });
-       }
-
-       /**
+  constructor(chart, animations) {
+    this._chart = chart;
+    this._properties = new Map();
+    this.configure(animations);
+  }
+
+  configure(animations) {
+    if (!isObject(animations)) {
+      return;
+    }
+
+    const animatedProps = this._properties;
+    const animDefaults = extensibleConfig(animations);
+
+    Object.keys(animations).forEach(key => {
+      const cfg = animations[key];
+      if (!isObject(cfg)) {
+        return;
+      }
+      (cfg.properties || [key]).forEach((prop) => {
+        // Can have only one config per animation.
+        if (!animatedProps.has(prop)) {
+          animatedProps.set(prop, Object.assign({}, animDefaults, cfg));
+        } else if (prop === key) {
+          // Single property targetting config wins over multi-targetting.
+          // eslint-disable-next-line no-unused-vars
+          const {properties, ...inherited} = animatedProps.get(prop);
+          animatedProps.set(prop, Object.assign({}, inherited, cfg));
+        }
+      });
+    });
+  }
+
+  /**
         * Utility to handle animation of `options`.
         * @private
         */
-       _animateOptions(target, values) {
-               const newOptions = values.options;
-               const options = resolveTargetOptions(target, newOptions);
-               if (!options) {
-                       return [];
-               }
-
-               const animations = this._createAnimations(options, newOptions);
-               if (newOptions.$shared && !options.$shared) {
-                       // Going from distinct options to shared options:
-                       // After all animations are done, assign the shared options object to the element
-                       // So any new updates to the shared options are observed
-                       awaitAll(target.options.$animations, newOptions).then(() => {
-                               target.options = newOptions;
-                       }, () => {
-                               // rejected, noop
-                       });
-               }
-
-               return animations;
-       }
-
-       /**
+  _animateOptions(target, values) {
+    const newOptions = values.options;
+    const options = resolveTargetOptions(target, newOptions);
+    if (!options) {
+      return [];
+    }
+
+    const animations = this._createAnimations(options, newOptions);
+    if (newOptions.$shared && !options.$shared) {
+      // Going from distinct options to shared options:
+      // After all animations are done, assign the shared options object to the element
+      // So any new updates to the shared options are observed
+      awaitAll(target.options.$animations, newOptions).then(() => {
+        target.options = newOptions;
+      }, () => {
+        // rejected, noop
+      });
+    }
+
+    return animations;
+  }
+
+  /**
         * @private
         */
-       _createAnimations(target, values) {
-               const animatedProps = this._properties;
-               const animations = [];
-               const running = target.$animations || (target.$animations = {});
-               const props = Object.keys(values);
-               const date = Date.now();
-               let i;
-
-               for (i = props.length - 1; i >= 0; --i) {
-                       const prop = props[i];
-                       if (prop.charAt(0) === '$') {
-                               continue;
-                       }
-
-                       if (prop === 'options') {
-                               animations.push(...this._animateOptions(target, values));
-                               continue;
-                       }
-                       const value = values[prop];
-                       let animation = running[prop];
-                       const cfg = animatedProps.get(prop);
-
-                       if (animation) {
-                               if (cfg && animation.active()) {
-                                       // There is an existing active animation, let's update that
-                                       animation.update(cfg, value, date);
-                                       continue;
-                               } else {
-                                       animation.cancel();
-                               }
-                       }
-                       if (!cfg || !cfg.duration) {
-                               // not animated, set directly to new value
-                               target[prop] = value;
-                               continue;
-                       }
-
-                       running[prop] = animation = new Animation(cfg, target, prop, value);
-                       animations.push(animation);
-               }
-               return animations;
-       }
-
-
-       /**
+  _createAnimations(target, values) {
+    const animatedProps = this._properties;
+    const animations = [];
+    const running = target.$animations || (target.$animations = {});
+    const props = Object.keys(values);
+    const date = Date.now();
+    let i;
+
+    for (i = props.length - 1; i >= 0; --i) {
+      const prop = props[i];
+      if (prop.charAt(0) === '$') {
+        continue;
+      }
+
+      if (prop === 'options') {
+        animations.push(...this._animateOptions(target, values));
+        continue;
+      }
+      const value = values[prop];
+      let animation = running[prop];
+      const cfg = animatedProps.get(prop);
+
+      if (animation) {
+        if (cfg && animation.active()) {
+          // There is an existing active animation, let's update that
+          animation.update(cfg, value, date);
+          continue;
+        } else {
+          animation.cancel();
+        }
+      }
+      if (!cfg || !cfg.duration) {
+        // not animated, set directly to new value
+        target[prop] = value;
+        continue;
+      }
+
+      running[prop] = animation = new Animation(cfg, target, prop, value);
+      animations.push(animation);
+    }
+    return animations;
+  }
+
+
+  /**
         * Update `target` properties to new values, using configured animations
         * @param {object} target - object to update
         * @param {object} values - new target properties
         * @returns {boolean|undefined} - `true` if animations were started
         **/
-       update(target, values) {
-               if (this._properties.size === 0) {
-                       // Nothing is animated, just apply the new values.
-                       // Options can be shared, need to account for that.
-                       copyOptions(target, values);
-                       // copyOptions removes the `options` from `values`,
-                       // unless it can be directly assigned.
-                       Object.assign(target, values);
-                       return;
-               }
-
-               const animations = this._createAnimations(target, values);
-
-               if (animations.length) {
-                       animator.add(this._chart, animations);
-                       return true;
-               }
-       }
+  update(target, values) {
+    if (this._properties.size === 0) {
+      // Nothing is animated, just apply the new values.
+      // Options can be shared, need to account for that.
+      copyOptions(target, values);
+      // copyOptions removes the `options` from `values`,
+      // unless it can be directly assigned.
+      Object.assign(target, values);
+      return;
+    }
+
+    const animations = this._createAnimations(target, values);
+
+    if (animations.length) {
+      animator.add(this._chart, animations);
+      return true;
+    }
+  }
 }
 
 function awaitAll(animations, properties) {
-       const running = [];
-       const keys = Object.keys(properties);
-       for (let i = 0; i < keys.length; i++) {
-               const anim = animations[keys[i]];
-               if (anim && anim.active()) {
-                       running.push(anim.wait());
-               }
-       }
-       // @ts-ignore
-       return Promise.all(running);
+  const running = [];
+  const keys = Object.keys(properties);
+  for (let i = 0; i < keys.length; i++) {
+    const anim = animations[keys[i]];
+    if (anim && anim.active()) {
+      running.push(anim.wait());
+    }
+  }
+  // @ts-ignore
+  return Promise.all(running);
 }
 
 function resolveTargetOptions(target, newOptions) {
-       if (!newOptions) {
-               return;
-       }
-       let options = target.options;
-       if (!options) {
-               target.options = newOptions;
-               return;
-       }
-       if (options.$shared && !newOptions.$shared) {
-               // Going from shared options to distinct one:
-               // Create new options object containing the old shared values and start updating that.
-               target.options = options = Object.assign({}, options, {$shared: false, $animations: {}});
-       }
-       return options;
+  if (!newOptions) {
+    return;
+  }
+  let options = target.options;
+  if (!options) {
+    target.options = newOptions;
+    return;
+  }
+  if (options.$shared && !newOptions.$shared) {
+    // Going from shared options to distinct one:
+    // Create new options object containing the old shared values and start updating that.
+    target.options = options = Object.assign({}, options, {$shared: false, $animations: {}});
+  }
+  return options;
 }
index 64771ff5f245df00ea41404bd051f023e36a3a13..1d78e34aca94502b92d8e30b06e94c5b6a1f35ff 100644 (file)
@@ -6,17 +6,17 @@ import {requestAnimFrame} from '../helpers/helpers.extras';
  */
 
 function drawFPS(chart, count, date, lastDate) {
-       const fps = (1000 / (date - lastDate)) | 0;
-       const ctx = chart.ctx;
-       ctx.save();
-       ctx.clearRect(0, 0, 50, 24);
-       ctx.fillStyle = 'black';
-       ctx.textAlign = 'right';
-       if (count) {
-               ctx.fillText(count, 50, 8);
-               ctx.fillText(fps + ' fps', 50, 18);
-       }
-       ctx.restore();
+  const fps = (1000 / (date - lastDate)) | 0;
+  const ctx = chart.ctx;
+  ctx.save();
+  ctx.clearRect(0, 0, 50, 24);
+  ctx.fillStyle = 'black';
+  ctx.textAlign = 'right';
+  if (count) {
+    ctx.fillText(count, 50, 8);
+    ctx.fillText(fps + ' fps', 50, 18);
+  }
+  ctx.restore();
 }
 
 /**
@@ -24,204 +24,204 @@ function drawFPS(chart, count, date, lastDate) {
  * Note: class is export for typedoc
  */
 export class Animator {
-       constructor() {
-               this._request = null;
-               this._charts = new Map();
-               this._running = false;
-               this._lastDate = undefined;
-       }
-
-       /**
+  constructor() {
+    this._request = null;
+    this._charts = new Map();
+    this._running = false;
+    this._lastDate = undefined;
+  }
+
+  /**
         * @private
         */
-       _notify(chart, anims, date, type) {
-               const callbacks = anims.listeners[type] || [];
-               const numSteps = anims.duration;
-
-               callbacks.forEach(fn => fn({
-                       chart,
-                       numSteps,
-                       currentStep: Math.min(date - anims.start, numSteps)
-               }));
-       }
-
-       /**
+  _notify(chart, anims, date, type) {
+    const callbacks = anims.listeners[type] || [];
+    const numSteps = anims.duration;
+
+    callbacks.forEach(fn => fn({
+      chart,
+      numSteps,
+      currentStep: Math.min(date - anims.start, numSteps)
+    }));
+  }
+
+  /**
         * @private
         */
-       _refresh() {
-               const me = this;
+  _refresh() {
+    const me = this;
 
-               if (me._request) {
-                       return;
-               }
-               me._running = true;
+    if (me._request) {
+      return;
+    }
+    me._running = true;
 
-               me._request = requestAnimFrame.call(window, () => {
-                       me._update();
-                       me._request = null;
+    me._request = requestAnimFrame.call(window, () => {
+      me._update();
+      me._request = null;
 
-                       if (me._running) {
-                               me._refresh();
-                       }
-               });
-       }
+      if (me._running) {
+        me._refresh();
+      }
+    });
+  }
 
-       /**
+  /**
         * @private
         */
-       _update() {
-               const me = this;
-               const date = Date.now();
-               let remaining = 0;
-
-               me._charts.forEach((anims, chart) => {
-                       if (!anims.running || !anims.items.length) {
-                               return;
-                       }
-                       const items = anims.items;
-                       let i = items.length - 1;
-                       let draw = false;
-                       let item;
-
-                       for (; i >= 0; --i) {
-                               item = items[i];
-
-                               if (item._active) {
-                                       item.tick(date);
-                                       draw = true;
-                               } else {
-                                       // Remove the item by replacing it with last item and removing the last
-                                       // A lot faster than splice.
-                                       items[i] = items[items.length - 1];
-                                       items.pop();
-                               }
-                       }
-
-                       if (draw) {
-                               chart.draw();
-                               me._notify(chart, anims, date, 'progress');
-                       }
-
-                       if (chart.options.animation.debug) {
-                               drawFPS(chart, items.length, date, me._lastDate);
-                       }
-
-                       if (!items.length) {
-                               anims.running = false;
-                               me._notify(chart, anims, date, 'complete');
-                       }
-
-                       remaining += items.length;
-               });
-
-               me._lastDate = date;
-
-               if (remaining === 0) {
-                       me._running = false;
-               }
-       }
-
-       /**
+  _update() {
+    const me = this;
+    const date = Date.now();
+    let remaining = 0;
+
+    me._charts.forEach((anims, chart) => {
+      if (!anims.running || !anims.items.length) {
+        return;
+      }
+      const items = anims.items;
+      let i = items.length - 1;
+      let draw = false;
+      let item;
+
+      for (; i >= 0; --i) {
+        item = items[i];
+
+        if (item._active) {
+          item.tick(date);
+          draw = true;
+        } else {
+          // Remove the item by replacing it with last item and removing the last
+          // A lot faster than splice.
+          items[i] = items[items.length - 1];
+          items.pop();
+        }
+      }
+
+      if (draw) {
+        chart.draw();
+        me._notify(chart, anims, date, 'progress');
+      }
+
+      if (chart.options.animation.debug) {
+        drawFPS(chart, items.length, date, me._lastDate);
+      }
+
+      if (!items.length) {
+        anims.running = false;
+        me._notify(chart, anims, date, 'complete');
+      }
+
+      remaining += items.length;
+    });
+
+    me._lastDate = date;
+
+    if (remaining === 0) {
+      me._running = false;
+    }
+  }
+
+  /**
         * @private
         */
-       _getAnims(chart) {
-               const charts = this._charts;
-               let anims = charts.get(chart);
-               if (!anims) {
-                       anims = {
-                               running: false,
-                               items: [],
-                               listeners: {
-                                       complete: [],
-                                       progress: []
-                               }
-                       };
-                       charts.set(chart, anims);
-               }
-               return anims;
-       }
-
-       /**
+  _getAnims(chart) {
+    const charts = this._charts;
+    let anims = charts.get(chart);
+    if (!anims) {
+      anims = {
+        running: false,
+        items: [],
+        listeners: {
+          complete: [],
+          progress: []
+        }
+      };
+      charts.set(chart, anims);
+    }
+    return anims;
+  }
+
+  /**
         * @param {Chart} chart
         * @param {string} event - event name
         * @param {Function} cb - callback
         */
-       listen(chart, event, cb) {
-               this._getAnims(chart).listeners[event].push(cb);
-       }
+  listen(chart, event, cb) {
+    this._getAnims(chart).listeners[event].push(cb);
+  }
 
-       /**
+  /**
         * Add animations
         * @param {Chart} chart
         * @param {Animation[]} items - animations
         */
-       add(chart, items) {
-               if (!items || !items.length) {
-                       return;
-               }
-               this._getAnims(chart).items.push(...items);
-       }
-
-       /**
+  add(chart, items) {
+    if (!items || !items.length) {
+      return;
+    }
+    this._getAnims(chart).items.push(...items);
+  }
+
+  /**
         * Counts number of active animations for the chart
         * @param {Chart} chart
         */
-       has(chart) {
-               return this._getAnims(chart).items.length > 0;
-       }
+  has(chart) {
+    return this._getAnims(chart).items.length > 0;
+  }
 
-       /**
+  /**
         * Start animating (all charts)
         * @param {Chart} chart
         */
-       start(chart) {
-               const anims = this._charts.get(chart);
-               if (!anims) {
-                       return;
-               }
-               anims.running = true;
-               anims.start = Date.now();
-               anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);
-               this._refresh();
-       }
-
-       running(chart) {
-               if (!this._running) {
-                       return false;
-               }
-               const anims = this._charts.get(chart);
-               if (!anims || !anims.running || !anims.items.length) {
-                       return false;
-               }
-               return true;
-       }
-
-       /**
+  start(chart) {
+    const anims = this._charts.get(chart);
+    if (!anims) {
+      return;
+    }
+    anims.running = true;
+    anims.start = Date.now();
+    anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);
+    this._refresh();
+  }
+
+  running(chart) {
+    if (!this._running) {
+      return false;
+    }
+    const anims = this._charts.get(chart);
+    if (!anims || !anims.running || !anims.items.length) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
         * Stop all animations for the chart
         * @param {Chart} chart
         */
-       stop(chart) {
-               const anims = this._charts.get(chart);
-               if (!anims || !anims.items.length) {
-                       return;
-               }
-               const items = anims.items;
-               let i = items.length - 1;
-
-               for (; i >= 0; --i) {
-                       items[i].cancel();
-               }
-               anims.items = [];
-               this._notify(chart, anims, Date.now(), 'complete');
-       }
-
-       /**
+  stop(chart) {
+    const anims = this._charts.get(chart);
+    if (!anims || !anims.items.length) {
+      return;
+    }
+    const items = anims.items;
+    let i = items.length - 1;
+
+    for (; i >= 0; --i) {
+      items[i].cancel();
+    }
+    anims.items = [];
+    this._notify(chart, anims, Date.now(), 'complete');
+  }
+
+  /**
         * Remove chart from Animator
         * @param {Chart} chart
         */
-       remove(chart) {
-               return this._charts.delete(chart);
-       }
+  remove(chart) {
+    return this._charts.delete(chart);
+  }
 }
 
 // singleton instance
index 6772182ff0f966a3397f06e1d3b789e7f1b7b23d..06fcbbefff9847c273f78a108f59a686eafb1b40 100644 (file)
@@ -2,81 +2,81 @@ import defaults from './core.defaults';
 import {mergeIf, merge, _merger} from '../helpers/helpers.core';
 
 export function getIndexAxis(type, options) {
-       const typeDefaults = defaults.controllers[type] || {};
-       const datasetDefaults = typeDefaults.datasets || {};
-       const datasetOptions = options.datasets || {};
-       const typeOptions = datasetOptions[type] || {};
-       return typeOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
+  const typeDefaults = defaults.controllers[type] || {};
+  const datasetDefaults = typeDefaults.datasets || {};
+  const datasetOptions = options.datasets || {};
+  const typeOptions = datasetOptions[type] || {};
+  return typeOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
 }
 
 function getAxisFromDefaultScaleID(id, indexAxis) {
-       let axis = id;
-       if (id === '_index_') {
-               axis = indexAxis;
-       } else if (id === '_value_') {
-               axis = indexAxis === 'x' ? 'y' : 'x';
-       }
-       return axis;
+  let axis = id;
+  if (id === '_index_') {
+    axis = indexAxis;
+  } else if (id === '_value_') {
+    axis = indexAxis === 'x' ? 'y' : 'x';
+  }
+  return axis;
 }
 
 function getDefaultScaleIDFromAxis(axis, indexAxis) {
-       return axis === indexAxis ? '_index_' : '_value_';
+  return axis === indexAxis ? '_index_' : '_value_';
 }
 
 function axisFromPosition(position) {
-       if (position === 'top' || position === 'bottom') {
-               return 'x';
-       }
-       if (position === 'left' || position === 'right') {
-               return 'y';
-       }
+  if (position === 'top' || position === 'bottom') {
+    return 'x';
+  }
+  if (position === 'left' || position === 'right') {
+    return 'y';
+  }
 }
 
 export function determineAxis(id, scaleOptions) {
-       if (id === 'x' || id === 'y' || id === 'r') {
-               return id;
-       }
-       return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase();
+  if (id === 'x' || id === 'y' || id === 'r') {
+    return id;
+  }
+  return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase();
 }
 
 function mergeScaleConfig(config, options) {
-       const chartDefaults = defaults.controllers[config.type] || {scales: {}};
-       const configScales = options.scales || {};
-       const chartIndexAxis = getIndexAxis(config.type, options);
-       const firstIDs = Object.create(null);
-       const scales = Object.create(null);
-
-       // First figure out first scale id's per axis.
-       Object.keys(configScales).forEach(id => {
-               const scaleConf = configScales[id];
-               const axis = determineAxis(id, scaleConf);
-               const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
-               const defaultScaleOptions = chartDefaults.scales || {};
-               firstIDs[axis] = firstIDs[axis] || id;
-               scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]);
-       });
-
-       // Then merge dataset defaults to scale configs
-       config.data.datasets.forEach(dataset => {
-               const type = dataset.type || config.type;
-               const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
-               const datasetDefaults = defaults.controllers[type] || {};
-               const defaultScaleOptions = datasetDefaults.scales || {};
-               Object.keys(defaultScaleOptions).forEach(defaultID => {
-                       const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
-                       const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis;
-                       scales[id] = scales[id] || Object.create(null);
-                       mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]);
-               });
-       });
-
-       // apply scale defaults, if not overridden by dataset defaults
-       Object.keys(scales).forEach(key => {
-               const scale = scales[key];
-               mergeIf(scale, [defaults.scales[scale.type], defaults.scale]);
-       });
-
-       return scales;
+  const chartDefaults = defaults.controllers[config.type] || {scales: {}};
+  const configScales = options.scales || {};
+  const chartIndexAxis = getIndexAxis(config.type, options);
+  const firstIDs = Object.create(null);
+  const scales = Object.create(null);
+
+  // First figure out first scale id's per axis.
+  Object.keys(configScales).forEach(id => {
+    const scaleConf = configScales[id];
+    const axis = determineAxis(id, scaleConf);
+    const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
+    const defaultScaleOptions = chartDefaults.scales || {};
+    firstIDs[axis] = firstIDs[axis] || id;
+    scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]);
+  });
+
+  // Then merge dataset defaults to scale configs
+  config.data.datasets.forEach(dataset => {
+    const type = dataset.type || config.type;
+    const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
+    const datasetDefaults = defaults.controllers[type] || {};
+    const defaultScaleOptions = datasetDefaults.scales || {};
+    Object.keys(defaultScaleOptions).forEach(defaultID => {
+      const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
+      const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis;
+      scales[id] = scales[id] || Object.create(null);
+      mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]);
+    });
+  });
+
+  // apply scale defaults, if not overridden by dataset defaults
+  Object.keys(scales).forEach(key => {
+    const scale = scales[key];
+    mergeIf(scale, [defaults.scales[scale.type], defaults.scale]);
+  });
+
+  return scales;
 }
 
 /**
@@ -85,101 +85,101 @@ function mergeScaleConfig(config, options) {
  * a deep copy of the result, thus doesn't alter inputs.
  */
 function mergeConfig(...args/* config objects ... */) {
-       return merge(Object.create(null), args, {
-               merger(key, target, source, options) {
-                       if (key !== 'scales' && key !== 'scale' && key !== 'controllers') {
-                               _merger(key, target, source, options);
-                       }
-               }
-       });
+  return merge(Object.create(null), args, {
+    merger(key, target, source, options) {
+      if (key !== 'scales' && key !== 'scale' && key !== 'controllers') {
+        _merger(key, target, source, options);
+      }
+    }
+  });
 }
 
 function includePluginDefaults(options) {
-       options.plugins = options.plugins || {};
-       options.plugins.title = (options.plugins.title !== false) && merge(Object.create(null), [
-               defaults.plugins.title,
-               options.plugins.title
-       ]);
-
-       options.plugins.tooltip = (options.plugins.tooltip !== false) && merge(Object.create(null), [
-               defaults.interaction,
-               defaults.plugins.tooltip,
-               options.interaction,
-               options.plugins.tooltip
-       ]);
+  options.plugins = options.plugins || {};
+  options.plugins.title = (options.plugins.title !== false) && merge(Object.create(null), [
+    defaults.plugins.title,
+    options.plugins.title
+  ]);
+
+  options.plugins.tooltip = (options.plugins.tooltip !== false) && merge(Object.create(null), [
+    defaults.interaction,
+    defaults.plugins.tooltip,
+    options.interaction,
+    options.plugins.tooltip
+  ]);
 }
 
 function includeDefaults(config, options) {
-       options = options || {};
+  options = options || {};
 
-       const scaleConfig = mergeScaleConfig(config, options);
-       const hoverEanbled = options.interaction !== false && options.hover !== false;
+  const scaleConfig = mergeScaleConfig(config, options);
+  const hoverEanbled = options.interaction !== false && options.hover !== false;
 
-       options = mergeConfig(
-               defaults,
-               defaults.controllers[config.type],
-               options);
+  options = mergeConfig(
+    defaults,
+    defaults.controllers[config.type],
+    options);
 
-       options.hover = hoverEanbled && merge(Object.create(null), [
-               defaults.interaction,
-               defaults.hover,
-               options.interaction,
-               options.hover
-       ]);
+  options.hover = hoverEanbled && merge(Object.create(null), [
+    defaults.interaction,
+    defaults.hover,
+    options.interaction,
+    options.hover
+  ]);
 
-       options.scales = scaleConfig;
+  options.scales = scaleConfig;
 
-       if (options.plugins !== false) {
-               includePluginDefaults(options);
-       }
-       return options;
+  if (options.plugins !== false) {
+    includePluginDefaults(options);
+  }
+  return options;
 }
 
 function initConfig(config) {
-       config = config || {};
+  config = config || {};
 
-       // Do NOT use mergeConfig for the data object because this method merges arrays
-       // and so would change references to labels and datasets, preventing data updates.
-       const data = config.data = config.data || {datasets: [], labels: []};
-       data.datasets = data.datasets || [];
-       data.labels = data.labels || [];
+  // Do NOT use mergeConfig for the data object because this method merges arrays
+  // and so would change references to labels and datasets, preventing data updates.
+  const data = config.data = config.data || {datasets: [], labels: []};
+  data.datasets = data.datasets || [];
+  data.labels = data.labels || [];
 
-       config.options = includeDefaults(config, config.options);
+  config.options = includeDefaults(config, config.options);
 
-       return config;
+  return config;
 }
 
 export default class Config {
-       constructor(config) {
-               this._config = initConfig(config);
-       }
-
-       get type() {
-               return this._config.type;
-       }
-
-       set type(type) {
-               this._config.type = type;
-       }
-
-       get data() {
-               return this._config.data;
-       }
-
-       set data(data) {
-               this._config.data = data;
-       }
-
-       get options() {
-               return this._config.options;
-       }
-
-       get plugins() {
-               return this._config.plugins;
-       }
-
-       update(options) {
-               const config = this._config;
-               config.options = includeDefaults(config, options);
-       }
+  constructor(config) {
+    this._config = initConfig(config);
+  }
+
+  get type() {
+    return this._config.type;
+  }
+
+  set type(type) {
+    this._config.type = type;
+  }
+
+  get data() {
+    return this._config.data;
+  }
+
+  set data(data) {
+    this._config.data = data;
+  }
+
+  get options() {
+    return this._config.options;
+  }
+
+  get plugins() {
+    return this._config.plugins;
+  }
+
+  update(options) {
+    const config = this._config;
+    config.options = includeDefaults(config, options);
+  }
 }
index 8d257f9c3182753c08c2425e795629a3646403da..cf0b75867e24b7299310d5a9e269df2197615ead 100644 (file)
@@ -18,33 +18,33 @@ import {version} from '../../package.json';
 
 const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea'];
 function positionIsHorizontal(position, axis) {
-       return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x');
+  return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x');
 }
 
 function compare2Level(l1, l2) {
-       return function(a, b) {
-               return a[l1] === b[l1]
-                       ? a[l2] - b[l2]
-                       : a[l1] - b[l1];
-       };
+  return function(a, b) {
+    return a[l1] === b[l1]
+      ? a[l2] - b[l2]
+      : a[l1] - b[l1];
+  };
 }
 
 function onAnimationsComplete(context) {
-       const chart = context.chart;
-       const animationOptions = chart.options.animation;
+  const chart = context.chart;
+  const animationOptions = chart.options.animation;
 
-       chart.notifyPlugins('afterRender');
-       callCallback(animationOptions && animationOptions.onComplete, [context], chart);
+  chart.notifyPlugins('afterRender');
+  callCallback(animationOptions && animationOptions.onComplete, [context], chart);
 }
 
 function onAnimationProgress(context) {
-       const chart = context.chart;
-       const animationOptions = chart.options.animation;
-       callCallback(animationOptions && animationOptions.onProgress, [context], chart);
+  const chart = context.chart;
+  const animationOptions = chart.options.animation;
+  callCallback(animationOptions && animationOptions.onProgress, [context], chart);
 }
 
 function isDomSupported() {
-       return typeof window !== 'undefined' && typeof document !== 'undefined';
+  return typeof window !== 'undefined' && typeof document !== 'undefined';
 }
 
 /**
@@ -52,938 +52,938 @@ function isDomSupported() {
  * Attempt to unwrap the item passed into the chart constructor so that it is a canvas element (if possible).
  */
 function getCanvas(item) {
-       if (isDomSupported() && typeof item === 'string') {
-               item = document.getElementById(item);
-       } else if (item && item.length) {
-               // Support for array based queries (such as jQuery)
-               item = item[0];
-       }
-
-       if (item && item.canvas) {
-               // Support for any object associated to a canvas (including a context2d)
-               item = item.canvas;
-       }
-       return item;
+  if (isDomSupported() && typeof item === 'string') {
+    item = document.getElementById(item);
+  } else if (item && item.length) {
+    // Support for array based queries (such as jQuery)
+    item = item[0];
+  }
+
+  if (item && item.canvas) {
+    // Support for any object associated to a canvas (including a context2d)
+    item = item.canvas;
+  }
+  return item;
 }
 
 class Chart {
 
-       // eslint-disable-next-line max-statements
-       constructor(item, config) {
-               const me = this;
+  // eslint-disable-next-line max-statements
+  constructor(item, config) {
+    const me = this;
 
-               this.config = config = new Config(config);
-               const initialCanvas = getCanvas(item);
-               const existingChart = Chart.getChart(initialCanvas);
-               if (existingChart) {
-                       throw new Error(
-                               'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +
+    this.config = config = new Config(config);
+    const initialCanvas = getCanvas(item);
+    const existingChart = Chart.getChart(initialCanvas);
+    if (existingChart) {
+      throw new Error(
+        'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +
                                ' must be destroyed before the canvas can be reused.'
-                       );
-               }
-
-               this.platform = me._initializePlatform(initialCanvas, config);
-
-               const context = me.platform.acquireContext(initialCanvas, config);
-               const canvas = context && context.canvas;
-               const height = canvas && canvas.height;
-               const width = canvas && canvas.width;
-
-               this.id = uid();
-               this.ctx = context;
-               this.canvas = canvas;
-               this.width = width;
-               this.height = height;
-               this.aspectRatio = height ? width / height : null;
-               this.options = config.options;
-               this._layers = [];
-               this._metasets = [];
-               this.boxes = [];
-               this.currentDevicePixelRatio = undefined;
-               this.chartArea = undefined;
-               this._active = [];
-               this._lastEvent = undefined;
-               /** @type {{attach?: function, detach?: function, resize?: function}} */
-               this._listeners = {};
-               this._sortedMetasets = [];
-               this.scales = {};
-               this.scale = undefined;
-               this._plugins = new PluginService();
-               this.$proxies = {};
-               this._hiddenIndices = {};
-               this.attached = false;
-               this._animationsDisabled = undefined;
-               this.$context = undefined;
-
-               // Add the chart instance to the global namespace
-               Chart.instances[me.id] = me;
-
-               if (!context || !canvas) {
-                       // The given item is not a compatible context2d element, let's return before finalizing
-                       // the chart initialization but after setting basic chart / controller properties that
-                       // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
-                       // https://github.com/chartjs/Chart.js/issues/2807
-                       console.error("Failed to create chart: can't acquire context from the given item");
-                       return;
-               }
-
-               animator.listen(me, 'complete', onAnimationsComplete);
-               animator.listen(me, 'progress', onAnimationProgress);
-
-               me._initialize();
-               if (me.attached) {
-                       me.update();
-               }
-       }
-
-       get data() {
-               return this.config.data;
-       }
-
-       set data(data) {
-               this.config.data = data;
-       }
-
-       /**
+      );
+    }
+
+    this.platform = me._initializePlatform(initialCanvas, config);
+
+    const context = me.platform.acquireContext(initialCanvas, config);
+    const canvas = context && context.canvas;
+    const height = canvas && canvas.height;
+    const width = canvas && canvas.width;
+
+    this.id = uid();
+    this.ctx = context;
+    this.canvas = canvas;
+    this.width = width;
+    this.height = height;
+    this.aspectRatio = height ? width / height : null;
+    this.options = config.options;
+    this._layers = [];
+    this._metasets = [];
+    this.boxes = [];
+    this.currentDevicePixelRatio = undefined;
+    this.chartArea = undefined;
+    this._active = [];
+    this._lastEvent = undefined;
+    /** @type {{attach?: function, detach?: function, resize?: function}} */
+    this._listeners = {};
+    this._sortedMetasets = [];
+    this.scales = {};
+    this.scale = undefined;
+    this._plugins = new PluginService();
+    this.$proxies = {};
+    this._hiddenIndices = {};
+    this.attached = false;
+    this._animationsDisabled = undefined;
+    this.$context = undefined;
+
+    // Add the chart instance to the global namespace
+    Chart.instances[me.id] = me;
+
+    if (!context || !canvas) {
+      // The given item is not a compatible context2d element, let's return before finalizing
+      // the chart initialization but after setting basic chart / controller properties that
+      // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
+      // https://github.com/chartjs/Chart.js/issues/2807
+      console.error("Failed to create chart: can't acquire context from the given item");
+      return;
+    }
+
+    animator.listen(me, 'complete', onAnimationsComplete);
+    animator.listen(me, 'progress', onAnimationProgress);
+
+    me._initialize();
+    if (me.attached) {
+      me.update();
+    }
+  }
+
+  get data() {
+    return this.config.data;
+  }
+
+  set data(data) {
+    this.config.data = data;
+  }
+
+  /**
         * @private
         */
-       _initialize() {
-               const me = this;
+  _initialize() {
+    const me = this;
 
-               // Before init plugin notification
-               me.notifyPlugins('beforeInit');
+    // Before init plugin notification
+    me.notifyPlugins('beforeInit');
 
-               if (me.options.responsive) {
-                       me.resize();
-               } else {
-                       retinaScale(me, me.options.devicePixelRatio);
-               }
+    if (me.options.responsive) {
+      me.resize();
+    } else {
+      retinaScale(me, me.options.devicePixelRatio);
+    }
 
-               me.bindEvents();
+    me.bindEvents();
 
-               // After init plugin notification
-               me.notifyPlugins('afterInit');
+    // After init plugin notification
+    me.notifyPlugins('afterInit');
 
-               return me;
-       }
+    return me;
+  }
 
-       /**
+  /**
         * @private
         */
-       _initializePlatform(canvas, config) {
-               if (config.platform) {
-                       return new config.platform();
-               } else if (!isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) {
-                       return new BasicPlatform();
-               }
-               return new DomPlatform();
-       }
-
-       clear() {
-               clearCanvas(this.canvas, this.ctx);
-               return this;
-       }
-
-       stop() {
-               animator.stop(this);
-               return this;
-       }
-
-       /**
+  _initializePlatform(canvas, config) {
+    if (config.platform) {
+      return new config.platform();
+    } else if (!isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) {
+      return new BasicPlatform();
+    }
+    return new DomPlatform();
+  }
+
+  clear() {
+    clearCanvas(this.canvas, this.ctx);
+    return this;
+  }
+
+  stop() {
+    animator.stop(this);
+    return this;
+  }
+
+  /**
         * Resize the chart to its container or to explicit dimensions.
         * @param {number} [width]
         * @param {number} [height]
         */
-       resize(width, height) {
-               if (!animator.running(this)) {
-                       this._resize(width, height);
-               } else {
-                       this._resizeBeforeDraw = {width, height};
-               }
-       }
-
-       _resize(width, height) {
-               const me = this;
-               const options = me.options;
-               const canvas = me.canvas;
-               const aspectRatio = options.maintainAspectRatio && me.aspectRatio;
-               const newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio);
-
-               // detect devicePixelRation changes
-               const oldRatio = me.currentDevicePixelRatio;
-               const newRatio = options.devicePixelRatio || me.platform.getDevicePixelRatio();
-
-               if (me.width === newSize.width && me.height === newSize.height && oldRatio === newRatio) {
-                       return;
-               }
-
-               canvas.width = me.width = newSize.width;
-               canvas.height = me.height = newSize.height;
-               if (canvas.style) {
-                       canvas.style.width = newSize.width + 'px';
-                       canvas.style.height = newSize.height + 'px';
-               }
-
-               retinaScale(me, newRatio);
-
-               me.notifyPlugins('resize', {size: newSize});
-
-               callCallback(options.onResize, [newSize], me);
-
-               if (me.attached) {
-                       me.update('resize');
-               }
-       }
-
-       ensureScalesHaveIDs() {
-               const options = this.options;
-               const scalesOptions = options.scales || {};
-               const scaleOptions = options.scale;
-
-               each(scalesOptions, (axisOptions, axisID) => {
-                       axisOptions.id = axisID;
-               });
-
-               if (scaleOptions) {
-                       scaleOptions.id = scaleOptions.id || 'scale';
-               }
-       }
-
-       /**
+  resize(width, height) {
+    if (!animator.running(this)) {
+      this._resize(width, height);
+    } else {
+      this._resizeBeforeDraw = {width, height};
+    }
+  }
+
+  _resize(width, height) {
+    const me = this;
+    const options = me.options;
+    const canvas = me.canvas;
+    const aspectRatio = options.maintainAspectRatio && me.aspectRatio;
+    const newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio);
+
+    // detect devicePixelRation changes
+    const oldRatio = me.currentDevicePixelRatio;
+    const newRatio = options.devicePixelRatio || me.platform.getDevicePixelRatio();
+
+    if (me.width === newSize.width && me.height === newSize.height && oldRatio === newRatio) {
+      return;
+    }
+
+    canvas.width = me.width = newSize.width;
+    canvas.height = me.height = newSize.height;
+    if (canvas.style) {
+      canvas.style.width = newSize.width + 'px';
+      canvas.style.height = newSize.height + 'px';
+    }
+
+    retinaScale(me, newRatio);
+
+    me.notifyPlugins('resize', {size: newSize});
+
+    callCallback(options.onResize, [newSize], me);
+
+    if (me.attached) {
+      me.update('resize');
+    }
+  }
+
+  ensureScalesHaveIDs() {
+    const options = this.options;
+    const scalesOptions = options.scales || {};
+    const scaleOptions = options.scale;
+
+    each(scalesOptions, (axisOptions, axisID) => {
+      axisOptions.id = axisID;
+    });
+
+    if (scaleOptions) {
+      scaleOptions.id = scaleOptions.id || 'scale';
+    }
+  }
+
+  /**
         * Builds a map of scale ID to scale object for future lookup.
         */
-       buildOrUpdateScales() {
-               const me = this;
-               const options = me.options;
-               const scaleOpts = options.scales;
-               const scales = me.scales || {};
-               const updated = Object.keys(scales).reduce((obj, id) => {
-                       obj[id] = false;
-                       return obj;
-               }, {});
-               let items = [];
-
-               if (scaleOpts) {
-                       items = items.concat(
-                               Object.keys(scaleOpts).map((id) => {
-                                       const scaleOptions = scaleOpts[id];
-                                       const axis = determineAxis(id, scaleOptions);
-                                       const isRadial = axis === 'r';
-                                       const isHorizontal = axis === 'x';
-                                       return {
-                                               options: scaleOptions,
-                                               dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
-                                               dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
-                                       };
-                               })
-                       );
-               }
-
-               each(items, (item) => {
-                       const scaleOptions = item.options;
-                       const id = scaleOptions.id;
-                       const axis = determineAxis(id, scaleOptions);
-                       const scaleType = valueOrDefault(scaleOptions.type, item.dtype);
-
-                       if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
-                               scaleOptions.position = item.dposition;
-                       }
-
-                       updated[id] = true;
-                       let scale = null;
-                       if (id in scales && scales[id].type === scaleType) {
-                               scale = scales[id];
-                       } else {
-                               const scaleClass = registry.getScale(scaleType);
-                               scale = new scaleClass({
-                                       id,
-                                       type: scaleType,
-                                       ctx: me.ctx,
-                                       chart: me
-                               });
-                               scales[scale.id] = scale;
-                       }
-
-                       scale.init(scaleOptions, options);
-               });
-               // clear up discarded scales
-               each(updated, (hasUpdated, id) => {
-                       if (!hasUpdated) {
-                               delete scales[id];
-                       }
-               });
-
-               me.scales = scales;
-
-               each(scales, (scale) => {
-                       layouts.configure(me, scale, scale.options);
-                       layouts.addBox(me, scale);
-               });
-       }
-
-       /**
+  buildOrUpdateScales() {
+    const me = this;
+    const options = me.options;
+    const scaleOpts = options.scales;
+    const scales = me.scales || {};
+    const updated = Object.keys(scales).reduce((obj, id) => {
+      obj[id] = false;
+      return obj;
+    }, {});
+    let items = [];
+
+    if (scaleOpts) {
+      items = items.concat(
+        Object.keys(scaleOpts).map((id) => {
+          const scaleOptions = scaleOpts[id];
+          const axis = determineAxis(id, scaleOptions);
+          const isRadial = axis === 'r';
+          const isHorizontal = axis === 'x';
+          return {
+            options: scaleOptions,
+            dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
+            dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
+          };
+        })
+      );
+    }
+
+    each(items, (item) => {
+      const scaleOptions = item.options;
+      const id = scaleOptions.id;
+      const axis = determineAxis(id, scaleOptions);
+      const scaleType = valueOrDefault(scaleOptions.type, item.dtype);
+
+      if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
+        scaleOptions.position = item.dposition;
+      }
+
+      updated[id] = true;
+      let scale = null;
+      if (id in scales && scales[id].type === scaleType) {
+        scale = scales[id];
+      } else {
+        const scaleClass = registry.getScale(scaleType);
+        scale = new scaleClass({
+          id,
+          type: scaleType,
+          ctx: me.ctx,
+          chart: me
+        });
+        scales[scale.id] = scale;
+      }
+
+      scale.init(scaleOptions, options);
+    });
+    // clear up discarded scales
+    each(updated, (hasUpdated, id) => {
+      if (!hasUpdated) {
+        delete scales[id];
+      }
+    });
+
+    me.scales = scales;
+
+    each(scales, (scale) => {
+      layouts.configure(me, scale, scale.options);
+      layouts.addBox(me, scale);
+    });
+  }
+
+  /**
         * Updates the given metaset with the given dataset index. Ensures it's stored at that index
         * in the _metasets array by swapping with the metaset at that index if necessary.
         * @param {Object} meta - the dataset metadata
         * @param {number} index - the dataset index
         * @private
         */
-       _updateMetasetIndex(meta, index) {
-               const metasets = this._metasets;
-               const oldIndex = meta.index;
-               if (oldIndex !== index) {
-                       metasets[oldIndex] = metasets[index];
-                       metasets[index] = meta;
-                       meta.index = index;
-               }
-       }
-
-       /**
+  _updateMetasetIndex(meta, index) {
+    const metasets = this._metasets;
+    const oldIndex = meta.index;
+    if (oldIndex !== index) {
+      metasets[oldIndex] = metasets[index];
+      metasets[index] = meta;
+      meta.index = index;
+    }
+  }
+
+  /**
         * @private
         */
-       _updateMetasets() {
-               const me = this;
-               const metasets = me._metasets;
-               const numData = me.data.datasets.length;
-               const numMeta = metasets.length;
-
-               if (numMeta > numData) {
-                       for (let i = numData; i < numMeta; ++i) {
-                               me._destroyDatasetMeta(i);
-                       }
-                       metasets.splice(numData, numMeta - numData);
-               }
-               me._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
-       }
-
-       /**
+  _updateMetasets() {
+    const me = this;
+    const metasets = me._metasets;
+    const numData = me.data.datasets.length;
+    const numMeta = metasets.length;
+
+    if (numMeta > numData) {
+      for (let i = numData; i < numMeta; ++i) {
+        me._destroyDatasetMeta(i);
+      }
+      metasets.splice(numData, numMeta - numData);
+    }
+    me._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
+  }
+
+  /**
         * @private
         */
-       _removeUnreferencedMetasets() {
-               const me = this;
-               const datasets = me.data.datasets;
-               me._metasets.forEach((meta, index) => {
-                       if (datasets.filter(x => x === meta._dataset).length === 0) {
-                               me._destroyDatasetMeta(index);
-                       }
-               });
-       }
-
-       buildOrUpdateControllers() {
-               const me = this;
-               const newControllers = [];
-               const datasets = me.data.datasets;
-               let i, ilen;
-
-               me._removeUnreferencedMetasets();
-
-               for (i = 0, ilen = datasets.length; i < ilen; i++) {
-                       const dataset = datasets[i];
-                       let meta = me.getDatasetMeta(i);
-                       const type = dataset.type || me.config.type;
-
-                       if (meta.type && meta.type !== type) {
-                               me._destroyDatasetMeta(i);
-                               meta = me.getDatasetMeta(i);
-                       }
-                       meta.type = type;
-                       meta.indexAxis = dataset.indexAxis || getIndexAxis(type, me.options);
-                       meta.order = dataset.order || 0;
-                       me._updateMetasetIndex(meta, i);
-                       meta.label = '' + dataset.label;
-                       meta.visible = me.isDatasetVisible(i);
-
-                       if (meta.controller) {
-                               meta.controller.updateIndex(i);
-                               meta.controller.linkScales();
-                       } else {
-                               const controllerDefaults = defaults.controllers[type];
-                               const ControllerClass = registry.getController(type);
-                               Object.assign(ControllerClass.prototype, {
-                                       dataElementType: registry.getElement(controllerDefaults.dataElementType),
-                                       datasetElementType: controllerDefaults.datasetElementType && registry.getElement(controllerDefaults.datasetElementType),
-                                       dataElementOptions: controllerDefaults.dataElementOptions,
-                                       datasetElementOptions: controllerDefaults.datasetElementOptions
-                               });
-                               meta.controller = new ControllerClass(me, i);
-                               newControllers.push(meta.controller);
-                       }
-               }
-
-               me._updateMetasets();
-               return newControllers;
-       }
-
-       /**
+  _removeUnreferencedMetasets() {
+    const me = this;
+    const datasets = me.data.datasets;
+    me._metasets.forEach((meta, index) => {
+      if (datasets.filter(x => x === meta._dataset).length === 0) {
+        me._destroyDatasetMeta(index);
+      }
+    });
+  }
+
+  buildOrUpdateControllers() {
+    const me = this;
+    const newControllers = [];
+    const datasets = me.data.datasets;
+    let i, ilen;
+
+    me._removeUnreferencedMetasets();
+
+    for (i = 0, ilen = datasets.length; i < ilen; i++) {
+      const dataset = datasets[i];
+      let meta = me.getDatasetMeta(i);
+      const type = dataset.type || me.config.type;
+
+      if (meta.type && meta.type !== type) {
+        me._destroyDatasetMeta(i);
+        meta = me.getDatasetMeta(i);
+      }
+      meta.type = type;
+      meta.indexAxis = dataset.indexAxis || getIndexAxis(type, me.options);
+      meta.order = dataset.order || 0;
+      me._updateMetasetIndex(meta, i);
+      meta.label = '' + dataset.label;
+      meta.visible = me.isDatasetVisible(i);
+
+      if (meta.controller) {
+        meta.controller.updateIndex(i);
+        meta.controller.linkScales();
+      } else {
+        const controllerDefaults = defaults.controllers[type];
+        const ControllerClass = registry.getController(type);
+        Object.assign(ControllerClass.prototype, {
+          dataElementType: registry.getElement(controllerDefaults.dataElementType),
+          datasetElementType: controllerDefaults.datasetElementType && registry.getElement(controllerDefaults.datasetElementType),
+          dataElementOptions: controllerDefaults.dataElementOptions,
+          datasetElementOptions: controllerDefaults.datasetElementOptions
+        });
+        meta.controller = new ControllerClass(me, i);
+        newControllers.push(meta.controller);
+      }
+    }
+
+    me._updateMetasets();
+    return newControllers;
+  }
+
+  /**
         * Reset the elements of all datasets
         * @private
         */
-       _resetElements() {
-               const me = this;
-               each(me.data.datasets, (dataset, datasetIndex) => {
-                       me.getDatasetMeta(datasetIndex).controller.reset();
-               }, me);
-       }
-
-       /**
+  _resetElements() {
+    const me = this;
+    each(me.data.datasets, (dataset, datasetIndex) => {
+      me.getDatasetMeta(datasetIndex).controller.reset();
+    }, me);
+  }
+
+  /**
        * Resets the chart back to its state before the initial animation
        */
-       reset() {
-               this._resetElements();
-               this.notifyPlugins('reset');
-       }
+  reset() {
+    this._resetElements();
+    this.notifyPlugins('reset');
+  }
 
-       update(mode) {
-               const me = this;
-               let i, ilen;
+  update(mode) {
+    const me = this;
+    let i, ilen;
 
-               each(me.scales, (scale) => {
-                       layouts.removeBox(me, scale);
-               });
+    each(me.scales, (scale) => {
+      layouts.removeBox(me, scale);
+    });
 
-               me.config.update(me.options);
-               me.options = me.config.options;
-               const animsDisabled = me._animationsDisabled = !me.options.animation;
+    me.config.update(me.options);
+    me.options = me.config.options;
+    const animsDisabled = me._animationsDisabled = !me.options.animation;
 
-               me.ensureScalesHaveIDs();
-               me.buildOrUpdateScales();
+    me.ensureScalesHaveIDs();
+    me.buildOrUpdateScales();
 
-               // plugins options references might have change, let's invalidate the cache
-               // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
-               me._plugins.invalidate();
+    // plugins options references might have change, let's invalidate the cache
+    // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+    me._plugins.invalidate();
 
-               if (me.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) {
-                       return;
-               }
+    if (me.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) {
+      return;
+    }
 
-               // Make sure dataset controllers are updated and new controllers are reset
-               const newControllers = me.buildOrUpdateControllers();
+    // Make sure dataset controllers are updated and new controllers are reset
+    const newControllers = me.buildOrUpdateControllers();
 
-               me.notifyPlugins('beforeElementsUpdate');
+    me.notifyPlugins('beforeElementsUpdate');
 
-               // Make sure all dataset controllers have correct meta data counts
-               for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {
-                       const {controller} = me.getDatasetMeta(i);
-                       const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
-                       // New controllers will be reset after the layout pass, so we only want to modify
-                       // elements added to new datasets
-                       controller.buildOrUpdateElements(reset);
-               }
+    // Make sure all dataset controllers have correct meta data counts
+    for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {
+      const {controller} = me.getDatasetMeta(i);
+      const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
+      // New controllers will be reset after the layout pass, so we only want to modify
+      // elements added to new datasets
+      controller.buildOrUpdateElements(reset);
+    }
 
-               me._updateLayout();
+    me._updateLayout();
 
-               // Only reset the controllers if we have animations
-               if (!animsDisabled) {
-                       // Can only reset the new controllers after the scales have been updated
-                       // Reset is done to get the starting point for the initial animation
-                       each(newControllers, (controller) => {
-                               controller.reset();
-                       });
-               }
+    // Only reset the controllers if we have animations
+    if (!animsDisabled) {
+      // Can only reset the new controllers after the scales have been updated
+      // Reset is done to get the starting point for the initial animation
+      each(newControllers, (controller) => {
+        controller.reset();
+      });
+    }
 
-               me._updateDatasets(mode);
+    me._updateDatasets(mode);
 
-               // Do this before render so that any plugins that need final scale updates can use it
-               me.notifyPlugins('afterUpdate', {mode});
+    // Do this before render so that any plugins that need final scale updates can use it
+    me.notifyPlugins('afterUpdate', {mode});
 
-               me._layers.sort(compare2Level('z', '_idx'));
+    me._layers.sort(compare2Level('z', '_idx'));
 
-               // Replay last event from before update
-               if (me._lastEvent) {
-                       me._eventHandler(me._lastEvent, true);
-               }
+    // Replay last event from before update
+    if (me._lastEvent) {
+      me._eventHandler(me._lastEvent, true);
+    }
 
-               me.render();
-       }
+    me.render();
+  }
 
-       /**
+  /**
         * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
         * hook, in which case, plugins will not be called on `afterLayout`.
         * @private
         */
-       _updateLayout() {
-               const me = this;
+  _updateLayout() {
+    const me = this;
 
-               if (me.notifyPlugins('beforeLayout', {cancelable: true}) === false) {
-                       return;
-               }
+    if (me.notifyPlugins('beforeLayout', {cancelable: true}) === false) {
+      return;
+    }
 
-               layouts.update(me, me.width, me.height);
+    layouts.update(me, me.width, me.height);
 
-               const area = me.chartArea;
-               const noArea = area.width <= 0 || area.height <= 0;
+    const area = me.chartArea;
+    const noArea = area.width <= 0 || area.height <= 0;
 
-               me._layers = [];
-               each(me.boxes, (box) => {
-                       if (noArea && box.position === 'chartArea') {
-                               // Skip drawing and configuring chartArea boxes when chartArea is zero or negative
-                               return;
-                       }
+    me._layers = [];
+    each(me.boxes, (box) => {
+      if (noArea && box.position === 'chartArea') {
+        // Skip drawing and configuring chartArea boxes when chartArea is zero or negative
+        return;
+      }
 
-                       // configure is called twice, once in core.scale.update and once here.
-                       // Here the boxes are fully updated and at their final positions.
-                       if (box.configure) {
-                               box.configure();
-                       }
-                       me._layers.push(...box._layers());
-               }, me);
+      // configure is called twice, once in core.scale.update and once here.
+      // Here the boxes are fully updated and at their final positions.
+      if (box.configure) {
+        box.configure();
+      }
+      me._layers.push(...box._layers());
+    }, me);
 
-               me._layers.forEach((item, index) => {
-                       item._idx = index;
-               });
+    me._layers.forEach((item, index) => {
+      item._idx = index;
+    });
 
-               me.notifyPlugins('afterLayout');
-       }
+    me.notifyPlugins('afterLayout');
+  }
 
-       /**
+  /**
         * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
         * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
         * @private
         */
-       _updateDatasets(mode) {
-               const me = this;
-               const isFunction = typeof mode === 'function';
+  _updateDatasets(mode) {
+    const me = this;
+    const isFunction = typeof mode === 'function';
 
-               if (me.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) {
-                       return;
-               }
+    if (me.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) {
+      return;
+    }
 
-               for (let i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
-                       me._updateDataset(i, isFunction ? mode({datasetIndex: i}) : mode);
-               }
+    for (let i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+      me._updateDataset(i, isFunction ? mode({datasetIndex: i}) : mode);
+    }
 
-               me.notifyPlugins('afterDatasetsUpdate', {mode});
-       }
+    me.notifyPlugins('afterDatasetsUpdate', {mode});
+  }
 
-       /**
+  /**
         * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
         * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
         * @private
         */
-       _updateDataset(index, mode) {
-               const me = this;
-               const meta = me.getDatasetMeta(index);
-               const args = {meta, index, mode, cancelable: true};
-
-               if (me.notifyPlugins('beforeDatasetUpdate', args) === false) {
-                       return;
-               }
-
-               meta.controller._update(mode);
-
-               args.cancelable = false;
-               me.notifyPlugins('afterDatasetUpdate', args);
-       }
-
-       render() {
-               const me = this;
-               if (me.notifyPlugins('beforeRender', {cancelable: true}) === false) {
-                       return;
-               }
-
-               if (animator.has(me)) {
-                       if (me.attached && !animator.running(me)) {
-                               animator.start(me);
-                       }
-               } else {
-                       me.draw();
-                       onAnimationsComplete({chart: me});
-               }
-       }
-
-       draw() {
-               const me = this;
-               let i;
-               if (me._resizeBeforeDraw) {
-                       const {width, height} = me._resizeBeforeDraw;
-                       me._resize(width, height);
-                       me._resizeBeforeDraw = null;
-               }
-               me.clear();
-
-               if (me.width <= 0 || me.height <= 0) {
-                       return;
-               }
-
-               if (me.notifyPlugins('beforeDraw', {cancelable: true}) === false) {
-                       return;
-               }
-
-               // Because of plugin hooks (before/afterDatasetsDraw), datasets can't
-               // currently be part of layers. Instead, we draw
-               // layers <= 0 before(default, backward compat), and the rest after
-               const layers = me._layers;
-               for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
-                       layers[i].draw(me.chartArea);
-               }
-
-               me._drawDatasets();
-
-               // Rest of layers
-               for (; i < layers.length; ++i) {
-                       layers[i].draw(me.chartArea);
-               }
-
-               me.notifyPlugins('afterDraw');
-       }
-
-       /**
+  _updateDataset(index, mode) {
+    const me = this;
+    const meta = me.getDatasetMeta(index);
+    const args = {meta, index, mode, cancelable: true};
+
+    if (me.notifyPlugins('beforeDatasetUpdate', args) === false) {
+      return;
+    }
+
+    meta.controller._update(mode);
+
+    args.cancelable = false;
+    me.notifyPlugins('afterDatasetUpdate', args);
+  }
+
+  render() {
+    const me = this;
+    if (me.notifyPlugins('beforeRender', {cancelable: true}) === false) {
+      return;
+    }
+
+    if (animator.has(me)) {
+      if (me.attached && !animator.running(me)) {
+        animator.start(me);
+      }
+    } else {
+      me.draw();
+      onAnimationsComplete({chart: me});
+    }
+  }
+
+  draw() {
+    const me = this;
+    let i;
+    if (me._resizeBeforeDraw) {
+      const {width, height} = me._resizeBeforeDraw;
+      me._resize(width, height);
+      me._resizeBeforeDraw = null;
+    }
+    me.clear();
+
+    if (me.width <= 0 || me.height <= 0) {
+      return;
+    }
+
+    if (me.notifyPlugins('beforeDraw', {cancelable: true}) === false) {
+      return;
+    }
+
+    // Because of plugin hooks (before/afterDatasetsDraw), datasets can't
+    // currently be part of layers. Instead, we draw
+    // layers <= 0 before(default, backward compat), and the rest after
+    const layers = me._layers;
+    for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
+      layers[i].draw(me.chartArea);
+    }
+
+    me._drawDatasets();
+
+    // Rest of layers
+    for (; i < layers.length; ++i) {
+      layers[i].draw(me.chartArea);
+    }
+
+    me.notifyPlugins('afterDraw');
+  }
+
+  /**
         * @private
         */
-       _getSortedDatasetMetas(filterVisible) {
-               const me = this;
-               const metasets = me._sortedMetasets;
-               const result = [];
-               let i, ilen;
-
-               for (i = 0, ilen = metasets.length; i < ilen; ++i) {
-                       const meta = metasets[i];
-                       if (!filterVisible || meta.visible) {
-                               result.push(meta);
-                       }
-               }
-
-               return result;
-       }
-
-       /**
+  _getSortedDatasetMetas(filterVisible) {
+    const me = this;
+    const metasets = me._sortedMetasets;
+    const result = [];
+    let i, ilen;
+
+    for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+      const meta = metasets[i];
+      if (!filterVisible || meta.visible) {
+        result.push(meta);
+      }
+    }
+
+    return result;
+  }
+
+  /**
         * Gets the visible dataset metas in drawing order
         * @return {object[]}
         */
-       getSortedVisibleDatasetMetas() {
-               return this._getSortedDatasetMetas(true);
-       }
+  getSortedVisibleDatasetMetas() {
+    return this._getSortedDatasetMetas(true);
+  }
 
-       /**
+  /**
         * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
         * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
         * @private
         */
-       _drawDatasets() {
-               const me = this;
+  _drawDatasets() {
+    const me = this;
 
-               if (me.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) {
-                       return;
-               }
+    if (me.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) {
+      return;
+    }
 
-               const metasets = me.getSortedVisibleDatasetMetas();
-               for (let i = metasets.length - 1; i >= 0; --i) {
-                       me._drawDataset(metasets[i]);
-               }
+    const metasets = me.getSortedVisibleDatasetMetas();
+    for (let i = metasets.length - 1; i >= 0; --i) {
+      me._drawDataset(metasets[i]);
+    }
 
-               me.notifyPlugins('afterDatasetsDraw');
-       }
+    me.notifyPlugins('afterDatasetsDraw');
+  }
 
-       /**
+  /**
         * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
         * hook, in which case, plugins will not be called on `afterDatasetDraw`.
         * @private
         */
-       _drawDataset(meta) {
-               const me = this;
-               const ctx = me.ctx;
-               const clip = meta._clip;
-               const area = me.chartArea;
-               const args = {
-                       meta,
-                       index: meta.index,
-                       cancelable: true
-               };
-
-               if (me.notifyPlugins('beforeDatasetDraw', args) === false) {
-                       return;
-               }
-
-               clipArea(ctx, {
-                       left: clip.left === false ? 0 : area.left - clip.left,
-                       right: clip.right === false ? me.width : area.right + clip.right,
-                       top: clip.top === false ? 0 : area.top - clip.top,
-                       bottom: clip.bottom === false ? me.height : area.bottom + clip.bottom
-               });
-
-               meta.controller.draw();
-
-               unclipArea(ctx);
-
-               args.cancelable = false;
-               me.notifyPlugins('afterDatasetDraw', args);
-       }
-
-       getElementsAtEventForMode(e, mode, options, useFinalPosition) {
-               const method = Interaction.modes[mode];
-               if (typeof method === 'function') {
-                       return method(this, e, options, useFinalPosition);
-               }
-
-               return [];
-       }
-
-       getDatasetMeta(datasetIndex) {
-               const me = this;
-               const dataset = me.data.datasets[datasetIndex];
-               const metasets = me._metasets;
-               let meta = metasets.filter(x => x && x._dataset === dataset).pop();
-
-               if (!meta) {
-                       meta = metasets[datasetIndex] = {
-                               type: null,
-                               data: [],
-                               dataset: null,
-                               controller: null,
-                               hidden: null,                   // See isDatasetVisible() comment
-                               xAxisID: null,
-                               yAxisID: null,
-                               order: dataset && dataset.order || 0,
-                               index: datasetIndex,
-                               _dataset: dataset,
-                               _parsed: [],
-                               _sorted: false
-                       };
-               }
-
-               return meta;
-       }
-
-       getContext() {
-               return this.$context || (this.$context = Object.create(null, {
-                       chart: {
-                               value: this
-                       },
-                       type: {
-                               value: 'chart'
-                       }
-               }));
-       }
-
-       getVisibleDatasetCount() {
-               return this.getSortedVisibleDatasetMetas().length;
-       }
-
-       isDatasetVisible(datasetIndex) {
-               const dataset = this.data.datasets[datasetIndex];
-               if (!dataset) {
-                       return false;
-               }
-
-               const meta = this.getDatasetMeta(datasetIndex);
-
-               // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
-               // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
-               return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
-       }
-
-       setDatasetVisibility(datasetIndex, visible) {
-               const meta = this.getDatasetMeta(datasetIndex);
-               meta.hidden = !visible;
-       }
-
-       toggleDataVisibility(index) {
-               this._hiddenIndices[index] = !this._hiddenIndices[index];
-       }
-
-       getDataVisibility(index) {
-               return !this._hiddenIndices[index];
-       }
-
-       /**
+  _drawDataset(meta) {
+    const me = this;
+    const ctx = me.ctx;
+    const clip = meta._clip;
+    const area = me.chartArea;
+    const args = {
+      meta,
+      index: meta.index,
+      cancelable: true
+    };
+
+    if (me.notifyPlugins('beforeDatasetDraw', args) === false) {
+      return;
+    }
+
+    clipArea(ctx, {
+      left: clip.left === false ? 0 : area.left - clip.left,
+      right: clip.right === false ? me.width : area.right + clip.right,
+      top: clip.top === false ? 0 : area.top - clip.top,
+      bottom: clip.bottom === false ? me.height : area.bottom + clip.bottom
+    });
+
+    meta.controller.draw();
+
+    unclipArea(ctx);
+
+    args.cancelable = false;
+    me.notifyPlugins('afterDatasetDraw', args);
+  }
+
+  getElementsAtEventForMode(e, mode, options, useFinalPosition) {
+    const method = Interaction.modes[mode];
+    if (typeof method === 'function') {
+      return method(this, e, options, useFinalPosition);
+    }
+
+    return [];
+  }
+
+  getDatasetMeta(datasetIndex) {
+    const me = this;
+    const dataset = me.data.datasets[datasetIndex];
+    const metasets = me._metasets;
+    let meta = metasets.filter(x => x && x._dataset === dataset).pop();
+
+    if (!meta) {
+      meta = metasets[datasetIndex] = {
+        type: null,
+        data: [],
+        dataset: null,
+        controller: null,
+        hidden: null,                  // See isDatasetVisible() comment
+        xAxisID: null,
+        yAxisID: null,
+        order: dataset && dataset.order || 0,
+        index: datasetIndex,
+        _dataset: dataset,
+        _parsed: [],
+        _sorted: false
+      };
+    }
+
+    return meta;
+  }
+
+  getContext() {
+    return this.$context || (this.$context = Object.create(null, {
+      chart: {
+        value: this
+      },
+      type: {
+        value: 'chart'
+      }
+    }));
+  }
+
+  getVisibleDatasetCount() {
+    return this.getSortedVisibleDatasetMetas().length;
+  }
+
+  isDatasetVisible(datasetIndex) {
+    const dataset = this.data.datasets[datasetIndex];
+    if (!dataset) {
+      return false;
+    }
+
+    const meta = this.getDatasetMeta(datasetIndex);
+
+    // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
+    // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
+    return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
+  }
+
+  setDatasetVisibility(datasetIndex, visible) {
+    const meta = this.getDatasetMeta(datasetIndex);
+    meta.hidden = !visible;
+  }
+
+  toggleDataVisibility(index) {
+    this._hiddenIndices[index] = !this._hiddenIndices[index];
+  }
+
+  getDataVisibility(index) {
+    return !this._hiddenIndices[index];
+  }
+
+  /**
         * @private
         */
-       _updateDatasetVisibility(datasetIndex, visible) {
-               const me = this;
-               const mode = visible ? 'show' : 'hide';
-               const meta = me.getDatasetMeta(datasetIndex);
-               const anims = meta.controller._resolveAnimations(undefined, mode);
-               me.setDatasetVisibility(datasetIndex, visible);
+  _updateDatasetVisibility(datasetIndex, visible) {
+    const me = this;
+    const mode = visible ? 'show' : 'hide';
+    const meta = me.getDatasetMeta(datasetIndex);
+    const anims = meta.controller._resolveAnimations(undefined, mode);
+    me.setDatasetVisibility(datasetIndex, visible);
 
-               // Animate visible state, so hide animation can be seen. This could be handled better if update / updateDataset returned a Promise.
-               anims.update(meta, {visible});
+    // Animate visible state, so hide animation can be seen. This could be handled better if update / updateDataset returned a Promise.
+    anims.update(meta, {visible});
 
-               me.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);
-       }
+    me.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);
+  }
 
-       hide(datasetIndex) {
-               this._updateDatasetVisibility(datasetIndex, false);
-       }
+  hide(datasetIndex) {
+    this._updateDatasetVisibility(datasetIndex, false);
+  }
 
-       show(datasetIndex) {
-               this._updateDatasetVisibility(datasetIndex, true);
-       }
+  show(datasetIndex) {
+    this._updateDatasetVisibility(datasetIndex, true);
+  }
 
-       /**
+  /**
         * @private
         */
-       _destroyDatasetMeta(datasetIndex) {
-               const me = this;
-               const meta = me._metasets && me._metasets[datasetIndex];
-
-               if (meta && meta.controller) {
-                       meta.controller._destroy();
-                       delete me._metasets[datasetIndex];
-               }
-       }
-
-       destroy() {
-               const me = this;
-               const {canvas, ctx} = me;
-               let i, ilen;
-
-               me.stop();
-               animator.remove(me);
-
-               // dataset controllers need to cleanup associated data
-               for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
-                       me._destroyDatasetMeta(i);
-               }
-
-               if (canvas) {
-                       me.unbindEvents();
-                       clearCanvas(canvas, ctx);
-                       me.platform.releaseContext(ctx);
-                       me.canvas = null;
-                       me.ctx = null;
-               }
-
-               me.notifyPlugins('destroy');
-
-               delete Chart.instances[me.id];
-       }
-
-       toBase64Image(...args) {
-               return this.canvas.toDataURL(...args);
-       }
-
-       /**
+  _destroyDatasetMeta(datasetIndex) {
+    const me = this;
+    const meta = me._metasets && me._metasets[datasetIndex];
+
+    if (meta && meta.controller) {
+      meta.controller._destroy();
+      delete me._metasets[datasetIndex];
+    }
+  }
+
+  destroy() {
+    const me = this;
+    const {canvas, ctx} = me;
+    let i, ilen;
+
+    me.stop();
+    animator.remove(me);
+
+    // dataset controllers need to cleanup associated data
+    for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
+      me._destroyDatasetMeta(i);
+    }
+
+    if (canvas) {
+      me.unbindEvents();
+      clearCanvas(canvas, ctx);
+      me.platform.releaseContext(ctx);
+      me.canvas = null;
+      me.ctx = null;
+    }
+
+    me.notifyPlugins('destroy');
+
+    delete Chart.instances[me.id];
+  }
+
+  toBase64Image(...args) {
+    return this.canvas.toDataURL(...args);
+  }
+
+  /**
         * @private
         */
-       bindEvents() {
-               const me = this;
-               const listeners = me._listeners;
-               const platform = me.platform;
-
-               const _add = (type, listener) => {
-                       platform.addEventListener(me, type, listener);
-                       listeners[type] = listener;
-               };
-               const _remove = (type, listener) => {
-                       if (listeners[type]) {
-                               platform.removeEventListener(me, type, listener);
-                               delete listeners[type];
-                       }
-               };
-
-               let listener = function(e, x, y) {
-                       e.offsetX = x;
-                       e.offsetY = y;
-                       me._eventHandler(e);
-               };
-
-               each(me.options.events, (type) => _add(type, listener));
-
-               if (me.options.responsive) {
-                       listener = (width, height) => {
-                               if (me.canvas) {
-                                       me.resize(width, height);
-                               }
-                       };
-
-                       let detached; // eslint-disable-line prefer-const
-                       const attached = () => {
-                               _remove('attach', attached);
-
-                               me.attached = true;
-                               me.resize();
-
-                               _add('resize', listener);
-                               _add('detach', detached);
-                       };
-
-                       detached = () => {
-                               me.attached = false;
-
-                               _remove('resize', listener);
-                               _add('attach', attached);
-                       };
-
-                       if (platform.isAttached(me.canvas)) {
-                               attached();
-                       } else {
-                               detached();
-                       }
-               } else {
-                       me.attached = true;
-               }
-       }
-
-       /**
+  bindEvents() {
+    const me = this;
+    const listeners = me._listeners;
+    const platform = me.platform;
+
+    const _add = (type, listener) => {
+      platform.addEventListener(me, type, listener);
+      listeners[type] = listener;
+    };
+    const _remove = (type, listener) => {
+      if (listeners[type]) {
+        platform.removeEventListener(me, type, listener);
+        delete listeners[type];
+      }
+    };
+
+    let listener = function(e, x, y) {
+      e.offsetX = x;
+      e.offsetY = y;
+      me._eventHandler(e);
+    };
+
+    each(me.options.events, (type) => _add(type, listener));
+
+    if (me.options.responsive) {
+      listener = (width, height) => {
+        if (me.canvas) {
+          me.resize(width, height);
+        }
+      };
+
+      let detached; // eslint-disable-line prefer-const
+      const attached = () => {
+        _remove('attach', attached);
+
+        me.attached = true;
+        me.resize();
+
+        _add('resize', listener);
+        _add('detach', detached);
+      };
+
+      detached = () => {
+        me.attached = false;
+
+        _remove('resize', listener);
+        _add('attach', attached);
+      };
+
+      if (platform.isAttached(me.canvas)) {
+        attached();
+      } else {
+        detached();
+      }
+    } else {
+      me.attached = true;
+    }
+  }
+
+  /**
         * @private
         */
-       unbindEvents() {
-               const me = this;
-               const listeners = me._listeners;
-               if (!listeners) {
-                       return;
-               }
-
-               delete me._listeners;
-               each(listeners, (listener, type) => {
-                       me.platform.removeEventListener(me, type, listener);
-               });
-       }
-
-       updateHoverStyle(items, mode, enabled) {
-               const prefix = enabled ? 'set' : 'remove';
-               let meta, item, i, ilen;
-
-               if (mode === 'dataset') {
-                       meta = this.getDatasetMeta(items[0].datasetIndex);
-                       meta.controller['_' + prefix + 'DatasetHoverStyle']();
-               }
-
-               for (i = 0, ilen = items.length; i < ilen; ++i) {
-                       item = items[i];
-                       const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
-                       if (controller) {
-                               controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
-                       }
-               }
-       }
-
-       /**
+  unbindEvents() {
+    const me = this;
+    const listeners = me._listeners;
+    if (!listeners) {
+      return;
+    }
+
+    delete me._listeners;
+    each(listeners, (listener, type) => {
+      me.platform.removeEventListener(me, type, listener);
+    });
+  }
+
+  updateHoverStyle(items, mode, enabled) {
+    const prefix = enabled ? 'set' : 'remove';
+    let meta, item, i, ilen;
+
+    if (mode === 'dataset') {
+      meta = this.getDatasetMeta(items[0].datasetIndex);
+      meta.controller['_' + prefix + 'DatasetHoverStyle']();
+    }
+
+    for (i = 0, ilen = items.length; i < ilen; ++i) {
+      item = items[i];
+      const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
+      if (controller) {
+        controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
+      }
+    }
+  }
+
+  /**
         * Get active (hovered) elements
         * @returns array
         */
-       getActiveElements() {
-               return this._active || [];
-       }
+  getActiveElements() {
+    return this._active || [];
+  }
 
-       /**
+  /**
         * Set active (hovered) elements
         * @param {array} activeElements New active data points
         */
-       setActiveElements(activeElements) {
-               const me = this;
-               const lastActive = me._active || [];
-               const active = activeElements.map(({datasetIndex, index}) => {
-                       const meta = me.getDatasetMeta(datasetIndex);
-                       if (!meta) {
-                               throw new Error('No dataset found at index ' + datasetIndex);
-                       }
-
-                       return {
-                               datasetIndex,
-                               element: meta.data[index],
-                               index,
-                       };
-               });
-               const changed = !_elementsEqual(active, lastActive);
-
-               if (changed) {
-                       me._active = active;
-                       me._updateHoverStyles(active, lastActive);
-               }
-       }
-
-       /**
+  setActiveElements(activeElements) {
+    const me = this;
+    const lastActive = me._active || [];
+    const active = activeElements.map(({datasetIndex, index}) => {
+      const meta = me.getDatasetMeta(datasetIndex);
+      if (!meta) {
+        throw new Error('No dataset found at index ' + datasetIndex);
+      }
+
+      return {
+        datasetIndex,
+        element: meta.data[index],
+        index,
+      };
+    });
+    const changed = !_elementsEqual(active, lastActive);
+
+    if (changed) {
+      me._active = active;
+      me._updateHoverStyles(active, lastActive);
+    }
+  }
+
+  /**
         * Calls enabled plugins on the specified hook and with the given args.
         * This method immediately returns as soon as a plugin explicitly returns false. The
         * returned value can be used, for instance, to interrupt the current action.
@@ -991,109 +991,109 @@ class Chart {
         * @param {Object} [args] - Extra arguments to apply to the hook call.
         * @returns {boolean} false if any of the plugins return false, else returns true.
         */
-       notifyPlugins(hook, args) {
-               return this._plugins.notify(this, hook, args);
-       }
+  notifyPlugins(hook, args) {
+    return this._plugins.notify(this, hook, args);
+  }
 
-       /**
+  /**
         * @private
         */
-       _updateHoverStyles(active, lastActive, replay) {
-               const me = this;
-               const options = me.options || {};
-               const hoverOptions = options.hover;
-               const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index));
-               const deactivated = diff(lastActive, active);
-               const activated = replay ? active : diff(active, lastActive);
-
-               if (deactivated.length) {
-                       me.updateHoverStyle(deactivated, hoverOptions.mode, false);
-               }
-
-               if (activated.length && hoverOptions.mode) {
-                       me.updateHoverStyle(activated, hoverOptions.mode, true);
-               }
-       }
-
-       /**
+  _updateHoverStyles(active, lastActive, replay) {
+    const me = this;
+    const options = me.options || {};
+    const hoverOptions = options.hover;
+    const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index));
+    const deactivated = diff(lastActive, active);
+    const activated = replay ? active : diff(active, lastActive);
+
+    if (deactivated.length) {
+      me.updateHoverStyle(deactivated, hoverOptions.mode, false);
+    }
+
+    if (activated.length && hoverOptions.mode) {
+      me.updateHoverStyle(activated, hoverOptions.mode, true);
+    }
+  }
+
+  /**
         * @private
         */
-       _eventHandler(e, replay) {
-               const me = this;
-               const args = {event: e, replay, cancelable: true};
+  _eventHandler(e, replay) {
+    const me = this;
+    const args = {event: e, replay, cancelable: true};
 
-               if (me.notifyPlugins('beforeEvent', args) === false) {
-                       return;
-               }
+    if (me.notifyPlugins('beforeEvent', args) === false) {
+      return;
+    }
 
-               const changed = me._handleEvent(e, replay);
+    const changed = me._handleEvent(e, replay);
 
-               args.cancelable = false;
-               me.notifyPlugins('afterEvent', args);
+    args.cancelable = false;
+    me.notifyPlugins('afterEvent', args);
 
-               if (changed || args.changed) {
-                       me.render();
-               }
+    if (changed || args.changed) {
+      me.render();
+    }
 
-               return me;
-       }
+    return me;
+  }
 
-       /**
+  /**
         * Handle an event
         * @param {ChartEvent} e the event to handle
         * @param {boolean} [replay] - true if the event was replayed by `update`
         * @return {boolean} true if the chart needs to re-render
         * @private
         */
-       _handleEvent(e, replay) {
-               const me = this;
-               const lastActive = me._active || [];
-               const options = me.options;
-               const hoverOptions = options.hover;
-
-               // If the event is replayed from `update`, we should evaluate with the final positions.
-               //
-               // The `replay`:
-               // It's the last event (excluding click) that has occurred before `update`.
-               // So mouse has not moved. It's also over the chart, because there is a `replay`.
-               //
-               // The why:
-               // If animations are active, the elements haven't moved yet compared to state before update.
-               // But if they will, we are activating the elements that would be active, if this check
-               // was done after the animations have completed. => "final positions".
-               // If there is no animations, the "final" and "current" positions are equal.
-               // This is done so we do not have to evaluate the active elements each animation frame
-               // - it would be expensive.
-               const useFinalPosition = replay;
-
-               let active = [];
-               let changed = false;
-
-               // Find Active Elements for hover and tooltips
-               if (e.type === 'mouseout') {
-                       me._lastEvent = null;
-               } else {
-                       active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
-                       me._lastEvent = e.type === 'click' ? me._lastEvent : e;
-               }
-
-               // Invoke onHover hook
-               callCallback(options.onHover || options.hover.onHover, [e, active, me], me);
-
-               if (e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu') {
-                       if (_isPointInArea(e, me.chartArea)) {
-                               callCallback(options.onClick, [e, active, me], me);
-                       }
-               }
-
-               changed = !_elementsEqual(active, lastActive);
-               if (changed || replay) {
-                       me._active = active;
-                       me._updateHoverStyles(active, lastActive, replay);
-               }
-
-               return changed;
-       }
+  _handleEvent(e, replay) {
+    const me = this;
+    const lastActive = me._active || [];
+    const options = me.options;
+    const hoverOptions = options.hover;
+
+    // If the event is replayed from `update`, we should evaluate with the final positions.
+    //
+    // The `replay`:
+    // It's the last event (excluding click) that has occurred before `update`.
+    // So mouse has not moved. It's also over the chart, because there is a `replay`.
+    //
+    // The why:
+    // If animations are active, the elements haven't moved yet compared to state before update.
+    // But if they will, we are activating the elements that would be active, if this check
+    // was done after the animations have completed. => "final positions".
+    // If there is no animations, the "final" and "current" positions are equal.
+    // This is done so we do not have to evaluate the active elements each animation frame
+    // - it would be expensive.
+    const useFinalPosition = replay;
+
+    let active = [];
+    let changed = false;
+
+    // Find Active Elements for hover and tooltips
+    if (e.type === 'mouseout') {
+      me._lastEvent = null;
+    } else {
+      active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
+      me._lastEvent = e.type === 'click' ? me._lastEvent : e;
+    }
+
+    // Invoke onHover hook
+    callCallback(options.onHover || options.hover.onHover, [e, active, me], me);
+
+    if (e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu') {
+      if (_isPointInArea(e, me.chartArea)) {
+        callCallback(options.onClick, [e, active, me], me);
+      }
+    }
+
+    changed = !_elementsEqual(active, lastActive);
+    if (changed || replay) {
+      me._active = active;
+      me._updateHoverStyles(active, lastActive, replay);
+    }
+
+    return changed;
+  }
 }
 
 // These are available to both, UMD and ESM packages
@@ -1103,20 +1103,20 @@ Chart.registry = registry;
 Chart.version = version;
 
 Chart.getChart = (key) => {
-       const canvas = getCanvas(key);
-       return Object.values(Chart.instances).filter((c) => c.canvas === canvas).pop();
+  const canvas = getCanvas(key);
+  return Object.values(Chart.instances).filter((c) => c.canvas === canvas).pop();
 };
 
 // @ts-ignore
 const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate());
 
 Chart.register = (...items) => {
-       registry.add(...items);
-       invalidatePlugins();
+  registry.add(...items);
+  invalidatePlugins();
 };
 Chart.unregister = (...items) => {
-       registry.remove(...items);
-       invalidatePlugins();
+  registry.remove(...items);
+  invalidatePlugins();
 };
 
 export default Chart;
index 49413ce938735341977db60a0f95d7b5317515db..b5f50fd091ce3ef8ad2d10719abab43ae7d30f51 100644 (file)
@@ -12,202 +12,202 @@ import {sign} from '../helpers/helpers.math';
  */
 
 function scaleClip(scale, allowedOverflow) {
-       const opts = scale && scale.options || {};
-       const reverse = opts.reverse;
-       const min = opts.min === undefined ? allowedOverflow : 0;
-       const max = opts.max === undefined ? allowedOverflow : 0;
-       return {
-               start: reverse ? max : min,
-               end: reverse ? min : max
-       };
+  const opts = scale && scale.options || {};
+  const reverse = opts.reverse;
+  const min = opts.min === undefined ? allowedOverflow : 0;
+  const max = opts.max === undefined ? allowedOverflow : 0;
+  return {
+    start: reverse ? max : min,
+    end: reverse ? min : max
+  };
 }
 
 function defaultClip(xScale, yScale, allowedOverflow) {
-       if (allowedOverflow === false) {
-               return false;
-       }
-       const x = scaleClip(xScale, allowedOverflow);
-       const y = scaleClip(yScale, allowedOverflow);
-
-       return {
-               top: y.end,
-               right: x.end,
-               bottom: y.start,
-               left: x.start
-       };
+  if (allowedOverflow === false) {
+    return false;
+  }
+  const x = scaleClip(xScale, allowedOverflow);
+  const y = scaleClip(yScale, allowedOverflow);
+
+  return {
+    top: y.end,
+    right: x.end,
+    bottom: y.start,
+    left: x.start
+  };
 }
 
 function toClip(value) {
-       let t, r, b, l;
-
-       if (isObject(value)) {
-               t = value.top;
-               r = value.right;
-               b = value.bottom;
-               l = value.left;
-       } else {
-               t = r = b = l = value;
-       }
-
-       return {
-               top: t,
-               right: r,
-               bottom: b,
-               left: l
-       };
+  let t, r, b, l;
+
+  if (isObject(value)) {
+    t = value.top;
+    r = value.right;
+    b = value.bottom;
+    l = value.left;
+  } else {
+    t = r = b = l = value;
+  }
+
+  return {
+    top: t,
+    right: r,
+    bottom: b,
+    left: l
+  };
 }
 
 function getSortedDatasetIndices(chart, filterVisible) {
-       const keys = [];
-       const metasets = chart._getSortedDatasetMetas(filterVisible);
-       let i, ilen;
-
-       for (i = 0, ilen = metasets.length; i < ilen; ++i) {
-               keys.push(metasets[i].index);
-       }
-       return keys;
+  const keys = [];
+  const metasets = chart._getSortedDatasetMetas(filterVisible);
+  let i, ilen;
+
+  for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+    keys.push(metasets[i].index);
+  }
+  return keys;
 }
 
 function applyStack(stack, value, dsIndex, allOther) {
-       const keys = stack.keys;
-       let i, ilen, datasetIndex, otherValue;
-
-       for (i = 0, ilen = keys.length; i < ilen; ++i) {
-               datasetIndex = +keys[i];
-               if (datasetIndex === dsIndex) {
-                       if (allOther) {
-                               continue;
-                       }
-                       break;
-               }
-               otherValue = stack.values[datasetIndex];
-               if (!isNaN(otherValue) && (value === 0 || sign(value) === sign(otherValue))) {
-                       value += otherValue;
-               }
-       }
-       return value;
+  const keys = stack.keys;
+  let i, ilen, datasetIndex, otherValue;
+
+  for (i = 0, ilen = keys.length; i < ilen; ++i) {
+    datasetIndex = +keys[i];
+    if (datasetIndex === dsIndex) {
+      if (allOther) {
+        continue;
+      }
+      break;
+    }
+    otherValue = stack.values[datasetIndex];
+    if (!isNaN(otherValue) && (value === 0 || sign(value) === sign(otherValue))) {
+      value += otherValue;
+    }
+  }
+  return value;
 }
 
 function convertObjectDataToArray(data) {
-       const keys = Object.keys(data);
-       const adata = new Array(keys.length);
-       let i, ilen, key;
-       for (i = 0, ilen = keys.length; i < ilen; ++i) {
-               key = keys[i];
-               adata[i] = {
-                       x: key,
-                       y: data[key]
-               };
-       }
-       return adata;
+  const keys = Object.keys(data);
+  const adata = new Array(keys.length);
+  let i, ilen, key;
+  for (i = 0, ilen = keys.length; i < ilen; ++i) {
+    key = keys[i];
+    adata[i] = {
+      x: key,
+      y: data[key]
+    };
+  }
+  return adata;
 }
 
 function isStacked(scale, meta) {
-       const stacked = scale && scale.options.stacked;
-       return stacked || (stacked === undefined && meta.stack !== undefined);
+  const stacked = scale && scale.options.stacked;
+  return stacked || (stacked === undefined && meta.stack !== undefined);
 }
 
 function getStackKey(indexScale, valueScale, meta) {
-       return indexScale.id + '.' + valueScale.id + '.' + meta.stack + '.' + meta.type;
+  return indexScale.id + '.' + valueScale.id + '.' + meta.stack + '.' + meta.type;
 }
 
 function getUserBounds(scale) {
-       const {min, max, minDefined, maxDefined} = scale.getUserBounds();
-       return {
-               min: minDefined ? min : Number.NEGATIVE_INFINITY,
-               max: maxDefined ? max : Number.POSITIVE_INFINITY
-       };
+  const {min, max, minDefined, maxDefined} = scale.getUserBounds();
+  return {
+    min: minDefined ? min : Number.NEGATIVE_INFINITY,
+    max: maxDefined ? max : Number.POSITIVE_INFINITY
+  };
 }
 
 function getOrCreateStack(stacks, stackKey, indexValue) {
-       const subStack = stacks[stackKey] || (stacks[stackKey] = {});
-       return subStack[indexValue] || (subStack[indexValue] = {});
+  const subStack = stacks[stackKey] || (stacks[stackKey] = {});
+  return subStack[indexValue] || (subStack[indexValue] = {});
 }
 
 function updateStacks(controller, parsed) {
-       const {chart, _cachedMeta: meta} = controller;
-       const stacks = chart._stacks || (chart._stacks = {}); // map structure is {stackKey: {datasetIndex: value}}
-       const {iScale, vScale, index: datasetIndex} = meta;
-       const iAxis = iScale.axis;
-       const vAxis = vScale.axis;
-       const key = getStackKey(iScale, vScale, meta);
-       const ilen = parsed.length;
-       let stack;
-
-       for (let i = 0; i < ilen; ++i) {
-               const item = parsed[i];
-               const {[iAxis]: index, [vAxis]: value} = item;
-               const itemStacks = item._stacks || (item._stacks = {});
-               stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
-               stack[datasetIndex] = value;
-       }
+  const {chart, _cachedMeta: meta} = controller;
+  const stacks = chart._stacks || (chart._stacks = {}); // map structure is {stackKey: {datasetIndex: value}}
+  const {iScale, vScale, index: datasetIndex} = meta;
+  const iAxis = iScale.axis;
+  const vAxis = vScale.axis;
+  const key = getStackKey(iScale, vScale, meta);
+  const ilen = parsed.length;
+  let stack;
+
+  for (let i = 0; i < ilen; ++i) {
+    const item = parsed[i];
+    const {[iAxis]: index, [vAxis]: value} = item;
+    const itemStacks = item._stacks || (item._stacks = {});
+    stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
+    stack[datasetIndex] = value;
+  }
 }
 
 function getFirstScaleId(chart, axis) {
-       const scales = chart.scales;
-       return Object.keys(scales).filter(key => scales[key].axis === axis).shift();
+  const scales = chart.scales;
+  return Object.keys(scales).filter(key => scales[key].axis === axis).shift();
 }
 
 function createDatasetContext(parent, index, dataset) {
-       return Object.create(parent, {
-               active: {
-                       writable: true,
-                       value: false
-               },
-               dataset: {
-                       value: dataset
-               },
-               datasetIndex: {
-                       value: index
-               },
-               index: {
-                       get() {
-                               return this.datasetIndex;
-                       }
-               },
-               type: {
-                       value: 'dataset'
-               }
-       });
+  return Object.create(parent, {
+    active: {
+      writable: true,
+      value: false
+    },
+    dataset: {
+      value: dataset
+    },
+    datasetIndex: {
+      value: index
+    },
+    index: {
+      get() {
+        return this.datasetIndex;
+      }
+    },
+    type: {
+      value: 'dataset'
+    }
+  });
 }
 
 function createDataContext(parent, index, point, raw, element) {
-       return Object.create(parent, {
-               active: {
-                       writable: true,
-                       value: false
-               },
-               dataIndex: {
-                       value: index
-               },
-               parsed: {
-                       value: point
-               },
-               raw: {
-                       value: raw
-               },
-               element: {
-                       value: element
-               },
-               index: {
-                       get() {
-                               return this.dataIndex;
-                       }
-               },
-               type: {
-                       value: 'data',
-               }
-       });
+  return Object.create(parent, {
+    active: {
+      writable: true,
+      value: false
+    },
+    dataIndex: {
+      value: index
+    },
+    parsed: {
+      value: point
+    },
+    raw: {
+      value: raw
+    },
+    element: {
+      value: element
+    },
+    index: {
+      get() {
+        return this.dataIndex;
+      }
+    },
+    type: {
+      value: 'data',
+    }
+  });
 }
 
 function clearStacks(meta, items) {
-       items = items || meta._parsed;
-       items.forEach((parsed) => {
-               if (parsed._stacks[meta.vScale.id] === undefined || parsed._stacks[meta.vScale.id][meta.index] === undefined) {
-                       return;
-               }
-               delete parsed._stacks[meta.vScale.id][meta.index];
-       });
+  items = items || meta._parsed;
+  items.forEach((parsed) => {
+    if (parsed._stacks[meta.vScale.id] === undefined || parsed._stacks[meta.vScale.id][meta.index] === undefined) {
+      return;
+    }
+    delete parsed._stacks[meta.vScale.id][meta.index];
+  });
 }
 
 const optionKeys = (optionNames) => isArray(optionNames) ? optionNames : Object.keys(optionNames);
@@ -217,243 +217,243 @@ const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({},
 
 export default class DatasetController {
 
-       /**
+  /**
         * @param {Chart} chart
         * @param {number} datasetIndex
         */
-       constructor(chart, datasetIndex) {
-               this.chart = chart;
-               this._ctx = chart.ctx;
-               this.index = datasetIndex;
-               this._cachedAnimations = {};
-               this._cachedDataOpts = {};
-               this._cachedMeta = this.getMeta();
-               this._type = this._cachedMeta.type;
-               this._config = undefined;
-               /** @type {boolean | object} */
-               this._parsing = false;
-               this._data = undefined;
-               this._objectData = undefined;
-               this._sharedOptions = undefined;
-               this._drawStart = undefined;
-               this._drawCount = undefined;
-               this.enableOptionSharing = false;
-               this.$context = undefined;
-
-               this.initialize();
-       }
-
-       initialize() {
-               const me = this;
-               const meta = me._cachedMeta;
-               me.configure();
-               me.linkScales();
-               meta._stacked = isStacked(meta.vScale, meta);
-               me.addElements();
-       }
-
-       updateIndex(datasetIndex) {
-               this.index = datasetIndex;
-       }
-
-       linkScales() {
-               const me = this;
-               const chart = me.chart;
-               const meta = me._cachedMeta;
-               const dataset = me.getDataset();
-
-               const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y;
-
-               const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));
-               const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));
-               const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));
-               const indexAxis = meta.indexAxis;
-               const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
-               const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
-               meta.xScale = me.getScaleForId(xid);
-               meta.yScale = me.getScaleForId(yid);
-               meta.rScale = me.getScaleForId(rid);
-               meta.iScale = me.getScaleForId(iid);
-               meta.vScale = me.getScaleForId(vid);
-       }
-
-       getDataset() {
-               return this.chart.data.datasets[this.index];
-       }
-
-       getMeta() {
-               return this.chart.getDatasetMeta(this.index);
-       }
-
-       /**
+  constructor(chart, datasetIndex) {
+    this.chart = chart;
+    this._ctx = chart.ctx;
+    this.index = datasetIndex;
+    this._cachedAnimations = {};
+    this._cachedDataOpts = {};
+    this._cachedMeta = this.getMeta();
+    this._type = this._cachedMeta.type;
+    this._config = undefined;
+    /** @type {boolean | object} */
+    this._parsing = false;
+    this._data = undefined;
+    this._objectData = undefined;
+    this._sharedOptions = undefined;
+    this._drawStart = undefined;
+    this._drawCount = undefined;
+    this.enableOptionSharing = false;
+    this.$context = undefined;
+
+    this.initialize();
+  }
+
+  initialize() {
+    const me = this;
+    const meta = me._cachedMeta;
+    me.configure();
+    me.linkScales();
+    meta._stacked = isStacked(meta.vScale, meta);
+    me.addElements();
+  }
+
+  updateIndex(datasetIndex) {
+    this.index = datasetIndex;
+  }
+
+  linkScales() {
+    const me = this;
+    const chart = me.chart;
+    const meta = me._cachedMeta;
+    const dataset = me.getDataset();
+
+    const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y;
+
+    const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));
+    const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));
+    const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));
+    const indexAxis = meta.indexAxis;
+    const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
+    const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
+    meta.xScale = me.getScaleForId(xid);
+    meta.yScale = me.getScaleForId(yid);
+    meta.rScale = me.getScaleForId(rid);
+    meta.iScale = me.getScaleForId(iid);
+    meta.vScale = me.getScaleForId(vid);
+  }
+
+  getDataset() {
+    return this.chart.data.datasets[this.index];
+  }
+
+  getMeta() {
+    return this.chart.getDatasetMeta(this.index);
+  }
+
+  /**
         * @param {string} scaleID
         * @return {Scale}
         */
-       getScaleForId(scaleID) {
-               return this.chart.scales[scaleID];
-       }
+  getScaleForId(scaleID) {
+    return this.chart.scales[scaleID];
+  }
 
-       /**
+  /**
         * @private
         */
-       _getOtherScale(scale) {
-               const meta = this._cachedMeta;
-               return scale === meta.iScale
-                       ? meta.vScale
-                       : meta.iScale;
-       }
-
-       reset() {
-               this._update('reset');
-       }
-
-       /**
+  _getOtherScale(scale) {
+    const meta = this._cachedMeta;
+    return scale === meta.iScale
+      ? meta.vScale
+      : meta.iScale;
+  }
+
+  reset() {
+    this._update('reset');
+  }
+
+  /**
         * @private
         */
-       _destroy() {
-               const meta = this._cachedMeta;
-               if (this._data) {
-                       unlistenArrayEvents(this._data, this);
-               }
-               if (meta._stacked) {
-                       clearStacks(meta);
-               }
-       }
-
-       /**
+  _destroy() {
+    const meta = this._cachedMeta;
+    if (this._data) {
+      unlistenArrayEvents(this._data, this);
+    }
+    if (meta._stacked) {
+      clearStacks(meta);
+    }
+  }
+
+  /**
         * @private
         */
-       _dataCheck() {
-               const me = this;
-               const dataset = me.getDataset();
-               const data = dataset.data || (dataset.data = []);
-
-               // In order to correctly handle data addition/deletion animation (an thus simulate
-               // real-time charts), we need to monitor these data modifications and synchronize
-               // the internal meta data accordingly.
-
-               if (isObject(data)) {
-                       me._data = convertObjectDataToArray(data);
-               } else if (me._data !== data) {
-                       if (me._data) {
-                               // This case happens when the user replaced the data array instance.
-                               unlistenArrayEvents(me._data, me);
-                       }
-                       if (data && Object.isExtensible(data)) {
-                               listenArrayEvents(data, me);
-                       }
-                       me._data = data;
-               }
-       }
-
-       addElements() {
-               const me = this;
-               const meta = me._cachedMeta;
-
-               me._dataCheck();
-
-               if (me.datasetElementType) {
-                       meta.dataset = new me.datasetElementType();
-               }
-       }
-
-       buildOrUpdateElements(resetNewElements) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const dataset = me.getDataset();
-               let stackChanged = false;
-
-               me._dataCheck();
-
-               // make sure cached _stacked status is current
-               meta._stacked = isStacked(meta.vScale, meta);
-
-               // detect change in stack option
-               if (meta.stack !== dataset.stack) {
-                       stackChanged = true;
-                       // remove values from old stack
-                       clearStacks(meta);
-                       meta.stack = dataset.stack;
-               }
-
-               // Re-sync meta data in case the user replaced the data array or if we missed
-               // any updates and so make sure that we handle number of datapoints changing.
-               me._resyncElements(resetNewElements);
-
-               // if stack changed, update stack values for the whole dataset
-               if (stackChanged) {
-                       updateStacks(me, meta._parsed);
-               }
-       }
-
-       /**
+  _dataCheck() {
+    const me = this;
+    const dataset = me.getDataset();
+    const data = dataset.data || (dataset.data = []);
+
+    // In order to correctly handle data addition/deletion animation (an thus simulate
+    // real-time charts), we need to monitor these data modifications and synchronize
+    // the internal meta data accordingly.
+
+    if (isObject(data)) {
+      me._data = convertObjectDataToArray(data);
+    } else if (me._data !== data) {
+      if (me._data) {
+        // This case happens when the user replaced the data array instance.
+        unlistenArrayEvents(me._data, me);
+      }
+      if (data && Object.isExtensible(data)) {
+        listenArrayEvents(data, me);
+      }
+      me._data = data;
+    }
+  }
+
+  addElements() {
+    const me = this;
+    const meta = me._cachedMeta;
+
+    me._dataCheck();
+
+    if (me.datasetElementType) {
+      meta.dataset = new me.datasetElementType();
+    }
+  }
+
+  buildOrUpdateElements(resetNewElements) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const dataset = me.getDataset();
+    let stackChanged = false;
+
+    me._dataCheck();
+
+    // make sure cached _stacked status is current
+    meta._stacked = isStacked(meta.vScale, meta);
+
+    // detect change in stack option
+    if (meta.stack !== dataset.stack) {
+      stackChanged = true;
+      // remove values from old stack
+      clearStacks(meta);
+      meta.stack = dataset.stack;
+    }
+
+    // Re-sync meta data in case the user replaced the data array or if we missed
+    // any updates and so make sure that we handle number of datapoints changing.
+    me._resyncElements(resetNewElements);
+
+    // if stack changed, update stack values for the whole dataset
+    if (stackChanged) {
+      updateStacks(me, meta._parsed);
+    }
+  }
+
+  /**
         * Merges user-supplied and default dataset-level options
         * @private
         */
-       configure() {
-               const me = this;
-               me._config = merge(Object.create(null), [
-                       defaults.controllers[me._type].datasets,
-                       (me.chart.options.datasets || {})[me._type],
-                       me.getDataset(),
-               ], {
-                       merger(key, target, source) {
-                               // Cloning the data is expensive and unnecessary.
-                               // Additionally, plugins may add dataset level fields that should
-                               // not be cloned. We identify those via an underscore prefix
-                               if (key !== 'data' && key.charAt(0) !== '_') {
-                                       _merger(key, target, source);
-                               }
-                       }
-               });
-               me._parsing = resolve([me._config.parsing, me.chart.options.parsing, true]);
-       }
-
-       /**
+  configure() {
+    const me = this;
+    me._config = merge(Object.create(null), [
+      defaults.controllers[me._type].datasets,
+      (me.chart.options.datasets || {})[me._type],
+      me.getDataset(),
+    ], {
+      merger(key, target, source) {
+        // Cloning the data is expensive and unnecessary.
+        // Additionally, plugins may add dataset level fields that should
+        // not be cloned. We identify those via an underscore prefix
+        if (key !== 'data' && key.charAt(0) !== '_') {
+          _merger(key, target, source);
+        }
+      }
+    });
+    me._parsing = resolve([me._config.parsing, me.chart.options.parsing, true]);
+  }
+
+  /**
         * @param {number} start
         * @param {number} count
         */
-       parse(start, count) {
-               const me = this;
-               const {_cachedMeta: meta, _data: data} = me;
-               const {iScale, _stacked} = meta;
-               const iAxis = iScale.axis;
-
-               let sorted = start === 0 && count === data.length ? true : meta._sorted;
-               let prev = start > 0 && meta._parsed[start - 1];
-               let i, cur, parsed;
-
-               if (me._parsing === false) {
-                       meta._parsed = data;
-                       meta._sorted = true;
-               } else {
-                       if (isArray(data[start])) {
-                               parsed = me.parseArrayData(meta, data, start, count);
-                       } else if (isObject(data[start])) {
-                               parsed = me.parseObjectData(meta, data, start, count);
-                       } else {
-                               parsed = me.parsePrimitiveData(meta, data, start, count);
-                       }
-
-                       const isNotInOrderComparedToPrev = () => isNaN(cur[iAxis]) || (prev && cur[iAxis] < prev[iAxis]);
-                       for (i = 0; i < count; ++i) {
-                               meta._parsed[i + start] = cur = parsed[i];
-                               if (sorted) {
-                                       if (isNotInOrderComparedToPrev()) {
-                                               sorted = false;
-                                       }
-                                       prev = cur;
-                               }
-                       }
-                       meta._sorted = sorted;
-               }
-
-               if (_stacked) {
-                       updateStacks(me, parsed);
-               }
-       }
-
-       /**
+  parse(start, count) {
+    const me = this;
+    const {_cachedMeta: meta, _data: data} = me;
+    const {iScale, _stacked} = meta;
+    const iAxis = iScale.axis;
+
+    let sorted = start === 0 && count === data.length ? true : meta._sorted;
+    let prev = start > 0 && meta._parsed[start - 1];
+    let i, cur, parsed;
+
+    if (me._parsing === false) {
+      meta._parsed = data;
+      meta._sorted = true;
+    } else {
+      if (isArray(data[start])) {
+        parsed = me.parseArrayData(meta, data, start, count);
+      } else if (isObject(data[start])) {
+        parsed = me.parseObjectData(meta, data, start, count);
+      } else {
+        parsed = me.parsePrimitiveData(meta, data, start, count);
+      }
+
+      const isNotInOrderComparedToPrev = () => isNaN(cur[iAxis]) || (prev && cur[iAxis] < prev[iAxis]);
+      for (i = 0; i < count; ++i) {
+        meta._parsed[i + start] = cur = parsed[i];
+        if (sorted) {
+          if (isNotInOrderComparedToPrev()) {
+            sorted = false;
+          }
+          prev = cur;
+        }
+      }
+      meta._sorted = sorted;
+    }
+
+    if (_stacked) {
+      updateStacks(me, parsed);
+    }
+  }
+
+  /**
         * Parse array of primitive values
         * @param {object} meta - dataset meta
         * @param {array} data - data array. Example [1,3,4]
@@ -464,26 +464,26 @@ export default class DatasetController {
         * Example: {xScale0: 0, yScale0: 1}
         * @protected
         */
-       parsePrimitiveData(meta, data, start, count) {
-               const {iScale, vScale} = meta;
-               const iAxis = iScale.axis;
-               const vAxis = vScale.axis;
-               const labels = iScale.getLabels();
-               const singleScale = iScale === vScale;
-               const parsed = new Array(count);
-               let i, ilen, index;
-
-               for (i = 0, ilen = count; i < ilen; ++i) {
-                       index = i + start;
-                       parsed[i] = {
-                               [iAxis]: singleScale || iScale.parse(labels[index], index),
-                               [vAxis]: vScale.parse(data[index], index)
-                       };
-               }
-               return parsed;
-       }
-
-       /**
+  parsePrimitiveData(meta, data, start, count) {
+    const {iScale, vScale} = meta;
+    const iAxis = iScale.axis;
+    const vAxis = vScale.axis;
+    const labels = iScale.getLabels();
+    const singleScale = iScale === vScale;
+    const parsed = new Array(count);
+    let i, ilen, index;
+
+    for (i = 0, ilen = count; i < ilen; ++i) {
+      index = i + start;
+      parsed[i] = {
+        [iAxis]: singleScale || iScale.parse(labels[index], index),
+        [vAxis]: vScale.parse(data[index], index)
+      };
+    }
+    return parsed;
+  }
+
+  /**
         * Parse array of arrays
         * @param {object} meta - dataset meta
         * @param {array} data - data array. Example [[1,2],[3,4]]
@@ -494,23 +494,23 @@ export default class DatasetController {
         * Example: {x: 0, y: 1}
         * @protected
         */
-       parseArrayData(meta, data, start, count) {
-               const {xScale, yScale} = meta;
-               const parsed = new Array(count);
-               let i, ilen, index, item;
-
-               for (i = 0, ilen = count; i < ilen; ++i) {
-                       index = i + start;
-                       item = data[index];
-                       parsed[i] = {
-                               x: xScale.parse(item[0], index),
-                               y: yScale.parse(item[1], index)
-                       };
-               }
-               return parsed;
-       }
-
-       /**
+  parseArrayData(meta, data, start, count) {
+    const {xScale, yScale} = meta;
+    const parsed = new Array(count);
+    let i, ilen, index, item;
+
+    for (i = 0, ilen = count; i < ilen; ++i) {
+      index = i + start;
+      item = data[index];
+      parsed[i] = {
+        x: xScale.parse(item[0], index),
+        y: yScale.parse(item[1], index)
+      };
+    }
+    return parsed;
+  }
+
+  /**
         * Parse array of objects
         * @param {object} meta - dataset meta
         * @param {array} data - data array. Example [{x:1, y:5}, {x:2, y:10}]
@@ -521,556 +521,556 @@ export default class DatasetController {
         * Example: {xScale0: 0, yScale0: 1, _custom: {r: 10, foo: 'bar'}}
         * @protected
         */
-       parseObjectData(meta, data, start, count) {
-               const {xScale, yScale} = meta;
-               const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
-               const parsed = new Array(count);
-               let i, ilen, index, item;
-
-               for (i = 0, ilen = count; i < ilen; ++i) {
-                       index = i + start;
-                       item = data[index];
-                       parsed[i] = {
-                               x: xScale.parse(resolveObjectKey(item, xAxisKey), index),
-                               y: yScale.parse(resolveObjectKey(item, yAxisKey), index)
-                       };
-               }
-               return parsed;
-       }
-
-       /**
+  parseObjectData(meta, data, start, count) {
+    const {xScale, yScale} = meta;
+    const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
+    const parsed = new Array(count);
+    let i, ilen, index, item;
+
+    for (i = 0, ilen = count; i < ilen; ++i) {
+      index = i + start;
+      item = data[index];
+      parsed[i] = {
+        x: xScale.parse(resolveObjectKey(item, xAxisKey), index),
+        y: yScale.parse(resolveObjectKey(item, yAxisKey), index)
+      };
+    }
+    return parsed;
+  }
+
+  /**
         * @protected
         */
-       getParsed(index) {
-               return this._cachedMeta._parsed[index];
-       }
+  getParsed(index) {
+    return this._cachedMeta._parsed[index];
+  }
 
-       /**
+  /**
         * @protected
         */
-       getDataElement(index) {
-               return this._cachedMeta.data[index];
-       }
+  getDataElement(index) {
+    return this._cachedMeta.data[index];
+  }
 
-       /**
+  /**
         * @protected
         */
-       applyStack(scale, parsed) {
-               const chart = this.chart;
-               const meta = this._cachedMeta;
-               const value = parsed[scale.axis];
-               const stack = {
-                       keys: getSortedDatasetIndices(chart, true),
-                       values: parsed._stacks[scale.axis]
-               };
-               return applyStack(stack, value, meta.index);
-       }
-
-       /**
+  applyStack(scale, parsed) {
+    const chart = this.chart;
+    const meta = this._cachedMeta;
+    const value = parsed[scale.axis];
+    const stack = {
+      keys: getSortedDatasetIndices(chart, true),
+      values: parsed._stacks[scale.axis]
+    };
+    return applyStack(stack, value, meta.index);
+  }
+
+  /**
         * @protected
         */
-       updateRangeFromParsed(range, scale, parsed, stack) {
-               let value = parsed[scale.axis];
-               const values = stack && parsed._stacks[scale.axis];
-               if (stack && values) {
-                       stack.values = values;
-                       // Need to consider individual stack values for data range,
-                       // in addition to the stacked value
-                       range.min = Math.min(range.min, value);
-                       range.max = Math.max(range.max, value);
-                       value = applyStack(stack, value, this._cachedMeta.index, true);
-               }
-               range.min = Math.min(range.min, value);
-               range.max = Math.max(range.max, value);
-       }
-
-       /**
+  updateRangeFromParsed(range, scale, parsed, stack) {
+    let value = parsed[scale.axis];
+    const values = stack && parsed._stacks[scale.axis];
+    if (stack && values) {
+      stack.values = values;
+      // Need to consider individual stack values for data range,
+      // in addition to the stacked value
+      range.min = Math.min(range.min, value);
+      range.max = Math.max(range.max, value);
+      value = applyStack(stack, value, this._cachedMeta.index, true);
+    }
+    range.min = Math.min(range.min, value);
+    range.max = Math.max(range.max, value);
+  }
+
+  /**
         * @protected
         */
-       getMinMax(scale, canStack) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const _parsed = meta._parsed;
-               const sorted = meta._sorted && scale === meta.iScale;
-               const ilen = _parsed.length;
-               const otherScale = me._getOtherScale(scale);
-               const stack = canStack && meta._stacked && {keys: getSortedDatasetIndices(me.chart, true), values: null};
-               const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY};
-               const {min: otherMin, max: otherMax} = getUserBounds(otherScale);
-               let i, value, parsed, otherValue;
-
-               function _skip() {
-                       parsed = _parsed[i];
-                       value = parsed[scale.axis];
-                       otherValue = parsed[otherScale.axis];
-                       return (isNaN(value) || isNaN(otherValue) || otherMin > otherValue || otherMax < otherValue);
-               }
-
-               for (i = 0; i < ilen; ++i) {
-                       if (_skip()) {
-                               continue;
-                       }
-                       me.updateRangeFromParsed(range, scale, parsed, stack);
-                       if (sorted) {
-                               // if the data is sorted, we don't need to check further from this end of array
-                               break;
-                       }
-               }
-               if (sorted) {
-                       // in the sorted case, find first non-skipped value from other end of array
-                       for (i = ilen - 1; i >= 0; --i) {
-                               if (_skip()) {
-                                       continue;
-                               }
-                               me.updateRangeFromParsed(range, scale, parsed, stack);
-                               break;
-                       }
-               }
-               return range;
-       }
-
-       getAllParsedValues(scale) {
-               const parsed = this._cachedMeta._parsed;
-               const values = [];
-               let i, ilen, value;
-
-               for (i = 0, ilen = parsed.length; i < ilen; ++i) {
-                       value = parsed[i][scale.axis];
-                       if (!isNaN(value)) {
-                               values.push(value);
-                       }
-               }
-               return values;
-       }
-
-       /**
+  getMinMax(scale, canStack) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const _parsed = meta._parsed;
+    const sorted = meta._sorted && scale === meta.iScale;
+    const ilen = _parsed.length;
+    const otherScale = me._getOtherScale(scale);
+    const stack = canStack && meta._stacked && {keys: getSortedDatasetIndices(me.chart, true), values: null};
+    const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY};
+    const {min: otherMin, max: otherMax} = getUserBounds(otherScale);
+    let i, value, parsed, otherValue;
+
+    function _skip() {
+      parsed = _parsed[i];
+      value = parsed[scale.axis];
+      otherValue = parsed[otherScale.axis];
+      return (isNaN(value) || isNaN(otherValue) || otherMin > otherValue || otherMax < otherValue);
+    }
+
+    for (i = 0; i < ilen; ++i) {
+      if (_skip()) {
+        continue;
+      }
+      me.updateRangeFromParsed(range, scale, parsed, stack);
+      if (sorted) {
+        // if the data is sorted, we don't need to check further from this end of array
+        break;
+      }
+    }
+    if (sorted) {
+      // in the sorted case, find first non-skipped value from other end of array
+      for (i = ilen - 1; i >= 0; --i) {
+        if (_skip()) {
+          continue;
+        }
+        me.updateRangeFromParsed(range, scale, parsed, stack);
+        break;
+      }
+    }
+    return range;
+  }
+
+  getAllParsedValues(scale) {
+    const parsed = this._cachedMeta._parsed;
+    const values = [];
+    let i, ilen, value;
+
+    for (i = 0, ilen = parsed.length; i < ilen; ++i) {
+      value = parsed[i][scale.axis];
+      if (!isNaN(value)) {
+        values.push(value);
+      }
+    }
+    return values;
+  }
+
+  /**
         * @return {number|boolean}
         * @protected
         */
-       getMaxOverflow() {
-               return false;
-       }
+  getMaxOverflow() {
+    return false;
+  }
 
-       /**
+  /**
         * @protected
         */
-       getLabelAndValue(index) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const iScale = meta.iScale;
-               const vScale = meta.vScale;
-               const parsed = me.getParsed(index);
-               return {
-                       label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
-                       value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
-               };
-       }
-
-       /**
+  getLabelAndValue(index) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const iScale = meta.iScale;
+    const vScale = meta.vScale;
+    const parsed = me.getParsed(index);
+    return {
+      label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
+      value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
+    };
+  }
+
+  /**
         * @private
         */
-       _update(mode) {
-               const me = this;
-               const meta = me._cachedMeta;
-               me.configure();
-               me._cachedAnimations = {};
-               me._cachedDataOpts = {};
-               me.update(mode || 'default');
-               meta._clip = toClip(valueOrDefault(me._config.clip, defaultClip(meta.xScale, meta.yScale, me.getMaxOverflow())));
-       }
-
-       /**
+  _update(mode) {
+    const me = this;
+    const meta = me._cachedMeta;
+    me.configure();
+    me._cachedAnimations = {};
+    me._cachedDataOpts = {};
+    me.update(mode || 'default');
+    meta._clip = toClip(valueOrDefault(me._config.clip, defaultClip(meta.xScale, meta.yScale, me.getMaxOverflow())));
+  }
+
+  /**
         * @param {string} mode
         */
-       update(mode) {} // eslint-disable-line no-unused-vars
-
-       draw() {
-               const me = this;
-               const ctx = me._ctx;
-               const chart = me.chart;
-               const meta = me._cachedMeta;
-               const elements = meta.data || [];
-               const area = chart.chartArea;
-               const active = [];
-               const start = me._drawStart || 0;
-               const count = me._drawCount || (elements.length - start);
-               let i;
-
-               if (meta.dataset) {
-                       meta.dataset.draw(ctx, area, start, count);
-               }
-
-               for (i = start; i < start + count; ++i) {
-                       const element = elements[i];
-                       if (element.active) {
-                               active.push(element);
-                       } else {
-                               element.draw(ctx, area);
-                       }
-               }
-
-               for (i = 0; i < active.length; ++i) {
-                       active[i].draw(ctx, area);
-               }
-       }
-
-       /**
+  update(mode) {} // eslint-disable-line no-unused-vars
+
+  draw() {
+    const me = this;
+    const ctx = me._ctx;
+    const chart = me.chart;
+    const meta = me._cachedMeta;
+    const elements = meta.data || [];
+    const area = chart.chartArea;
+    const active = [];
+    const start = me._drawStart || 0;
+    const count = me._drawCount || (elements.length - start);
+    let i;
+
+    if (meta.dataset) {
+      meta.dataset.draw(ctx, area, start, count);
+    }
+
+    for (i = start; i < start + count; ++i) {
+      const element = elements[i];
+      if (element.active) {
+        active.push(element);
+      } else {
+        element.draw(ctx, area);
+      }
+    }
+
+    for (i = 0; i < active.length; ++i) {
+      active[i].draw(ctx, area);
+    }
+  }
+
+  /**
         * @private
         */
-       _addAutomaticHoverColors(index, options) {
-               const me = this;
-               const normalOptions = me.getStyle(index);
-               const missingColors = Object.keys(normalOptions).filter(key => key.indexOf('Color') !== -1 && !(key in options));
-               let i = missingColors.length - 1;
-               let color;
-               for (; i >= 0; i--) {
-                       color = missingColors[i];
-                       options[color] = getHoverColor(normalOptions[color]);
-               }
-       }
-
-       /**
+  _addAutomaticHoverColors(index, options) {
+    const me = this;
+    const normalOptions = me.getStyle(index);
+    const missingColors = Object.keys(normalOptions).filter(key => key.indexOf('Color') !== -1 && !(key in options));
+    let i = missingColors.length - 1;
+    let color;
+    for (; i >= 0; i--) {
+      color = missingColors[i];
+      options[color] = getHoverColor(normalOptions[color]);
+    }
+  }
+
+  /**
         * Returns a set of predefined style properties that should be used to represent the dataset
         * or the data if the index is specified
         * @param {number} index - data index
         * @param {boolean} [active] - true if hover
         * @return {object} style object
         */
-       getStyle(index, active) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const dataset = meta.dataset;
-
-               if (!me._config) {
-                       me.configure();
-               }
-
-               const options = dataset && index === undefined
-                       ? me.resolveDatasetElementOptions(active)
-                       : me.resolveDataElementOptions(index || 0, active && 'active');
-               if (active) {
-                       me._addAutomaticHoverColors(index, options);
-               }
-
-               return options;
-       }
-
-       /**
+  getStyle(index, active) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const dataset = meta.dataset;
+
+    if (!me._config) {
+      me.configure();
+    }
+
+    const options = dataset && index === undefined
+      ? me.resolveDatasetElementOptions(active)
+      : me.resolveDataElementOptions(index || 0, active && 'active');
+    if (active) {
+      me._addAutomaticHoverColors(index, options);
+    }
+
+    return options;
+  }
+
+  /**
         * @protected
         */
-       getContext(index, active) {
-               const me = this;
-               const dataset = me.getDataset();
-               let context;
-               if (index >= 0 && index < me._cachedMeta.data.length) {
-                       const element = me._cachedMeta.data[index];
-                       context = element.$context ||
+  getContext(index, active) {
+    const me = this;
+    const dataset = me.getDataset();
+    let context;
+    if (index >= 0 && index < me._cachedMeta.data.length) {
+      const element = me._cachedMeta.data[index];
+      context = element.$context ||
                                (element.$context = createDataContext(me.getContext(), index, me.getParsed(index), dataset.data[index], element));
-               } else {
-                       context = me.$context || (me.$context = createDatasetContext(me.chart.getContext(), me.index, dataset));
-               }
+    } else {
+      context = me.$context || (me.$context = createDatasetContext(me.chart.getContext(), me.index, dataset));
+    }
 
-               context.active = !!active;
-               return context;
-       }
+    context.active = !!active;
+    return context;
+  }
 
-       /**
+  /**
         * @param {boolean} [active]
         * @protected
         */
-       resolveDatasetElementOptions(active) {
-               return this._resolveOptions(this.datasetElementOptions, {
-                       active,
-                       type: this.datasetElementType.id
-               });
-       }
-
-       /**
+  resolveDatasetElementOptions(active) {
+    return this._resolveOptions(this.datasetElementOptions, {
+      active,
+      type: this.datasetElementType.id
+    });
+  }
+
+  /**
         * @param {number} index
         * @param {string} [mode]
         * @protected
         */
-       resolveDataElementOptions(index, mode) {
-               mode = mode || 'default';
-               const me = this;
-               const active = mode === 'active';
-               const cache = me._cachedDataOpts;
-               const cached = cache[mode];
-               const sharing = me.enableOptionSharing;
-               if (cached) {
-                       return cloneIfNotShared(cached, sharing);
-               }
-               const info = {cacheable: !active};
-
-               const values = me._resolveOptions(me.dataElementOptions, {
-                       index,
-                       active,
-                       info,
-                       type: me.dataElementType.id
-               });
-
-               if (info.cacheable) {
-                       // `$shared` indicates this set of options can be shared between multiple elements.
-                       // Sharing is used to reduce number of properties to change during animation.
-                       values.$shared = sharing;
-
-                       // We cache options by `mode`, which can be 'active' for example. This enables us
-                       // to have the 'active' element options and 'default' options to switch between
-                       // when interacting.
-                       // We freeze a clone of this object, so the returned values are not frozen.
-                       cache[mode] = Object.freeze(Object.assign({}, values));
-               }
-
-               return values;
-       }
-
-       /**
+  resolveDataElementOptions(index, mode) {
+    mode = mode || 'default';
+    const me = this;
+    const active = mode === 'active';
+    const cache = me._cachedDataOpts;
+    const cached = cache[mode];
+    const sharing = me.enableOptionSharing;
+    if (cached) {
+      return cloneIfNotShared(cached, sharing);
+    }
+    const info = {cacheable: !active};
+
+    const values = me._resolveOptions(me.dataElementOptions, {
+      index,
+      active,
+      info,
+      type: me.dataElementType.id
+    });
+
+    if (info.cacheable) {
+      // `$shared` indicates this set of options can be shared between multiple elements.
+      // Sharing is used to reduce number of properties to change during animation.
+      values.$shared = sharing;
+
+      // We cache options by `mode`, which can be 'active' for example. This enables us
+      // to have the 'active' element options and 'default' options to switch between
+      // when interacting.
+      // We freeze a clone of this object, so the returned values are not frozen.
+      cache[mode] = Object.freeze(Object.assign({}, values));
+    }
+
+    return values;
+  }
+
+  /**
         * @private
         */
-       _resolveOptions(optionNames, args) {
-               const me = this;
-               const {index, active, type, info} = args;
-               const datasetOpts = me._config;
-               const options = me.chart.options.elements[type] || {};
-               const values = {};
-               const context = me.getContext(index, active);
-               const keys = optionKeys(optionNames);
-
-               for (let i = 0, ilen = keys.length; i < ilen; ++i) {
-                       const key = keys[i];
-                       const readKey = optionKey(key, active);
-                       const value = resolve([
-                               datasetOpts[optionNames[readKey]],
-                               datasetOpts[readKey],
-                               options[readKey]
-                       ], context, index, info);
-
-                       if (value !== undefined) {
-                               values[key] = value;
-                       }
-               }
-
-               return values;
-       }
-
-       /**
+  _resolveOptions(optionNames, args) {
+    const me = this;
+    const {index, active, type, info} = args;
+    const datasetOpts = me._config;
+    const options = me.chart.options.elements[type] || {};
+    const values = {};
+    const context = me.getContext(index, active);
+    const keys = optionKeys(optionNames);
+
+    for (let i = 0, ilen = keys.length; i < ilen; ++i) {
+      const key = keys[i];
+      const readKey = optionKey(key, active);
+      const value = resolve([
+        datasetOpts[optionNames[readKey]],
+        datasetOpts[readKey],
+        options[readKey]
+      ], context, index, info);
+
+      if (value !== undefined) {
+        values[key] = value;
+      }
+    }
+
+    return values;
+  }
+
+  /**
         * @private
         */
-       _resolveAnimations(index, mode, active) {
-               const me = this;
-               const chart = me.chart;
-               const cached = me._cachedAnimations;
-               mode = mode || 'default';
+  _resolveAnimations(index, mode, active) {
+    const me = this;
+    const chart = me.chart;
+    const cached = me._cachedAnimations;
+    mode = mode || 'default';
 
-               if (cached[mode]) {
-                       return cached[mode];
-               }
+    if (cached[mode]) {
+      return cached[mode];
+    }
 
-               const info = {cacheable: true};
-               const context = me.getContext(index, active);
-               const chartAnim = resolve([chart.options.animation], context, index, info);
-               const datasetAnim = resolve([me._config.animation], context, index, info);
-               let config = chartAnim && mergeIf({}, [datasetAnim, chartAnim]);
+    const info = {cacheable: true};
+    const context = me.getContext(index, active);
+    const chartAnim = resolve([chart.options.animation], context, index, info);
+    const datasetAnim = resolve([me._config.animation], context, index, info);
+    let config = chartAnim && mergeIf({}, [datasetAnim, chartAnim]);
 
-               if (config[mode]) {
-                       config = Object.assign({}, config, config[mode]);
-               }
+    if (config[mode]) {
+      config = Object.assign({}, config, config[mode]);
+    }
 
-               const animations = new Animations(chart, config);
+    const animations = new Animations(chart, config);
 
-               if (info.cacheable) {
-                       cached[mode] = animations && Object.freeze(animations);
-               }
+    if (info.cacheable) {
+      cached[mode] = animations && Object.freeze(animations);
+    }
 
-               return animations;
-       }
+    return animations;
+  }
 
-       /**
+  /**
         * Utility for getting the options object shared between elements
         * @protected
         */
-       getSharedOptions(options) {
-               if (!options.$shared) {
-                       return;
-               }
-               return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
-       }
-
-       /**
+  getSharedOptions(options) {
+    if (!options.$shared) {
+      return;
+    }
+    return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
+  }
+
+  /**
         * Utility for determining if `options` should be included in the updated properties
         * @protected
         */
-       includeOptions(mode, sharedOptions) {
-               return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
-       }
+  includeOptions(mode, sharedOptions) {
+    return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
+  }
 
-       /**
+  /**
         * Utility for updating an element with new properties, using animations when appropriate.
         * @protected
         */
-       updateElement(element, index, properties, mode) {
-               if (isDirectUpdateMode(mode)) {
-                       Object.assign(element, properties);
-               } else {
-                       this._resolveAnimations(index, mode).update(element, properties);
-               }
-       }
-
-       /**
+  updateElement(element, index, properties, mode) {
+    if (isDirectUpdateMode(mode)) {
+      Object.assign(element, properties);
+    } else {
+      this._resolveAnimations(index, mode).update(element, properties);
+    }
+  }
+
+  /**
         * Utility to animate the shared options, that are potentially affecting multiple elements.
         * @protected
         */
-       updateSharedOptions(sharedOptions, mode, newOptions) {
-               if (sharedOptions) {
-                       this._resolveAnimations(undefined, mode).update({options: sharedOptions}, {options: newOptions});
-               }
-       }
+  updateSharedOptions(sharedOptions, mode, newOptions) {
+    if (sharedOptions) {
+      this._resolveAnimations(undefined, mode).update({options: sharedOptions}, {options: newOptions});
+    }
+  }
 
-       /**
+  /**
         * @private
         */
-       _setStyle(element, index, mode, active) {
-               element.active = active;
-               const options = this.getStyle(index, active);
-               this._resolveAnimations(index, mode, active).update(element, {options: this.getSharedOptions(options) || options});
-       }
+  _setStyle(element, index, mode, active) {
+    element.active = active;
+    const options = this.getStyle(index, active);
+    this._resolveAnimations(index, mode, active).update(element, {options: this.getSharedOptions(options) || options});
+  }
 
-       removeHoverStyle(element, datasetIndex, index) {
-               this._setStyle(element, index, 'active', false);
-       }
+  removeHoverStyle(element, datasetIndex, index) {
+    this._setStyle(element, index, 'active', false);
+  }
 
-       setHoverStyle(element, datasetIndex, index) {
-               this._setStyle(element, index, 'active', true);
-       }
+  setHoverStyle(element, datasetIndex, index) {
+    this._setStyle(element, index, 'active', true);
+  }
 
-       /**
+  /**
         * @private
         */
-       _removeDatasetHoverStyle() {
-               const element = this._cachedMeta.dataset;
+  _removeDatasetHoverStyle() {
+    const element = this._cachedMeta.dataset;
 
-               if (element) {
-                       this._setStyle(element, undefined, 'active', false);
-               }
-       }
+    if (element) {
+      this._setStyle(element, undefined, 'active', false);
+    }
+  }
 
-       /**
+  /**
         * @private
         */
-       _setDatasetHoverStyle() {
-               const element = this._cachedMeta.dataset;
+  _setDatasetHoverStyle() {
+    const element = this._cachedMeta.dataset;
 
-               if (element) {
-                       this._setStyle(element, undefined, 'active', true);
-               }
-       }
+    if (element) {
+      this._setStyle(element, undefined, 'active', true);
+    }
+  }
 
-       /**
+  /**
         * @private
         */
-       _resyncElements(resetNewElements) {
-               const me = this;
-               const numMeta = me._cachedMeta.data.length;
-               const numData = me._data.length;
-
-               if (numData > numMeta) {
-                       me._insertElements(numMeta, numData - numMeta, resetNewElements);
-               } else if (numData < numMeta) {
-                       me._removeElements(numData, numMeta - numData);
-               }
-               // Re-parse the old elements (new elements are parsed in _insertElements)
-               const count = Math.min(numData, numMeta);
-               if (count) {
-                       me.parse(0, count);
-               }
-       }
-
-       /**
+  _resyncElements(resetNewElements) {
+    const me = this;
+    const numMeta = me._cachedMeta.data.length;
+    const numData = me._data.length;
+
+    if (numData > numMeta) {
+      me._insertElements(numMeta, numData - numMeta, resetNewElements);
+    } else if (numData < numMeta) {
+      me._removeElements(numData, numMeta - numData);
+    }
+    // Re-parse the old elements (new elements are parsed in _insertElements)
+    const count = Math.min(numData, numMeta);
+    if (count) {
+      me.parse(0, count);
+    }
+  }
+
+  /**
         * @private
         */
-       _insertElements(start, count, resetNewElements = true) {
-               const me = this;
-               const meta = me._cachedMeta;
-               const data = meta.data;
-               const end = start + count;
-               let i;
-
-               const move = (arr) => {
-                       arr.length += count;
-                       for (i = arr.length - 1; i >= end; i--) {
-                               arr[i] = arr[i - count];
-                       }
-               };
-               move(data);
-
-               for (i = start; i < end; ++i) {
-                       data[i] = new me.dataElementType();
-               }
-
-               if (me._parsing) {
-                       move(meta._parsed);
-               }
-               me.parse(start, count);
-
-               if (resetNewElements) {
-                       me.updateElements(data, start, count, 'reset');
-               }
-       }
-
-       updateElements(element, start, count, mode) {} // eslint-disable-line no-unused-vars
-
-       /**
+  _insertElements(start, count, resetNewElements = true) {
+    const me = this;
+    const meta = me._cachedMeta;
+    const data = meta.data;
+    const end = start + count;
+    let i;
+
+    const move = (arr) => {
+      arr.length += count;
+      for (i = arr.length - 1; i >= end; i--) {
+        arr[i] = arr[i - count];
+      }
+    };
+    move(data);
+
+    for (i = start; i < end; ++i) {
+      data[i] = new me.dataElementType();
+    }
+
+    if (me._parsing) {
+      move(meta._parsed);
+    }
+    me.parse(start, count);
+
+    if (resetNewElements) {
+      me.updateElements(data, start, count, 'reset');
+    }
+  }
+
+  updateElements(element, start, count, mode) {} // eslint-disable-line no-unused-vars
+
+  /**
         * @private
         */
-       _removeElements(start, count) {
-               const me = this;
-               const meta = me._cachedMeta;
-               if (me._parsing) {
-                       const removed = meta._parsed.splice(start, count);
-                       if (meta._stacked) {
-                               clearStacks(meta, removed);
-                       }
-               }
-               meta.data.splice(start, count);
-       }
-
-
-       /**
+  _removeElements(start, count) {
+    const me = this;
+    const meta = me._cachedMeta;
+    if (me._parsing) {
+      const removed = meta._parsed.splice(start, count);
+      if (meta._stacked) {
+        clearStacks(meta, removed);
+      }
+    }
+    meta.data.splice(start, count);
+  }
+
+
+  /**
         * @private
         */
-       _onDataPush() {
-               const count = arguments.length;
-               this._insertElements(this.getDataset().data.length - count, count);
-       }
+  _onDataPush() {
+    const count = arguments.length;
+    this._insertElements(this.getDataset().data.length - count, count);
+  }
 
-       /**
+  /**
         * @private
         */
-       _onDataPop() {
-               this._removeElements(this._cachedMeta.data.length - 1, 1);
-       }
+  _onDataPop() {
+    this._removeElements(this._cachedMeta.data.length - 1, 1);
+  }
 
-       /**
+  /**
         * @private
         */
-       _onDataShift() {
-               this._removeElements(0, 1);
-       }
+  _onDataShift() {
+    this._removeElements(0, 1);
+  }
 
-       /**
+  /**
         * @private
         */
-       _onDataSplice(start, count) {
-               this._removeElements(start, count);
-               this._insertElements(start, arguments.length - 2);
-       }
+  _onDataSplice(start, count) {
+    this._removeElements(start, count);
+    this._insertElements(start, arguments.length - 2);
+  }
 
-       /**
+  /**
         * @private
         */
-       _onDataUnshift() {
-               this._insertElements(0, arguments.length);
-       }
+  _onDataUnshift() {
+    this._insertElements(0, arguments.length);
+  }
 }
 
 /**
@@ -1095,13 +1095,13 @@ DatasetController.prototype.dataElementType = null;
  * @type {string[]}
  */
 DatasetController.prototype.datasetElementOptions = [
-       'backgroundColor',
-       'borderCapStyle',
-       'borderColor',
-       'borderDash',
-       'borderDashOffset',
-       'borderJoinStyle',
-       'borderWidth'
+  'backgroundColor',
+  'borderCapStyle',
+  'borderColor',
+  'borderDash',
+  'borderDashOffset',
+  'borderJoinStyle',
+  'borderWidth'
 ];
 
 /**
@@ -1111,8 +1111,8 @@ DatasetController.prototype.datasetElementOptions = [
  * @type {string[]|object}
  */
 DatasetController.prototype.dataElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderWidth',
-       'pointStyle'
+  'backgroundColor',
+  'borderColor',
+  'borderWidth',
+  'pointStyle'
 ];
index 8e0a42773600e1fc3825cf280703ec2e010c5b91..14b16e1c4f094687f2cb68e2ad0be78e17763179 100644 (file)
@@ -6,15 +6,15 @@ import {isObject, merge, valueOrDefault} from '../helpers/helpers.core';
  * @return {object}
  */
 function getScope(node, key) {
-       if (!key) {
-               return node;
-       }
-       const keys = key.split('.');
-       for (let i = 0, n = keys.length; i < n; ++i) {
-               const k = keys[i];
-               node = node[k] || (node[k] = Object.create(null));
-       }
-       return node;
+  if (!key) {
+    return node;
+  }
+  const keys = key.split('.');
+  for (let i = 0, n = keys.length; i < n; ++i) {
+    const k = keys[i];
+    node = node[k] || (node[k] = Object.create(null));
+  }
+  return node;
 }
 
 /**
@@ -22,62 +22,62 @@ function getScope(node, key) {
  * Note: class is exported for typedoc
  */
 export class Defaults {
-       constructor() {
-               this.backgroundColor = 'rgba(0,0,0,0.1)';
-               this.borderColor = 'rgba(0,0,0,0.1)';
-               this.color = '#666';
-               this.controllers = {};
-               this.elements = {};
-               this.events = [
-                       'mousemove',
-                       'mouseout',
-                       'click',
-                       'touchstart',
-                       'touchmove'
-               ];
-               this.font = {
-                       family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
-                       size: 12,
-                       style: 'normal',
-                       lineHeight: 1.2,
-                       weight: null
-               };
-               this.hover = {
-                       onHover: null
-               };
-               this.interaction = {
-                       mode: 'nearest',
-                       intersect: true
-               };
-               this.maintainAspectRatio = true;
-               this.onHover = null;
-               this.onClick = null;
-               this.plugins = {};
-               this.responsive = true;
-               this.scale = undefined;
-               this.scales = {};
-               this.showLine = true;
-       }
+  constructor() {
+    this.backgroundColor = 'rgba(0,0,0,0.1)';
+    this.borderColor = 'rgba(0,0,0,0.1)';
+    this.color = '#666';
+    this.controllers = {};
+    this.elements = {};
+    this.events = [
+      'mousemove',
+      'mouseout',
+      'click',
+      'touchstart',
+      'touchmove'
+    ];
+    this.font = {
+      family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+      size: 12,
+      style: 'normal',
+      lineHeight: 1.2,
+      weight: null
+    };
+    this.hover = {
+      onHover: null
+    };
+    this.interaction = {
+      mode: 'nearest',
+      intersect: true
+    };
+    this.maintainAspectRatio = true;
+    this.onHover = null;
+    this.onClick = null;
+    this.plugins = {};
+    this.responsive = true;
+    this.scale = undefined;
+    this.scales = {};
+    this.showLine = true;
+  }
 
-       /**
+  /**
         * @param {string|object} scope
         * @param {object} [values]
         */
-       set(scope, values) {
-               if (typeof scope === 'string') {
-                       return merge(getScope(this, scope), values);
-               }
-               return merge(getScope(this, ''), scope);
-       }
+  set(scope, values) {
+    if (typeof scope === 'string') {
+      return merge(getScope(this, scope), values);
+    }
+    return merge(getScope(this, ''), scope);
+  }
 
-       /**
+  /**
         * @param {string} scope
         */
-       get(scope) {
-               return getScope(this, scope);
-       }
+  get(scope) {
+    return getScope(this, scope);
+  }
 
-       /**
+  /**
         * Routes the named defaults to fallback to another scope/name.
         * This routing is useful when those target values, like defaults.color, are changed runtime.
         * If the values would be copied, the runtime change would not take effect. By routing, the
@@ -94,34 +94,34 @@ export class Defaults {
         * Empty string ('') is the root of defaults.
         * @param {string} targetName The target name in the target scope the property should be routed to.
         */
-       route(scope, name, targetScope, targetName) {
-               const scopeObject = getScope(this, scope);
-               const targetScopeObject = getScope(this, targetScope);
-               const privateName = '_' + name;
+  route(scope, name, targetScope, targetName) {
+    const scopeObject = getScope(this, scope);
+    const targetScopeObject = getScope(this, targetScope);
+    const privateName = '_' + name;
 
-               Object.defineProperties(scopeObject, {
-                       // A private property is defined to hold the actual value, when this property is set in its scope (set in the setter)
-                       [privateName]: {
-                               value: scopeObject[name],
-                               writable: true
-                       },
-                       // The actual property is defined as getter/setter so we can do the routing when value is not locally set.
-                       [name]: {
-                               enumerable: true,
-                               get() {
-                                       const local = this[privateName];
-                                       const target = targetScopeObject[targetName];
-                                       if (isObject(local)) {
-                                               return Object.assign({}, target, local);
-                                       }
-                                       return valueOrDefault(local, target);
-                               },
-                               set(value) {
-                                       this[privateName] = value;
-                               }
-                       }
-               });
-       }
+    Object.defineProperties(scopeObject, {
+      // A private property is defined to hold the actual value, when this property is set in its scope (set in the setter)
+      [privateName]: {
+        value: scopeObject[name],
+        writable: true
+      },
+      // The actual property is defined as getter/setter so we can do the routing when value is not locally set.
+      [name]: {
+        enumerable: true,
+        get() {
+          const local = this[privateName];
+          const target = targetScopeObject[targetName];
+          if (isObject(local)) {
+            return Object.assign({}, target, local);
+          }
+          return valueOrDefault(local, target);
+        },
+        set(value) {
+          this[privateName] = value;
+        }
+      }
+    });
+  }
 }
 
 // singleton instance
index aefa1d918d4150cd10494bbade3364edf030091e..dc119dfcda33f372149cf48c33b7f90eae3503e6 100644 (file)
@@ -2,45 +2,45 @@ import {isNumber} from '../helpers/helpers.math';
 
 export default class Element {
 
-       constructor() {
-               this.x = undefined;
-               this.y = undefined;
-               this.active = false;
-               this.options = undefined;
-               this.$animations = undefined;
-       }
+  constructor() {
+    this.x = undefined;
+    this.y = undefined;
+    this.active = false;
+    this.options = undefined;
+    this.$animations = undefined;
+  }
 
-       /**
+  /**
         * @param {boolean} [useFinalPosition]
         */
-       tooltipPosition(useFinalPosition) {
-               const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
-               return {x, y};
-       }
+  tooltipPosition(useFinalPosition) {
+    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+    return {x, y};
+  }
 
-       hasValue() {
-               return isNumber(this.x) && isNumber(this.y);
-       }
+  hasValue() {
+    return isNumber(this.x) && isNumber(this.y);
+  }
 
-       /**
+  /**
         * Gets the current or final value of each prop. Can return extra properties (whole object).
         * @param {string[]} props - properties to get
         * @param {boolean} [final] - get the final value (animation target)
         * @return {object}
         */
-       getProps(props, final) {
-               const me = this;
-               const anims = this.$animations;
-               if (!final || !anims) {
-                       // let's not create an object, if not needed
-                       return me;
-               }
-               const ret = {};
-               props.forEach(prop => {
-                       ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : me[prop];
-               });
-               return ret;
-       }
+  getProps(props, final) {
+    const me = this;
+    const anims = this.$animations;
+    if (!final || !anims) {
+      // let's not create an object, if not needed
+      return me;
+    }
+    const ret = {};
+    props.forEach(prop => {
+      ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : me[prop];
+    });
+    return ret;
+  }
 }
 
 /**
index abcd5ca67f5a4770d52d3593e057cd25507377a9..10db9f487de90542882c279f47e75327ededc8f7 100644 (file)
@@ -16,14 +16,14 @@ import {getRelativePosition as helpersGetRelativePosition} from '../helpers/help
  * @returns {object} the event position
  */
 function getRelativePosition(e, chart) {
-       if ('native' in e) {
-               return {
-                       x: e.x,
-                       y: e.y
-               };
-       }
-
-       return helpersGetRelativePosition(e, chart);
+  if ('native' in e) {
+    return {
+      x: e.x,
+      y: e.y
+    };
+  }
+
+  return helpersGetRelativePosition(e, chart);
 }
 
 /**
@@ -32,18 +32,18 @@ function getRelativePosition(e, chart) {
  * @param {function} handler - the callback to execute for each visible item
  */
 function evaluateAllVisibleItems(chart, handler) {
-       const metasets = chart.getSortedVisibleDatasetMetas();
-       let index, data, element;
-
-       for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
-               ({index, data} = metasets[i]);
-               for (let j = 0, jlen = data.length; j < jlen; ++j) {
-                       element = data[j];
-                       if (!element.skip) {
-                               handler(element, index, j);
-                       }
-               }
-       }
+  const metasets = chart.getSortedVisibleDatasetMetas();
+  let index, data, element;
+
+  for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
+    ({index, data} = metasets[i]);
+    for (let j = 0, jlen = data.length; j < jlen; ++j) {
+      element = data[j];
+      if (!element.skip) {
+        handler(element, index, j);
+      }
+    }
+  }
 }
 
 /**
@@ -55,27 +55,27 @@ function evaluateAllVisibleItems(chart, handler) {
  * @returns {{lo:number, hi:number}} indices to search data array between
  */
 function binarySearch(metaset, axis, value, intersect) {
-       const {controller, data, _sorted} = metaset;
-       const iScale = controller._cachedMeta.iScale;
-       if (iScale && axis === iScale.axis && _sorted && data.length) {
-               const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;
-               if (!intersect) {
-                       return lookupMethod(data, axis, value);
-               } else if (controller._sharedOptions) {
-                       // _sharedOptions indicates that each element has equal options -> equal proportions
-                       // So we can do a ranged binary search based on the range of first element and
-                       // be confident to get the full range of indices that can intersect with the value.
-                       const el = data[0];
-                       const range = typeof el.getRange === 'function' && el.getRange(axis);
-                       if (range) {
-                               const start = lookupMethod(data, axis, value - range);
-                               const end = lookupMethod(data, axis, value + range);
-                               return {lo: start.lo, hi: end.hi};
-                       }
-               }
-       }
-       // Default to all elements, when binary search can not be used.
-       return {lo: 0, hi: data.length - 1};
+  const {controller, data, _sorted} = metaset;
+  const iScale = controller._cachedMeta.iScale;
+  if (iScale && axis === iScale.axis && _sorted && data.length) {
+    const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;
+    if (!intersect) {
+      return lookupMethod(data, axis, value);
+    } else if (controller._sharedOptions) {
+      // _sharedOptions indicates that each element has equal options -> equal proportions
+      // So we can do a ranged binary search based on the range of first element and
+      // be confident to get the full range of indices that can intersect with the value.
+      const el = data[0];
+      const range = typeof el.getRange === 'function' && el.getRange(axis);
+      if (range) {
+        const start = lookupMethod(data, axis, value - range);
+        const end = lookupMethod(data, axis, value + range);
+        return {lo: start.lo, hi: end.hi};
+      }
+    }
+  }
+  // Default to all elements, when binary search can not be used.
+  return {lo: 0, hi: data.length - 1};
 }
 
 /**
@@ -87,18 +87,18 @@ function binarySearch(metaset, axis, value, intersect) {
  * @param {boolean} [intersect] - consider intersecting items
  */
 function optimizedEvaluateItems(chart, axis, position, handler, intersect) {
-       const metasets = chart.getSortedVisibleDatasetMetas();
-       const value = position[axis];
-       for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
-               const {index, data} = metasets[i];
-               const {lo, hi} = binarySearch(metasets[i], axis, value, intersect);
-               for (let j = lo; j <= hi; ++j) {
-                       const element = data[j];
-                       if (!element.skip) {
-                               handler(element, index, j);
-                       }
-               }
-       }
+  const metasets = chart.getSortedVisibleDatasetMetas();
+  const value = position[axis];
+  for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
+    const {index, data} = metasets[i];
+    const {lo, hi} = binarySearch(metasets[i], axis, value, intersect);
+    for (let j = lo; j <= hi; ++j) {
+      const element = data[j];
+      if (!element.skip) {
+        handler(element, index, j);
+      }
+    }
+  }
 }
 
 /**
@@ -107,14 +107,14 @@ function optimizedEvaluateItems(chart, axis, position, handler, intersect) {
  * @param {string} axis - the axis mode. x|y|xy
  */
 function getDistanceMetricForAxis(axis) {
-       const useX = axis.indexOf('x') !== -1;
-       const useY = axis.indexOf('y') !== -1;
-
-       return function(pt1, pt2) {
-               const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
-               const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
-               return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
-       };
+  const useX = axis.indexOf('x') !== -1;
+  const useY = axis.indexOf('y') !== -1;
+
+  return function(pt1, pt2) {
+    const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
+    const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
+    return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
+  };
 }
 
 /**
@@ -126,20 +126,20 @@ function getDistanceMetricForAxis(axis) {
  * @return {InteractionItem[]} the nearest items
  */
 function getIntersectItems(chart, position, axis, useFinalPosition) {
-       const items = [];
+  const items = [];
 
-       if (!_isPointInArea(position, chart.chartArea)) {
-               return items;
-       }
+  if (!_isPointInArea(position, chart.chartArea)) {
+    return items;
+  }
 
-       const evaluationFunc = function(element, datasetIndex, index) {
-               if (element.inRange(position.x, position.y, useFinalPosition)) {
-                       items.push({element, datasetIndex, index});
-               }
-       };
+  const evaluationFunc = function(element, datasetIndex, index) {
+    if (element.inRange(position.x, position.y, useFinalPosition)) {
+      items.push({element, datasetIndex, index});
+    }
+  };
 
-       optimizedEvaluateItems(chart, axis, position, evaluationFunc, true);
-       return items;
+  optimizedEvaluateItems(chart, axis, position, evaluationFunc, true);
+  return items;
 }
 
 /**
@@ -152,57 +152,57 @@ function getIntersectItems(chart, position, axis, useFinalPosition) {
  * @return {InteractionItem[]} the nearest items
  */
 function getNearestItems(chart, position, axis, intersect, useFinalPosition) {
-       const distanceMetric = getDistanceMetricForAxis(axis);
-       let minDistance = Number.POSITIVE_INFINITY;
-       let items = [];
-
-       if (!_isPointInArea(position, chart.chartArea)) {
-               return items;
-       }
-
-       const evaluationFunc = function(element, datasetIndex, index) {
-               if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) {
-                       return;
-               }
-
-               const center = element.getCenterPoint(useFinalPosition);
-               const distance = distanceMetric(position, center);
-               if (distance < minDistance) {
-                       items = [{element, datasetIndex, index}];
-                       minDistance = distance;
-               } else if (distance === minDistance) {
-                       // Can have multiple items at the same distance in which case we sort by size
-                       items.push({element, datasetIndex, index});
-               }
-       };
-
-       optimizedEvaluateItems(chart, axis, position, evaluationFunc);
-       return items;
+  const distanceMetric = getDistanceMetricForAxis(axis);
+  let minDistance = Number.POSITIVE_INFINITY;
+  let items = [];
+
+  if (!_isPointInArea(position, chart.chartArea)) {
+    return items;
+  }
+
+  const evaluationFunc = function(element, datasetIndex, index) {
+    if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) {
+      return;
+    }
+
+    const center = element.getCenterPoint(useFinalPosition);
+    const distance = distanceMetric(position, center);
+    if (distance < minDistance) {
+      items = [{element, datasetIndex, index}];
+      minDistance = distance;
+    } else if (distance === minDistance) {
+      // Can have multiple items at the same distance in which case we sort by size
+      items.push({element, datasetIndex, index});
+    }
+  };
+
+  optimizedEvaluateItems(chart, axis, position, evaluationFunc);
+  return items;
 }
 
 function getAxisItems(chart, e, options, useFinalPosition) {
-       const position = getRelativePosition(e, chart);
-       const items = [];
-       const axis = options.axis;
-       const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
-       let intersectsItem = false;
-
-       evaluateAllVisibleItems(chart, (element, datasetIndex, index) => {
-               if (element[rangeMethod](position[axis], useFinalPosition)) {
-                       items.push({element, datasetIndex, index});
-               }
-
-               if (element.inRange(position.x, position.y, useFinalPosition)) {
-                       intersectsItem = true;
-               }
-       });
-
-       // If we want to trigger on an intersect and we don't have any items
-       // that intersect the position, return nothing
-       if (options.intersect && !intersectsItem) {
-               return [];
-       }
-       return items;
+  const position = getRelativePosition(e, chart);
+  const items = [];
+  const axis = options.axis;
+  const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
+  let intersectsItem = false;
+
+  evaluateAllVisibleItems(chart, (element, datasetIndex, index) => {
+    if (element[rangeMethod](position[axis], useFinalPosition)) {
+      items.push({element, datasetIndex, index});
+    }
+
+    if (element.inRange(position.x, position.y, useFinalPosition)) {
+      intersectsItem = true;
+    }
+  });
+
+  // If we want to trigger on an intersect and we don't have any items
+  // that intersect the position, return nothing
+  if (options.intersect && !intersectsItem) {
+    return [];
+  }
+  return items;
 }
 
 /**
@@ -210,9 +210,9 @@ function getAxisItems(chart, e, options, useFinalPosition) {
  * @namespace Chart.Interaction
  */
 export default {
-       // Helper function for different modes
-       modes: {
-               /**
+  // Helper function for different modes
+  modes: {
+    /**
                 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
                 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
                 * @function Chart.Interaction.modes.index
@@ -223,33 +223,33 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               index(chart, e, options, useFinalPosition) {
-                       const position = getRelativePosition(e, chart);
-                       // Default axis for index mode is 'x' to match old behaviour
-                       const axis = options.axis || 'x';
-                       const items = options.intersect
-                               ? getIntersectItems(chart, position, axis, useFinalPosition)
-                               : getNearestItems(chart, position, axis, false, useFinalPosition);
-                       const elements = [];
-
-                       if (!items.length) {
-                               return [];
-                       }
-
-                       chart.getSortedVisibleDatasetMetas().forEach((meta) => {
-                               const index = items[0].index;
-                               const element = meta.data[index];
-
-                               // don't count items that are skipped (null data)
-                               if (element && !element.skip) {
-                                       elements.push({element, datasetIndex: meta.index, index});
-                               }
-                       });
-
-                       return elements;
-               },
-
-               /**
+    index(chart, e, options, useFinalPosition) {
+      const position = getRelativePosition(e, chart);
+      // Default axis for index mode is 'x' to match old behaviour
+      const axis = options.axis || 'x';
+      const items = options.intersect
+        ? getIntersectItems(chart, position, axis, useFinalPosition)
+        : getNearestItems(chart, position, axis, false, useFinalPosition);
+      const elements = [];
+
+      if (!items.length) {
+        return [];
+      }
+
+      chart.getSortedVisibleDatasetMetas().forEach((meta) => {
+        const index = items[0].index;
+        const element = meta.data[index];
+
+        // don't count items that are skipped (null data)
+        if (element && !element.skip) {
+          elements.push({element, datasetIndex: meta.index, index});
+        }
+      });
+
+      return elements;
+    },
+
+    /**
                 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
                 * If the options.intersect is false, we find the nearest item and return the items in that dataset
                 * @function Chart.Interaction.modes.dataset
@@ -259,26 +259,26 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               dataset(chart, e, options, useFinalPosition) {
-                       const position = getRelativePosition(e, chart);
-                       const axis = options.axis || 'xy';
-                       let items = options.intersect
-                               ? getIntersectItems(chart, position, axis, useFinalPosition) :
-                               getNearestItems(chart, position, axis, false, useFinalPosition);
-
-                       if (items.length > 0) {
-                               const datasetIndex = items[0].datasetIndex;
-                               const data = chart.getDatasetMeta(datasetIndex).data;
-                               items = [];
-                               for (let i = 0; i < data.length; ++i) {
-                                       items.push({element: data[i], datasetIndex, index: i});
-                               }
-                       }
-
-                       return items;
-               },
-
-               /**
+    dataset(chart, e, options, useFinalPosition) {
+      const position = getRelativePosition(e, chart);
+      const axis = options.axis || 'xy';
+      let items = options.intersect
+        ? getIntersectItems(chart, position, axis, useFinalPosition) :
+        getNearestItems(chart, position, axis, false, useFinalPosition);
+
+      if (items.length > 0) {
+        const datasetIndex = items[0].datasetIndex;
+        const data = chart.getDatasetMeta(datasetIndex).data;
+        items = [];
+        for (let i = 0; i < data.length; ++i) {
+          items.push({element: data[i], datasetIndex, index: i});
+        }
+      }
+
+      return items;
+    },
+
+    /**
                 * Point mode returns all elements that hit test based on the event position
                 * of the event
                 * @function Chart.Interaction.modes.intersect
@@ -288,13 +288,13 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               point(chart, e, options, useFinalPosition) {
-                       const position = getRelativePosition(e, chart);
-                       const axis = options.axis || 'xy';
-                       return getIntersectItems(chart, position, axis, useFinalPosition);
-               },
+    point(chart, e, options, useFinalPosition) {
+      const position = getRelativePosition(e, chart);
+      const axis = options.axis || 'xy';
+      return getIntersectItems(chart, position, axis, useFinalPosition);
+    },
 
-               /**
+    /**
                 * nearest mode returns the element closest to the point
                 * @function Chart.Interaction.modes.intersect
                 * @param {Chart} chart - the chart we are returning items from
@@ -303,13 +303,13 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               nearest(chart, e, options, useFinalPosition) {
-                       const position = getRelativePosition(e, chart);
-                       const axis = options.axis || 'xy';
-                       return getNearestItems(chart, position, axis, options.intersect, useFinalPosition);
-               },
+    nearest(chart, e, options, useFinalPosition) {
+      const position = getRelativePosition(e, chart);
+      const axis = options.axis || 'xy';
+      return getNearestItems(chart, position, axis, options.intersect, useFinalPosition);
+    },
 
-               /**
+    /**
                 * x mode returns the elements that hit-test at the current x coordinate
                 * @function Chart.Interaction.modes.x
                 * @param {Chart} chart - the chart we are returning items from
@@ -318,12 +318,12 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               x(chart, e, options, useFinalPosition) {
-                       options.axis = 'x';
-                       return getAxisItems(chart, e, options, useFinalPosition);
-               },
+    x(chart, e, options, useFinalPosition) {
+      options.axis = 'x';
+      return getAxisItems(chart, e, options, useFinalPosition);
+    },
 
-               /**
+    /**
                 * y mode returns the elements that hit-test at the current y coordinate
                 * @function Chart.Interaction.modes.y
                 * @param {Chart} chart - the chart we are returning items from
@@ -332,9 +332,9 @@ export default {
                 * @param {boolean} [useFinalPosition] - use final element position (animation target)
                 * @return {InteractionItem[]} - items that are found
                 */
-               y(chart, e, options, useFinalPosition) {
-                       options.axis = 'y';
-                       return getAxisItems(chart, e, options, useFinalPosition);
-               }
-       }
+    y(chart, e, options, useFinalPosition) {
+      options.axis = 'y';
+      return getAxisItems(chart, e, options, useFinalPosition);
+    }
+  }
 };
index 88803cda287f705b383ab161ded075931cd4c8d5..176e346be9443cf26149d7c33d6f97dd7673e432 100644 (file)
@@ -2,16 +2,16 @@
 const intlCache = new Map();
 
 export function getNumberFormat(locale, options) {
-       options = options || {};
-       const cacheKey = locale + JSON.stringify(options);
-       let formatter = intlCache.get(cacheKey);
-       if (!formatter) {
-               formatter = new Intl.NumberFormat(locale, options);
-               intlCache.set(cacheKey, formatter);
-       }
-       return formatter;
+  options = options || {};
+  const cacheKey = locale + JSON.stringify(options);
+  let formatter = intlCache.get(cacheKey);
+  if (!formatter) {
+    formatter = new Intl.NumberFormat(locale, options);
+    intlCache.set(cacheKey, formatter);
+  }
+  return formatter;
 }
 
 export function formatNumber(num, locale, options) {
-       return getNumberFormat(locale, options).format(num);
+  return getNumberFormat(locale, options).format(num);
 }
index baf1637baaf8838ae8d22ca01a4d83fbb0efd500..31a4cb618a1cbb53c46bf53cddf8edd17f3ca53c 100644 (file)
@@ -9,208 +9,208 @@ import {toPadding, resolve} from '../helpers/helpers.options';
 const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom'];
 
 function filterByPosition(array, position) {
-       return array.filter(v => v.pos === position);
+  return array.filter(v => v.pos === position);
 }
 
 function filterDynamicPositionByAxis(array, axis) {
-       return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
+  return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
 }
 
 function sortByWeight(array, reverse) {
-       return array.sort((a, b) => {
-               const v0 = reverse ? b : a;
-               const v1 = reverse ? a : b;
-               return v0.weight === v1.weight ?
-                       v0.index - v1.index :
-                       v0.weight - v1.weight;
-       });
+  return array.sort((a, b) => {
+    const v0 = reverse ? b : a;
+    const v1 = reverse ? a : b;
+    return v0.weight === v1.weight ?
+      v0.index - v1.index :
+      v0.weight - v1.weight;
+  });
 }
 
 function wrapBoxes(boxes) {
-       const layoutBoxes = [];
-       let i, ilen, box;
-
-       for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
-               box = boxes[i];
-               layoutBoxes.push({
-                       index: i,
-                       box,
-                       pos: box.position,
-                       horizontal: box.isHorizontal(),
-                       weight: box.weight
-               });
-       }
-       return layoutBoxes;
+  const layoutBoxes = [];
+  let i, ilen, box;
+
+  for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
+    box = boxes[i];
+    layoutBoxes.push({
+      index: i,
+      box,
+      pos: box.position,
+      horizontal: box.isHorizontal(),
+      weight: box.weight
+    });
+  }
+  return layoutBoxes;
 }
 
 function setLayoutDims(layouts, params) {
-       let i, ilen, layout;
-       for (i = 0, ilen = layouts.length; i < ilen; ++i) {
-               layout = layouts[i];
-               // store dimensions used instead of available chartArea in fitBoxes
-               if (layout.horizontal) {
-                       layout.width = layout.box.fullSize && params.availableWidth;
-                       layout.height = params.hBoxMaxHeight;
-               } else {
-                       layout.width = params.vBoxMaxWidth;
-                       layout.height = layout.box.fullSize && params.availableHeight;
-               }
-       }
+  let i, ilen, layout;
+  for (i = 0, ilen = layouts.length; i < ilen; ++i) {
+    layout = layouts[i];
+    // store dimensions used instead of available chartArea in fitBoxes
+    if (layout.horizontal) {
+      layout.width = layout.box.fullSize && params.availableWidth;
+      layout.height = params.hBoxMaxHeight;
+    } else {
+      layout.width = params.vBoxMaxWidth;
+      layout.height = layout.box.fullSize && params.availableHeight;
+    }
+  }
 }
 
 function buildLayoutBoxes(boxes) {
-       const layoutBoxes = wrapBoxes(boxes);
-       const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
-       const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
-       const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
-       const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
-       const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
-       const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
-
-       return {
-               leftAndTop: left.concat(top),
-               rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
-               chartArea: filterByPosition(layoutBoxes, 'chartArea'),
-               vertical: left.concat(right).concat(centerVertical),
-               horizontal: top.concat(bottom).concat(centerHorizontal)
-       };
+  const layoutBoxes = wrapBoxes(boxes);
+  const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
+  const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
+  const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
+  const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
+  const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
+  const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
+
+  return {
+    leftAndTop: left.concat(top),
+    rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
+    chartArea: filterByPosition(layoutBoxes, 'chartArea'),
+    vertical: left.concat(right).concat(centerVertical),
+    horizontal: top.concat(bottom).concat(centerHorizontal)
+  };
 }
 
 function getCombinedMax(maxPadding, chartArea, a, b) {
-       return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
+  return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
 }
 
 function updateDims(chartArea, params, layout) {
-       const box = layout.box;
-       const maxPadding = chartArea.maxPadding;
-
-       if (isObject(layout.pos)) {
-               // dynamically placed boxes are not considered
-               return;
-       }
-       if (layout.size) {
-               // this layout was already counted for, lets first reduce old size
-               chartArea[layout.pos] -= layout.size;
-       }
-       layout.size = layout.horizontal ? Math.min(layout.height, box.height) : Math.min(layout.width, box.width);
-       chartArea[layout.pos] += layout.size;
-
-       if (box.getPadding) {
-               const boxPadding = box.getPadding();
-               maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
-               maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
-               maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
-               maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
-       }
-
-       const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
-       const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
-
-       if (newWidth !== chartArea.w || newHeight !== chartArea.h) {
-               chartArea.w = newWidth;
-               chartArea.h = newHeight;
-
-               // return true if chart area changed in layout's direction
-               return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;
-       }
+  const box = layout.box;
+  const maxPadding = chartArea.maxPadding;
+
+  if (isObject(layout.pos)) {
+    // dynamically placed boxes are not considered
+    return;
+  }
+  if (layout.size) {
+    // this layout was already counted for, lets first reduce old size
+    chartArea[layout.pos] -= layout.size;
+  }
+  layout.size = layout.horizontal ? Math.min(layout.height, box.height) : Math.min(layout.width, box.width);
+  chartArea[layout.pos] += layout.size;
+
+  if (box.getPadding) {
+    const boxPadding = box.getPadding();
+    maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
+    maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
+    maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
+    maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
+  }
+
+  const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
+  const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
+
+  if (newWidth !== chartArea.w || newHeight !== chartArea.h) {
+    chartArea.w = newWidth;
+    chartArea.h = newHeight;
+
+    // return true if chart area changed in layout's direction
+    return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;
+  }
 }
 
 function handleMaxPadding(chartArea) {
-       const maxPadding = chartArea.maxPadding;
-
-       function updatePos(pos) {
-               const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
-               chartArea[pos] += change;
-               return change;
-       }
-       chartArea.y += updatePos('top');
-       chartArea.x += updatePos('left');
-       updatePos('right');
-       updatePos('bottom');
+  const maxPadding = chartArea.maxPadding;
+
+  function updatePos(pos) {
+    const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
+    chartArea[pos] += change;
+    return change;
+  }
+  chartArea.y += updatePos('top');
+  chartArea.x += updatePos('left');
+  updatePos('right');
+  updatePos('bottom');
 }
 
 function getMargins(horizontal, chartArea) {
-       const maxPadding = chartArea.maxPadding;
-
-       function marginForPositions(positions) {
-               const margin = {left: 0, top: 0, right: 0, bottom: 0};
-               positions.forEach((pos) => {
-                       margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
-               });
-               return margin;
-       }
-
-       return horizontal
-               ? marginForPositions(['left', 'right'])
-               : marginForPositions(['top', 'bottom']);
+  const maxPadding = chartArea.maxPadding;
+
+  function marginForPositions(positions) {
+    const margin = {left: 0, top: 0, right: 0, bottom: 0};
+    positions.forEach((pos) => {
+      margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
+    });
+    return margin;
+  }
+
+  return horizontal
+    ? marginForPositions(['left', 'right'])
+    : marginForPositions(['top', 'bottom']);
 }
 
 function fitBoxes(boxes, chartArea, params) {
-       const refitBoxes = [];
-       let i, ilen, layout, box, refit, changed;
-
-       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
-               layout = boxes[i];
-               box = layout.box;
-
-               box.update(
-                       layout.width || chartArea.w,
-                       layout.height || chartArea.h,
-                       getMargins(layout.horizontal, chartArea)
-               );
-               if (updateDims(chartArea, params, layout)) {
-                       changed = true;
-                       if (refitBoxes.length) {
-                               // Dimensions changed and there were non full width boxes before this
-                               // -> we have to refit those
-                               refit = true;
-                       }
-               }
-               if (!box.fullSize) { // fullSize boxes don't need to be re-fitted in any case
-                       refitBoxes.push(layout);
-               }
-       }
-
-       return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;
+  const refitBoxes = [];
+  let i, ilen, layout, box, refit, changed;
+
+  for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+    layout = boxes[i];
+    box = layout.box;
+
+    box.update(
+      layout.width || chartArea.w,
+      layout.height || chartArea.h,
+      getMargins(layout.horizontal, chartArea)
+    );
+    if (updateDims(chartArea, params, layout)) {
+      changed = true;
+      if (refitBoxes.length) {
+        // Dimensions changed and there were non full width boxes before this
+        // -> we have to refit those
+        refit = true;
+      }
+    }
+    if (!box.fullSize) { // fullSize boxes don't need to be re-fitted in any case
+      refitBoxes.push(layout);
+    }
+  }
+
+  return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;
 }
 
 function placeBoxes(boxes, chartArea, params) {
-       const userPadding = params.padding;
-       let x = chartArea.x;
-       let y = chartArea.y;
-       let i, ilen, layout, box;
-
-       for (i = 0, ilen = boxes.length; i < ilen; ++i) {
-               layout = boxes[i];
-               box = layout.box;
-               if (layout.horizontal) {
-                       box.left = box.fullSize ? userPadding.left : chartArea.left;
-                       box.right = box.fullSize ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;
-                       box.top = y;
-                       box.bottom = y + box.height;
-                       box.width = box.right - box.left;
-                       y = box.bottom;
-               } else {
-                       box.left = x;
-                       box.right = x + box.width;
-                       box.top = box.fullSize ? userPadding.top : chartArea.top;
-                       box.bottom = box.fullSize ? params.outerHeight - userPadding.right : chartArea.top + chartArea.h;
-                       box.height = box.bottom - box.top;
-                       x = box.right;
-               }
-       }
-
-       chartArea.x = x;
-       chartArea.y = y;
+  const userPadding = params.padding;
+  let x = chartArea.x;
+  let y = chartArea.y;
+  let i, ilen, layout, box;
+
+  for (i = 0, ilen = boxes.length; i < ilen; ++i) {
+    layout = boxes[i];
+    box = layout.box;
+    if (layout.horizontal) {
+      box.left = box.fullSize ? userPadding.left : chartArea.left;
+      box.right = box.fullSize ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;
+      box.top = y;
+      box.bottom = y + box.height;
+      box.width = box.right - box.left;
+      y = box.bottom;
+    } else {
+      box.left = x;
+      box.right = x + box.width;
+      box.top = box.fullSize ? userPadding.top : chartArea.top;
+      box.bottom = box.fullSize ? params.outerHeight - userPadding.right : chartArea.top + chartArea.h;
+      box.height = box.bottom - box.top;
+      x = box.right;
+    }
+  }
+
+  chartArea.x = x;
+  chartArea.y = y;
 }
 
 defaults.set('layout', {
-       padding: {
-               top: 0,
-               right: 0,
-               bottom: 0,
-               left: 0
-       }
+  padding: {
+    top: 0,
+    right: 0,
+    bottom: 0,
+    left: 0
+  }
 });
 
 /**
@@ -237,168 +237,168 @@ defaults.set('layout', {
 // It is this service's responsibility of carrying out that layout.
 export default {
 
-       /**
+  /**
         * Register a box to a chart.
         * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
         * @param {Chart} chart - the chart to use
         * @param {LayoutItem} item - the item to add to be laid out
         */
-       addBox(chart, item) {
-               if (!chart.boxes) {
-                       chart.boxes = [];
-               }
-
-               // initialize item with default values
-               item.fullSize = item.fullSize || false;
-               item.position = item.position || 'top';
-               item.weight = item.weight || 0;
-               // @ts-ignore
-               item._layers = item._layers || function() {
-                       return [{
-                               z: 0,
-                               draw(chartArea) {
-                                       item.draw(chartArea);
-                               }
-                       }];
-               };
-
-               chart.boxes.push(item);
-       },
-
-       /**
+  addBox(chart, item) {
+    if (!chart.boxes) {
+      chart.boxes = [];
+    }
+
+    // initialize item with default values
+    item.fullSize = item.fullSize || false;
+    item.position = item.position || 'top';
+    item.weight = item.weight || 0;
+    // @ts-ignore
+    item._layers = item._layers || function() {
+      return [{
+        z: 0,
+        draw(chartArea) {
+          item.draw(chartArea);
+        }
+      }];
+    };
+
+    chart.boxes.push(item);
+  },
+
+  /**
         * Remove a layoutItem from a chart
         * @param {Chart} chart - the chart to remove the box from
         * @param {LayoutItem} layoutItem - the item to remove from the layout
         */
-       removeBox(chart, layoutItem) {
-               const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
-               if (index !== -1) {
-                       chart.boxes.splice(index, 1);
-               }
-       },
-
-       /**
+  removeBox(chart, layoutItem) {
+    const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
+    if (index !== -1) {
+      chart.boxes.splice(index, 1);
+    }
+  },
+
+  /**
         * Sets (or updates) options on the given `item`.
         * @param {Chart} chart - the chart in which the item lives (or will be added to)
         * @param {LayoutItem} item - the item to configure with the given options
         * @param {object} options - the new item options.
         */
-       configure(chart, item, options) {
-               item.fullSize = options.fullSize;
-               item.position = options.position;
-               item.weight = options.weight;
-       },
+  configure(chart, item, options) {
+    item.fullSize = options.fullSize;
+    item.position = options.position;
+    item.weight = options.weight;
+  },
 
-       /**
+  /**
         * Fits boxes of the given chart into the given size by having each box measure itself
         * then running a fitting algorithm
         * @param {Chart} chart - the chart
         * @param {number} width - the width to fit into
         * @param {number} height - the height to fit into
         */
-       update(chart, width, height) {
-               if (!chart) {
-                       return;
-               }
-
-               const layoutOptions = chart.options.layout || {};
-               const context = {chart};
-               const padding = toPadding(resolve([layoutOptions.padding], context));
-
-               const availableWidth = width - padding.width;
-               const availableHeight = height - padding.height;
-               const boxes = buildLayoutBoxes(chart.boxes);
-               const verticalBoxes = boxes.vertical;
-               const horizontalBoxes = boxes.horizontal;
-
-               // Before any changes are made, notify boxes that an update is about to being
-               // This is used to clear any cached data (e.g. scale limits)
-               each(chart.boxes, box => {
-                       if (typeof box.beforeLayout === 'function') {
-                               box.beforeLayout();
-                       }
-               });
-
-               // Essentially we now have any number of boxes on each of the 4 sides.
-               // Our canvas looks like the following.
-               // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
-               // B1 is the bottom axis
-               // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
-               // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
-               // an error will be thrown.
-               //
-               // |----------------------------------------------------|
-               // |                  T1 (Full Width)                   |
-               // |----------------------------------------------------|
-               // |    |    |                 T2                  |    |
-               // |    |----|-------------------------------------|----|
-               // |    |    | C1 |                           | C2 |    |
-               // |    |    |----|                           |----|    |
-               // |    |    |                                     |    |
-               // | L1 | L2 |           ChartArea (C0)            | R1 |
-               // |    |    |                                     |    |
-               // |    |    |----|                           |----|    |
-               // |    |    | C3 |                           | C4 |    |
-               // |    |----|-------------------------------------|----|
-               // |    |    |                 B1                  |    |
-               // |----------------------------------------------------|
-               // |                  B2 (Full Width)                   |
-               // |----------------------------------------------------|
-               //
-
-               const params = Object.freeze({
-                       outerWidth: width,
-                       outerHeight: height,
-                       padding,
-                       availableWidth,
-                       availableHeight,
-                       vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,
-                       hBoxMaxHeight: availableHeight / 2
-               });
-               const chartArea = Object.assign({
-                       maxPadding: Object.assign({}, padding),
-                       w: availableWidth,
-                       h: availableHeight,
-                       x: padding.left,
-                       y: padding.top
-               }, padding);
-
-               setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
-
-               // First fit vertical boxes
-               fitBoxes(verticalBoxes, chartArea, params);
-
-               // Then fit horizontal boxes
-               if (fitBoxes(horizontalBoxes, chartArea, params)) {
-                       // if the area changed, re-fit vertical boxes
-                       fitBoxes(verticalBoxes, chartArea, params);
-               }
-
-               handleMaxPadding(chartArea);
-
-               // Finally place the boxes to correct coordinates
-               placeBoxes(boxes.leftAndTop, chartArea, params);
-
-               // Move to opposite side of chart
-               chartArea.x += chartArea.w;
-               chartArea.y += chartArea.h;
-
-               placeBoxes(boxes.rightAndBottom, chartArea, params);
-
-               chart.chartArea = {
-                       left: chartArea.left,
-                       top: chartArea.top,
-                       right: chartArea.left + chartArea.w,
-                       bottom: chartArea.top + chartArea.h,
-                       height: chartArea.h,
-                       width: chartArea.w,
-               };
-
-               // Finally update boxes in chartArea (radial scale for example)
-               each(boxes.chartArea, (layout) => {
-                       const box = layout.box;
-                       Object.assign(box, chart.chartArea);
-                       box.update(chartArea.w, chartArea.h);
-               });
-       }
+  update(chart, width, height) {
+    if (!chart) {
+      return;
+    }
+
+    const layoutOptions = chart.options.layout || {};
+    const context = {chart};
+    const padding = toPadding(resolve([layoutOptions.padding], context));
+
+    const availableWidth = width - padding.width;
+    const availableHeight = height - padding.height;
+    const boxes = buildLayoutBoxes(chart.boxes);
+    const verticalBoxes = boxes.vertical;
+    const horizontalBoxes = boxes.horizontal;
+
+    // Before any changes are made, notify boxes that an update is about to being
+    // This is used to clear any cached data (e.g. scale limits)
+    each(chart.boxes, box => {
+      if (typeof box.beforeLayout === 'function') {
+        box.beforeLayout();
+      }
+    });
+
+    // Essentially we now have any number of boxes on each of the 4 sides.
+    // Our canvas looks like the following.
+    // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
+    // B1 is the bottom axis
+    // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
+    // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
+    // an error will be thrown.
+    //
+    // |----------------------------------------------------|
+    // |                  T1 (Full Width)                   |
+    // |----------------------------------------------------|
+    // |    |    |                 T2                  |    |
+    // |    |----|-------------------------------------|----|
+    // |    |    | C1 |                           | C2 |    |
+    // |    |    |----|                           |----|    |
+    // |    |    |                                     |    |
+    // | L1 | L2 |           ChartArea (C0)            | R1 |
+    // |    |    |                                     |    |
+    // |    |    |----|                           |----|    |
+    // |    |    | C3 |                           | C4 |    |
+    // |    |----|-------------------------------------|----|
+    // |    |    |                 B1                  |    |
+    // |----------------------------------------------------|
+    // |                  B2 (Full Width)                   |
+    // |----------------------------------------------------|
+    //
+
+    const params = Object.freeze({
+      outerWidth: width,
+      outerHeight: height,
+      padding,
+      availableWidth,
+      availableHeight,
+      vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,
+      hBoxMaxHeight: availableHeight / 2
+    });
+    const chartArea = Object.assign({
+      maxPadding: Object.assign({}, padding),
+      w: availableWidth,
+      h: availableHeight,
+      x: padding.left,
+      y: padding.top
+    }, padding);
+
+    setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
+
+    // First fit vertical boxes
+    fitBoxes(verticalBoxes, chartArea, params);
+
+    // Then fit horizontal boxes
+    if (fitBoxes(horizontalBoxes, chartArea, params)) {
+      // if the area changed, re-fit vertical boxes
+      fitBoxes(verticalBoxes, chartArea, params);
+    }
+
+    handleMaxPadding(chartArea);
+
+    // Finally place the boxes to correct coordinates
+    placeBoxes(boxes.leftAndTop, chartArea, params);
+
+    // Move to opposite side of chart
+    chartArea.x += chartArea.w;
+    chartArea.y += chartArea.h;
+
+    placeBoxes(boxes.rightAndBottom, chartArea, params);
+
+    chart.chartArea = {
+      left: chartArea.left,
+      top: chartArea.top,
+      right: chartArea.left + chartArea.w,
+      bottom: chartArea.top + chartArea.h,
+      height: chartArea.h,
+      width: chartArea.w,
+    };
+
+    // Finally update boxes in chartArea (radial scale for example)
+    each(boxes.chartArea, (layout) => {
+      const box = layout.box;
+      Object.assign(box, chart.chartArea);
+      box.update(chartArea.w, chartArea.h);
+    });
+  }
 };
index 5ebd25fa0435b831ec1cf71cfa5b9b18ba0e92e1..42f962c5b471b6c7b993ea3d8d9822a8e7916939 100644 (file)
@@ -10,11 +10,11 @@ import {callback as callCallback, mergeIf, valueOrDefault} from '../helpers/help
  */
 
 export default class PluginService {
-       constructor() {
-               this._init = [];
-       }
+  constructor() {
+    this._init = [];
+  }
 
-       /**
+  /**
         * Calls enabled plugins for `chart` on the specified hook and with the given args.
         * This method immediately returns as soon as a plugin explicitly returns false. The
         * returned value can be used, for instance, to interrupt the current action.
@@ -23,137 +23,137 @@ export default class PluginService {
         * @param {object} [args] - Extra arguments to apply to the hook call.
         * @returns {boolean} false if any of the plugins return false, else returns true.
         */
-       notify(chart, hook, args) {
-               const me = this;
+  notify(chart, hook, args) {
+    const me = this;
 
-               if (hook === 'beforeInit') {
-                       me._init = me._createDescriptors(chart, true);
-                       me._notify(me._init, chart, 'install');
-               }
+    if (hook === 'beforeInit') {
+      me._init = me._createDescriptors(chart, true);
+      me._notify(me._init, chart, 'install');
+    }
 
-               const descriptors = me._descriptors(chart);
-               const result = me._notify(descriptors, chart, hook, args);
+    const descriptors = me._descriptors(chart);
+    const result = me._notify(descriptors, chart, hook, args);
 
-               if (hook === 'destroy') {
-                       me._notify(descriptors, chart, 'stop');
-                       me._notify(me._init, chart, 'uninstall');
-               }
-               return result;
-       }
+    if (hook === 'destroy') {
+      me._notify(descriptors, chart, 'stop');
+      me._notify(me._init, chart, 'uninstall');
+    }
+    return result;
+  }
 
-       /**
+  /**
         * @private
         */
-       _notify(descriptors, chart, hook, args) {
-               args = args || {};
-               for (const descriptor of descriptors) {
-                       const plugin = descriptor.plugin;
-                       const method = plugin[hook];
-                       const params = [chart, args, descriptor.options];
-                       if (callCallback(method, params, plugin) === false && args.cancelable) {
-                               return false;
-                       }
-               }
-
-               return true;
-       }
-
-       invalidate() {
-               // When plugins are registered, there is the possibility of a double
-               // invalidate situation. In this case, we only want to invalidate once.
-               // If we invalidate multiple times, the `_oldCache` is lost and all of the
-               // plugins are restarted without being correctly stopped.
-               // See https://github.com/chartjs/Chart.js/issues/8147
-               if (!isNullOrUndef(this._cache)) {
-                       this._oldCache = this._cache;
-                       this._cache = undefined;
-               }
-       }
-
-       /**
+  _notify(descriptors, chart, hook, args) {
+    args = args || {};
+    for (const descriptor of descriptors) {
+      const plugin = descriptor.plugin;
+      const method = plugin[hook];
+      const params = [chart, args, descriptor.options];
+      if (callCallback(method, params, plugin) === false && args.cancelable) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  invalidate() {
+    // When plugins are registered, there is the possibility of a double
+    // invalidate situation. In this case, we only want to invalidate once.
+    // If we invalidate multiple times, the `_oldCache` is lost and all of the
+    // plugins are restarted without being correctly stopped.
+    // See https://github.com/chartjs/Chart.js/issues/8147
+    if (!isNullOrUndef(this._cache)) {
+      this._oldCache = this._cache;
+      this._cache = undefined;
+    }
+  }
+
+  /**
         * @param {Chart} chart
         * @private
         */
-       _descriptors(chart) {
-               if (this._cache) {
-                       return this._cache;
-               }
+  _descriptors(chart) {
+    if (this._cache) {
+      return this._cache;
+    }
 
-               const descriptors = this._cache = this._createDescriptors(chart);
+    const descriptors = this._cache = this._createDescriptors(chart);
 
-               this._notifyStateChanges(chart);
+    this._notifyStateChanges(chart);
 
-               return descriptors;
-       }
+    return descriptors;
+  }
 
-       _createDescriptors(chart, all) {
-               const config = chart && chart.config;
-               const options = valueOrDefault(config.options && config.options.plugins, {});
-               const plugins = allPlugins(config);
-               // options === false => all plugins are disabled
-               return options === false && !all ? [] : createDescriptors(plugins, options, all);
-       }
+  _createDescriptors(chart, all) {
+    const config = chart && chart.config;
+    const options = valueOrDefault(config.options && config.options.plugins, {});
+    const plugins = allPlugins(config);
+    // options === false => all plugins are disabled
+    return options === false && !all ? [] : createDescriptors(plugins, options, all);
+  }
 
-       /**
+  /**
         * @param {Chart} chart
         * @private
         */
-       _notifyStateChanges(chart) {
-               const previousDescriptors = this._oldCache || [];
-               const descriptors = this._cache;
-               const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id));
-               this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
-               this._notify(diff(descriptors, previousDescriptors), chart, 'start');
-       }
+  _notifyStateChanges(chart) {
+    const previousDescriptors = this._oldCache || [];
+    const descriptors = this._cache;
+    const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id));
+    this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
+    this._notify(diff(descriptors, previousDescriptors), chart, 'start');
+  }
 }
 
 /**
  * @param {import("./core.config").default} config
  */
 function allPlugins(config) {
-       const plugins = [];
-       const keys = Object.keys(registry.plugins.items);
-       for (let i = 0; i < keys.length; i++) {
-               plugins.push(registry.getPlugin(keys[i]));
-       }
-
-       const local = config.plugins || [];
-       for (let i = 0; i < local.length; i++) {
-               const plugin = local[i];
-
-               if (plugins.indexOf(plugin) === -1) {
-                       plugins.push(plugin);
-               }
-       }
-
-       return plugins;
+  const plugins = [];
+  const keys = Object.keys(registry.plugins.items);
+  for (let i = 0; i < keys.length; i++) {
+    plugins.push(registry.getPlugin(keys[i]));
+  }
+
+  const local = config.plugins || [];
+  for (let i = 0; i < local.length; i++) {
+    const plugin = local[i];
+
+    if (plugins.indexOf(plugin) === -1) {
+      plugins.push(plugin);
+    }
+  }
+
+  return plugins;
 }
 
 function getOpts(options, all) {
-       if (!all && options === false) {
-               return null;
-       }
-       if (options === true) {
-               return {};
-       }
-       return options;
+  if (!all && options === false) {
+    return null;
+  }
+  if (options === true) {
+    return {};
+  }
+  return options;
 }
 
 function createDescriptors(plugins, options, all) {
-       const result = [];
-
-       for (let i = 0; i < plugins.length; i++) {
-               const plugin = plugins[i];
-               const id = plugin.id;
-               const opts = getOpts(options[id], all);
-               if (opts === null) {
-                       continue;
-               }
-               result.push({
-                       plugin,
-                       options: mergeIf({}, [opts, defaults.plugins[id]])
-               });
-       }
-
-       return result;
+  const result = [];
+
+  for (let i = 0; i < plugins.length; i++) {
+    const plugin = plugins[i];
+    const id = plugin.id;
+    const opts = getOpts(options[id], all);
+    if (opts === null) {
+      continue;
+    }
+    result.push({
+      plugin,
+      options: mergeIf({}, [opts, defaults.plugins[id]])
+    });
+  }
+
+  return result;
 }
index 11f4d339f434573874510a9511c3a7bbf296bdf9..e46d2dc2fddfdd0cdbe388d20c2ec0b4372620ab 100644 (file)
@@ -9,177 +9,177 @@ import {each, callback as call, _capitalize} from '../helpers/helpers.core';
  * Note: class is exported for typedoc
  */
 export class Registry {
-       constructor() {
-               this.controllers = new TypedRegistry(DatasetController, 'controllers');
-               this.elements = new TypedRegistry(Element, 'elements');
-               this.plugins = new TypedRegistry(Object, 'plugins');
-               this.scales = new TypedRegistry(Scale, 'scales');
-               // Order is important, Scale has Element in prototype chain,
-               // so Scales must be before Elements. Plugins are a fallback, so not listed here.
-               this._typedRegistries = [this.controllers, this.scales, this.elements];
-       }
-
-       /**
+  constructor() {
+    this.controllers = new TypedRegistry(DatasetController, 'controllers');
+    this.elements = new TypedRegistry(Element, 'elements');
+    this.plugins = new TypedRegistry(Object, 'plugins');
+    this.scales = new TypedRegistry(Scale, 'scales');
+    // Order is important, Scale has Element in prototype chain,
+    // so Scales must be before Elements. Plugins are a fallback, so not listed here.
+    this._typedRegistries = [this.controllers, this.scales, this.elements];
+  }
+
+  /**
         * @param  {...any} args
         */
-       add(...args) {
-               this._each('register', args);
-       }
+  add(...args) {
+    this._each('register', args);
+  }
 
-       remove(...args) {
-               this._each('unregister', args);
-       }
+  remove(...args) {
+    this._each('unregister', args);
+  }
 
-       /**
+  /**
         * @param  {...typeof DatasetController} args
         */
-       addControllers(...args) {
-               this._each('register', args, this.controllers);
-       }
+  addControllers(...args) {
+    this._each('register', args, this.controllers);
+  }
 
-       /**
+  /**
         * @param  {...typeof Element} args
         */
-       addElements(...args) {
-               this._each('register', args, this.elements);
-       }
+  addElements(...args) {
+    this._each('register', args, this.elements);
+  }
 
-       /**
+  /**
         * @param  {...any} args
         */
-       addPlugins(...args) {
-               this._each('register', args, this.plugins);
-       }
+  addPlugins(...args) {
+    this._each('register', args, this.plugins);
+  }
 
-       /**
+  /**
         * @param  {...typeof Scale} args
         */
-       addScales(...args) {
-               this._each('register', args, this.scales);
-       }
+  addScales(...args) {
+    this._each('register', args, this.scales);
+  }
 
-       /**
+  /**
         * @param {string} id
         * @returns {typeof DatasetController}
         */
-       getController(id) {
-               return this._get(id, this.controllers, 'controller');
-       }
+  getController(id) {
+    return this._get(id, this.controllers, 'controller');
+  }
 
-       /**
+  /**
         * @param {string} id
         * @returns {typeof Element}
         */
-       getElement(id) {
-               return this._get(id, this.elements, 'element');
-       }
+  getElement(id) {
+    return this._get(id, this.elements, 'element');
+  }
 
-       /**
+  /**
         * @param {string} id
         * @returns {object}
         */
-       getPlugin(id) {
-               return this._get(id, this.plugins, 'plugin');
-       }
+  getPlugin(id) {
+    return this._get(id, this.plugins, 'plugin');
+  }
 
-       /**
+  /**
         * @param {string} id
         * @returns {typeof Scale}
         */
-       getScale(id) {
-               return this._get(id, this.scales, 'scale');
-       }
+  getScale(id) {
+    return this._get(id, this.scales, 'scale');
+  }
 
-       /**
+  /**
         * @param  {...typeof DatasetController} args
         */
-       removeControllers(...args) {
-               this._each('unregister', args, this.controllers);
-       }
+  removeControllers(...args) {
+    this._each('unregister', args, this.controllers);
+  }
 
-       /**
+  /**
         * @param  {...typeof Element} args
         */
-       removeElements(...args) {
-               this._each('unregister', args, this.elements);
-       }
+  removeElements(...args) {
+    this._each('unregister', args, this.elements);
+  }
 
-       /**
+  /**
         * @param  {...any} args
         */
-       removePlugins(...args) {
-               this._each('unregister', args, this.plugins);
-       }
+  removePlugins(...args) {
+    this._each('unregister', args, this.plugins);
+  }
 
-       /**
+  /**
         * @param  {...typeof Scale} args
         */
-       removeScales(...args) {
-               this._each('unregister', args, this.scales);
-       }
+  removeScales(...args) {
+    this._each('unregister', args, this.scales);
+  }
 
-       /**
+  /**
         * @private
         */
-       _each(method, args, typedRegistry) {
-               const me = this;
-               [...args].forEach(arg => {
-                       const reg = typedRegistry || me._getRegistryForType(arg);
-                       if (typedRegistry || reg.isForType(arg) || (reg === me.plugins && arg.id)) {
-                               me._exec(method, reg, arg);
-                       } else {
-                               // Handle loopable args
-                               // Use case:
-                               //  import * as plugins from './plugins';
-                               //  Chart.register(plugins);
-                               each(arg, item => {
-                                       // If there are mixed types in the loopable, make sure those are
-                                       // registered in correct registry
-                                       // Use case: (treemap exporting controller, elements etc)
-                                       //  import * as treemap from 'chartjs-chart-treemap';
-                                       //  Chart.register(treemap);
-
-                                       const itemReg = typedRegistry || me._getRegistryForType(item);
-                                       me._exec(method, itemReg, item);
-                               });
-                       }
-               });
-       }
-
-       /**
+  _each(method, args, typedRegistry) {
+    const me = this;
+    [...args].forEach(arg => {
+      const reg = typedRegistry || me._getRegistryForType(arg);
+      if (typedRegistry || reg.isForType(arg) || (reg === me.plugins && arg.id)) {
+        me._exec(method, reg, arg);
+      } else {
+        // Handle loopable args
+        // Use case:
+        //  import * as plugins from './plugins';
+        //  Chart.register(plugins);
+        each(arg, item => {
+          // If there are mixed types in the loopable, make sure those are
+          // registered in correct registry
+          // Use case: (treemap exporting controller, elements etc)
+          //  import * as treemap from 'chartjs-chart-treemap';
+          //  Chart.register(treemap);
+
+          const itemReg = typedRegistry || me._getRegistryForType(item);
+          me._exec(method, itemReg, item);
+        });
+      }
+    });
+  }
+
+  /**
         * @private
         */
-       _exec(method, registry, component) {
-               const camelMethod = _capitalize(method);
-               call(component['before' + camelMethod], [], component);
-               registry[method](component);
-               call(component['after' + camelMethod], [], component);
-       }
+  _exec(method, registry, component) {
+    const camelMethod = _capitalize(method);
+    call(component['before' + camelMethod], [], component);
+    registry[method](component);
+    call(component['after' + camelMethod], [], component);
+  }
 
-       /**
+  /**
         * @private
         */
-       _getRegistryForType(type) {
-               for (let i = 0; i < this._typedRegistries.length; i++) {
-                       const reg = this._typedRegistries[i];
-                       if (reg.isForType(type)) {
-                               return reg;
-                       }
-               }
-               // plugins is the fallback registry
-               return this.plugins;
-       }
-
-       /**
+  _getRegistryForType(type) {
+    for (let i = 0; i < this._typedRegistries.length; i++) {
+      const reg = this._typedRegistries[i];
+      if (reg.isForType(type)) {
+        return reg;
+      }
+    }
+    // plugins is the fallback registry
+    return this.plugins;
+  }
+
+  /**
         * @private
         */
-       _get(id, typedRegistry, type) {
-               const item = typedRegistry.get(id);
-               if (item === undefined) {
-                       throw new Error('"' + id + '" is not a registered ' + type + '.');
-               }
-               return item;
-       }
+  _get(id, typedRegistry, type) {
+    const item = typedRegistry.get(id);
+    if (item === undefined) {
+      throw new Error('"' + id + '" is not a registered ' + type + '.');
+    }
+    return item;
+  }
 
 }
 
index 94b15468b973451cb14745b37ef054934947d143..70fdfaca695c2ed212995d86a9621092117090d3 100644 (file)
@@ -12,67 +12,67 @@ import Ticks from './core.ticks';
  */
 
 defaults.set('scale', {
-       display: true,
-       offset: false,
-       reverse: false,
-       beginAtZero: false,
+  display: true,
+  offset: false,
+  reverse: false,
+  beginAtZero: false,
 
-       /**
+  /**
         * Scale boundary strategy (bypassed by min/max time options)
         * - `data`: make sure data are fully visible, ticks outside are removed
         * - `ticks`: make sure ticks are fully visible, data outside are truncated
         * @see https://github.com/chartjs/Chart.js/pull/4556
         * @since 3.0.0
         */
-       bounds: 'ticks',
-
-       // grid line settings
-       gridLines: {
-               display: true,
-               lineWidth: 1,
-               drawBorder: true,
-               drawOnChartArea: true,
-               drawTicks: true,
-               tickLength: 10,
-               offsetGridLines: false,
-               borderDash: [],
-               borderDashOffset: 0.0
-       },
-
-       // scale label
-       scaleLabel: {
-               // display property
-               display: false,
-
-               // actual label
-               labelString: '',
-
-               // top/bottom padding
-               padding: {
-                       top: 4,
-                       bottom: 4
-               }
-       },
-
-       // label settings
-       ticks: {
-               minRotation: 0,
-               maxRotation: 50,
-               mirror: false,
-               textStrokeWidth: 0,
-               textStrokeColor: '',
-               padding: 0,
-               display: true,
-               autoSkip: true,
-               autoSkipPadding: 0,
-               labelOffset: 0,
-               // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
-               callback: Ticks.formatters.values,
-               minor: {},
-               major: {},
-               align: 'center',
-               crossAlign: 'near',
-       }
+  bounds: 'ticks',
+
+  // grid line settings
+  gridLines: {
+    display: true,
+    lineWidth: 1,
+    drawBorder: true,
+    drawOnChartArea: true,
+    drawTicks: true,
+    tickLength: 10,
+    offsetGridLines: false,
+    borderDash: [],
+    borderDashOffset: 0.0
+  },
+
+  // scale label
+  scaleLabel: {
+    // display property
+    display: false,
+
+    // actual label
+    labelString: '',
+
+    // top/bottom padding
+    padding: {
+      top: 4,
+      bottom: 4
+    }
+  },
+
+  // label settings
+  ticks: {
+    minRotation: 0,
+    maxRotation: 50,
+    mirror: false,
+    textStrokeWidth: 0,
+    textStrokeColor: '',
+    padding: 0,
+    display: true,
+    autoSkip: true,
+    autoSkipPadding: 0,
+    labelOffset: 0,
+    // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
+    callback: Ticks.formatters.values,
+    minor: {},
+    major: {},
+    align: 'center',
+    crossAlign: 'near',
+  }
 });
 
 defaults.route('scale.ticks', 'color', '', 'color');
@@ -85,15 +85,15 @@ defaults.route('scale.scaleLabel', 'color', '', 'color');
  * @param {number} numItems
  */
 function sample(arr, numItems) {
-       const result = [];
-       const increment = arr.length / numItems;
-       const len = arr.length;
-       let i = 0;
-
-       for (; i < len; i += increment) {
-               result.push(arr[Math.floor(i)]);
-       }
-       return result;
+  const result = [];
+  const increment = arr.length / numItems;
+  const len = arr.length;
+  let i = 0;
+
+  for (; i < len; i += increment) {
+    result.push(arr[Math.floor(i)]);
+  }
+  return result;
 }
 
 /**
@@ -102,30 +102,30 @@ function sample(arr, numItems) {
  * @param {boolean} offsetGridLines
  */
 function getPixelForGridLine(scale, index, offsetGridLines) {
-       const length = scale.ticks.length;
-       const validIndex = Math.min(index, length - 1);
-       const start = scale._startPixel;
-       const end = scale._endPixel;
-       const epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
-       let lineValue = scale.getPixelForTick(validIndex);
-       let offset;
-
-       if (offsetGridLines) {
-               if (length === 1) {
-                       offset = Math.max(lineValue - start, end - lineValue);
-               } else if (index === 0) {
-                       offset = (scale.getPixelForTick(1) - lineValue) / 2;
-               } else {
-                       offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
-               }
-               lineValue += validIndex < index ? offset : -offset;
-
-               // Return undefined if the pixel is out of the range
-               if (lineValue < start - epsilon || lineValue > end + epsilon) {
-                       return;
-               }
-       }
-       return lineValue;
+  const length = scale.ticks.length;
+  const validIndex = Math.min(index, length - 1);
+  const start = scale._startPixel;
+  const end = scale._endPixel;
+  const epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
+  let lineValue = scale.getPixelForTick(validIndex);
+  let offset;
+
+  if (offsetGridLines) {
+    if (length === 1) {
+      offset = Math.max(lineValue - start, end - lineValue);
+    } else if (index === 0) {
+      offset = (scale.getPixelForTick(1) - lineValue) / 2;
+    } else {
+      offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
+    }
+    lineValue += validIndex < index ? offset : -offset;
+
+    // Return undefined if the pixel is out of the range
+    if (lineValue < start - epsilon || lineValue > end + epsilon) {
+      return;
+    }
+  }
+  return lineValue;
 }
 
 /**
@@ -133,57 +133,57 @@ function getPixelForGridLine(scale, index, offsetGridLines) {
  * @param {number} length
  */
 function garbageCollect(caches, length) {
-       each(caches, (cache) => {
-               const gc = cache.gc;
-               const gcLen = gc.length / 2;
-               let i;
-               if (gcLen > length) {
-                       for (i = 0; i < gcLen; ++i) {
-                               delete cache.data[gc[i]];
-                       }
-                       gc.splice(0, gcLen);
-               }
-       });
+  each(caches, (cache) => {
+    const gc = cache.gc;
+    const gcLen = gc.length / 2;
+    let i;
+    if (gcLen > length) {
+      for (i = 0; i < gcLen; ++i) {
+        delete cache.data[gc[i]];
+      }
+      gc.splice(0, gcLen);
+    }
+  });
 }
 
 /**
  * @param {object} options
  */
 function getTickMarkLength(options) {
-       return options.drawTicks ? options.tickLength : 0;
+  return options.drawTicks ? options.tickLength : 0;
 }
 
 /**
  * @param {object} options
  */
 function getScaleLabelHeight(options, fallback) {
-       if (!options.display) {
-               return 0;
-       }
+  if (!options.display) {
+    return 0;
+  }
 
-       const font = toFont(options.font, fallback);
-       const padding = toPadding(options.padding);
+  const font = toFont(options.font, fallback);
+  const padding = toPadding(options.padding);
 
-       return font.lineHeight + padding.height;
+  return font.lineHeight + padding.height;
 }
 
 /**
  * @param {number[]} arr
  */
 function getEvenSpacing(arr) {
-       const len = arr.length;
-       let i, diff;
-
-       if (len < 2) {
-               return false;
-       }
-
-       for (diff = arr[0], i = 1; i < len; ++i) {
-               if (arr[i] - arr[i - 1] !== diff) {
-                       return false;
-               }
-       }
-       return diff;
+  const len = arr.length;
+  let i, diff;
+
+  if (len < 2) {
+    return false;
+  }
+
+  for (diff = arr[0], i = 1; i < len; ++i) {
+    if (arr[i] - arr[i - 1] !== diff) {
+      return false;
+    }
+  }
+  return diff;
 }
 
 /**
@@ -192,37 +192,37 @@ function getEvenSpacing(arr) {
  * @param {number} ticksLimit
  */
 function calculateSpacing(majorIndices, ticks, ticksLimit) {
-       const evenMajorSpacing = getEvenSpacing(majorIndices);
-       const spacing = ticks.length / ticksLimit;
-
-       // If the major ticks are evenly spaced apart, place the minor ticks
-       // so that they divide the major ticks into even chunks
-       if (!evenMajorSpacing) {
-               return Math.max(spacing, 1);
-       }
-
-       const factors = _factorize(evenMajorSpacing);
-       for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {
-               const factor = factors[i];
-               if (factor > spacing) {
-                       return factor;
-               }
-       }
-       return Math.max(spacing, 1);
+  const evenMajorSpacing = getEvenSpacing(majorIndices);
+  const spacing = ticks.length / ticksLimit;
+
+  // If the major ticks are evenly spaced apart, place the minor ticks
+  // so that they divide the major ticks into even chunks
+  if (!evenMajorSpacing) {
+    return Math.max(spacing, 1);
+  }
+
+  const factors = _factorize(evenMajorSpacing);
+  for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {
+    const factor = factors[i];
+    if (factor > spacing) {
+      return factor;
+    }
+  }
+  return Math.max(spacing, 1);
 }
 
 /**
  * @param {Tick[]} ticks
  */
 function getMajorIndices(ticks) {
-       const result = [];
-       let i, ilen;
-       for (i = 0, ilen = ticks.length; i < ilen; i++) {
-               if (ticks[i].major) {
-                       result.push(i);
-               }
-       }
-       return result;
+  const result = [];
+  let i, ilen;
+  for (i = 0, ilen = ticks.length; i < ilen; i++) {
+    if (ticks[i].major) {
+      result.push(i);
+    }
+  }
+  return result;
 }
 
 /**
@@ -232,18 +232,18 @@ function getMajorIndices(ticks) {
  * @param {number} spacing
  */
 function skipMajors(ticks, newTicks, majorIndices, spacing) {
-       let count = 0;
-       let next = majorIndices[0];
-       let i;
-
-       spacing = Math.ceil(spacing);
-       for (i = 0; i < ticks.length; i++) {
-               if (i === next) {
-                       newTicks.push(ticks[i]);
-                       count++;
-                       next = majorIndices[count * spacing];
-               }
-       }
+  let count = 0;
+  let next = majorIndices[0];
+  let i;
+
+  spacing = Math.ceil(spacing);
+  for (i = 0; i < ticks.length; i++) {
+    if (i === next) {
+      newTicks.push(ticks[i]);
+      count++;
+      next = majorIndices[count * spacing];
+    }
+  }
 }
 
 /**
@@ -254,266 +254,266 @@ function skipMajors(ticks, newTicks, majorIndices, spacing) {
  * @param {number} [majorEnd]
  */
 function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
-       const start = valueOrDefault(majorStart, 0);
-       const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
-       let count = 0;
-       let length, i, next;
-
-       spacing = Math.ceil(spacing);
-       if (majorEnd) {
-               length = majorEnd - majorStart;
-               spacing = length / Math.floor(length / spacing);
-       }
-
-       next = start;
-
-       while (next < 0) {
-               count++;
-               next = Math.round(start + count * spacing);
-       }
-
-       for (i = Math.max(start, 0); i < end; i++) {
-               if (i === next) {
-                       newTicks.push(ticks[i]);
-                       count++;
-                       next = Math.round(start + count * spacing);
-               }
-       }
+  const start = valueOrDefault(majorStart, 0);
+  const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
+  let count = 0;
+  let length, i, next;
+
+  spacing = Math.ceil(spacing);
+  if (majorEnd) {
+    length = majorEnd - majorStart;
+    spacing = length / Math.floor(length / spacing);
+  }
+
+  next = start;
+
+  while (next < 0) {
+    count++;
+    next = Math.round(start + count * spacing);
+  }
+
+  for (i = Math.max(start, 0); i < end; i++) {
+    if (i === next) {
+      newTicks.push(ticks[i]);
+      count++;
+      next = Math.round(start + count * spacing);
+    }
+  }
 }
 
 function createScaleContext(parent, scale) {
-       return Object.create(parent, {
-               scale: {
-                       value: scale
-               },
-               type: {
-                       value: 'scale'
-               }
-       });
+  return Object.create(parent, {
+    scale: {
+      value: scale
+    },
+    type: {
+      value: 'scale'
+    }
+  });
 }
 
 function createTickContext(parent, index, tick) {
-       return Object.create(parent, {
-               tick: {
-                       value: tick
-               },
-               index: {
-                       value: index
-               },
-               type: {
-                       value: 'tick'
-               }
-       });
+  return Object.create(parent, {
+    tick: {
+      value: tick
+    },
+    index: {
+      value: index
+    },
+    type: {
+      value: 'tick'
+    }
+  });
 }
 
 export default class Scale extends Element {
 
-       // eslint-disable-next-line max-statements
-       constructor(cfg) {
-               super();
-
-               /** @type {string} */
-               this.id = cfg.id;
-               /** @type {string} */
-               this.type = cfg.type;
-               /** @type {object} */
-               this.options = undefined;
-               /** @type {CanvasRenderingContext2D} */
-               this.ctx = cfg.ctx;
-               /** @type {Chart} */
-               this.chart = cfg.chart;
-
-               // implements box
-               /** @type {number} */
-               this.top = undefined;
-               /** @type {number} */
-               this.bottom = undefined;
-               /** @type {number} */
-               this.left = undefined;
-               /** @type {number} */
-               this.right = undefined;
-               /** @type {number} */
-               this.width = undefined;
-               /** @type {number} */
-               this.height = undefined;
-               this._margins = {
-                       left: 0,
-                       right: 0,
-                       top: 0,
-                       bottom: 0
-               };
-               /** @type {number} */
-               this.maxWidth = undefined;
-               /** @type {number} */
-               this.maxHeight = undefined;
-               /** @type {number} */
-               this.paddingTop = undefined;
-               /** @type {number} */
-               this.paddingBottom = undefined;
-               /** @type {number} */
-               this.paddingLeft = undefined;
-               /** @type {number} */
-               this.paddingRight = undefined;
-
-               // scale-specific properties
-               /** @type {string=} */
-               this.axis = undefined;
-               /** @type {number=} */
-               this.labelRotation = undefined;
-               this.min = undefined;
-               this.max = undefined;
-               /** @type {Tick[]} */
-               this.ticks = [];
-               /** @type {object[]|null} */
-               this._gridLineItems = null;
-               /** @type {object[]|null} */
-               this._labelItems = null;
-               /** @type {object|null} */
-               this._labelSizes = null;
-               this._length = 0;
-               this._longestTextCache = {};
-               /** @type {number} */
-               this._startPixel = undefined;
-               /** @type {number} */
-               this._endPixel = undefined;
-               this._reversePixels = false;
-               this._userMax = undefined;
-               this._userMin = undefined;
-               this._suggestedMax = undefined;
-               this._suggestedMin = undefined;
-               this._ticksLength = 0;
-               this._borderValue = 0;
-               this._cache = {};
-               this._dataLimitsCached = false;
-               this.$context = undefined;
-       }
-
-       /**
+  // eslint-disable-next-line max-statements
+  constructor(cfg) {
+    super();
+
+    /** @type {string} */
+    this.id = cfg.id;
+    /** @type {string} */
+    this.type = cfg.type;
+    /** @type {object} */
+    this.options = undefined;
+    /** @type {CanvasRenderingContext2D} */
+    this.ctx = cfg.ctx;
+    /** @type {Chart} */
+    this.chart = cfg.chart;
+
+    // implements box
+    /** @type {number} */
+    this.top = undefined;
+    /** @type {number} */
+    this.bottom = undefined;
+    /** @type {number} */
+    this.left = undefined;
+    /** @type {number} */
+    this.right = undefined;
+    /** @type {number} */
+    this.width = undefined;
+    /** @type {number} */
+    this.height = undefined;
+    this._margins = {
+      left: 0,
+      right: 0,
+      top: 0,
+      bottom: 0
+    };
+    /** @type {number} */
+    this.maxWidth = undefined;
+    /** @type {number} */
+    this.maxHeight = undefined;
+    /** @type {number} */
+    this.paddingTop = undefined;
+    /** @type {number} */
+    this.paddingBottom = undefined;
+    /** @type {number} */
+    this.paddingLeft = undefined;
+    /** @type {number} */
+    this.paddingRight = undefined;
+
+    // scale-specific properties
+    /** @type {string=} */
+    this.axis = undefined;
+    /** @type {number=} */
+    this.labelRotation = undefined;
+    this.min = undefined;
+    this.max = undefined;
+    /** @type {Tick[]} */
+    this.ticks = [];
+    /** @type {object[]|null} */
+    this._gridLineItems = null;
+    /** @type {object[]|null} */
+    this._labelItems = null;
+    /** @type {object|null} */
+    this._labelSizes = null;
+    this._length = 0;
+    this._longestTextCache = {};
+    /** @type {number} */
+    this._startPixel = undefined;
+    /** @type {number} */
+    this._endPixel = undefined;
+    this._reversePixels = false;
+    this._userMax = undefined;
+    this._userMin = undefined;
+    this._suggestedMax = undefined;
+    this._suggestedMin = undefined;
+    this._ticksLength = 0;
+    this._borderValue = 0;
+    this._cache = {};
+    this._dataLimitsCached = false;
+    this.$context = undefined;
+  }
+
+  /**
         * @param {object} options
         * @since 3.0
         */
-       init(options) {
-               const me = this;
-               me.options = options;
+  init(options) {
+    const me = this;
+    me.options = options;
 
-               me.axis = me.isHorizontal() ? 'x' : 'y';
+    me.axis = me.isHorizontal() ? 'x' : 'y';
 
-               // parse min/max value, so we can properly determine min/max for other scales
-               me._userMin = me.parse(options.min);
-               me._userMax = me.parse(options.max);
-               me._suggestedMin = me.parse(options.suggestedMin);
-               me._suggestedMax = me.parse(options.suggestedMax);
-       }
+    // parse min/max value, so we can properly determine min/max for other scales
+    me._userMin = me.parse(options.min);
+    me._userMax = me.parse(options.max);
+    me._suggestedMin = me.parse(options.suggestedMin);
+    me._suggestedMax = me.parse(options.suggestedMax);
+  }
 
-       /**
+  /**
         * Parse a supported input value to internal representation.
         * @param {*} raw
         * @param {number} [index]
         * @since 3.0
         */
-       parse(raw, index) { // eslint-disable-line no-unused-vars
-               return raw;
-       }
+  parse(raw, index) { // eslint-disable-line no-unused-vars
+    return raw;
+  }
 
-       /**
+  /**
         * @return {{min: number, max: number, minDefined: boolean, maxDefined: boolean}}
         * @protected
         * @since 3.0
         */
-       getUserBounds() {
-               let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this;
-               _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);
-               _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);
-               _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);
-               _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);
-               return {
-                       min: finiteOrDefault(_userMin, _suggestedMin),
-                       max: finiteOrDefault(_userMax, _suggestedMax),
-                       minDefined: isFinite(_userMin),
-                       maxDefined: isFinite(_userMax)
-               };
-       }
-
-       /**
+  getUserBounds() {
+    let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this;
+    _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);
+    _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);
+    _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);
+    _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);
+    return {
+      min: finiteOrDefault(_userMin, _suggestedMin),
+      max: finiteOrDefault(_userMax, _suggestedMax),
+      minDefined: isFinite(_userMin),
+      maxDefined: isFinite(_userMax)
+    };
+  }
+
+  /**
         * @param {boolean} canStack
         * @return {{min: number, max: number}}
         * @protected
         * @since 3.0
         */
-       getMinMax(canStack) {
-               const me = this;
-               // eslint-disable-next-line prefer-const
-               let {min, max, minDefined, maxDefined} = me.getUserBounds();
-               let range;
-
-               if (minDefined && maxDefined) {
-                       return {min, max};
-               }
-
-               const metas = me.getMatchingVisibleMetas();
-               for (let i = 0, ilen = metas.length; i < ilen; ++i) {
-                       range = metas[i].controller.getMinMax(me, canStack);
-                       if (!minDefined) {
-                               min = Math.min(min, range.min);
-                       }
-                       if (!maxDefined) {
-                               max = Math.max(max, range.max);
-                       }
-               }
-
-               return {
-                       min: finiteOrDefault(min, finiteOrDefault(max, min)),
-                       max: finiteOrDefault(max, finiteOrDefault(min, max))
-               };
-       }
-
-       /**
+  getMinMax(canStack) {
+    const me = this;
+    // eslint-disable-next-line prefer-const
+    let {min, max, minDefined, maxDefined} = me.getUserBounds();
+    let range;
+
+    if (minDefined && maxDefined) {
+      return {min, max};
+    }
+
+    const metas = me.getMatchingVisibleMetas();
+    for (let i = 0, ilen = metas.length; i < ilen; ++i) {
+      range = metas[i].controller.getMinMax(me, canStack);
+      if (!minDefined) {
+        min = Math.min(min, range.min);
+      }
+      if (!maxDefined) {
+        max = Math.max(max, range.max);
+      }
+    }
+
+    return {
+      min: finiteOrDefault(min, finiteOrDefault(max, min)),
+      max: finiteOrDefault(max, finiteOrDefault(min, max))
+    };
+  }
+
+  /**
         * Get the padding needed for the scale
         * @return {{top: number, left: number, bottom: number, right: number}} the necessary padding
         * @private
         */
-       getPadding() {
-               const me = this;
-               return {
-                       left: me.paddingLeft || 0,
-                       top: me.paddingTop || 0,
-                       right: me.paddingRight || 0,
-                       bottom: me.paddingBottom || 0
-               };
-       }
-
-       /**
+  getPadding() {
+    const me = this;
+    return {
+      left: me.paddingLeft || 0,
+      top: me.paddingTop || 0,
+      right: me.paddingRight || 0,
+      bottom: me.paddingBottom || 0
+    };
+  }
+
+  /**
         * Returns the scale tick objects
         * @return {Tick[]}
         * @since 2.7
         */
-       getTicks() {
-               return this.ticks;
-       }
+  getTicks() {
+    return this.ticks;
+  }
 
-       /**
+  /**
         * @return {string[]}
         */
-       getLabels() {
-               const data = this.chart.data;
-               return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
-       }
-
-       // When a new layout is created, reset the data limits cache
-       beforeLayout() {
-               this._cache = {};
-               this._dataLimitsCached = false;
-       }
-
-       // These methods are ordered by lifecycle. Utilities then follow.
-       // Any function defined here is inherited by all scale types.
-       // Any function can be extended by the scale type
-
-       beforeUpdate() {
-               call(this.options.beforeUpdate, [this]);
-       }
-
-       /**
+  getLabels() {
+    const data = this.chart.data;
+    return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
+  }
+
+  // When a new layout is created, reset the data limits cache
+  beforeLayout() {
+    this._cache = {};
+    this._dataLimitsCached = false;
+  }
+
+  // These methods are ordered by lifecycle. Utilities then follow.
+  // Any function defined here is inherited by all scale types.
+  // Any function can be extended by the scale type
+
+  beforeUpdate() {
+    call(this.options.beforeUpdate, [this]);
+  }
+
+  /**
         * @param {number} maxWidth - the max width in pixels
         * @param {number} maxHeight - the max height in pixels
         * @param {{top: number, left: number, bottom: number, right: number}} margins - the space between the edge of the other scales and edge of the chart
@@ -521,1279 +521,1279 @@ export default class Scale extends Element {
         *     - padding - space that's required to show the labels at the edges of the scale
         *     - thickness of scales or legends in another orientation
         */
-       update(maxWidth, maxHeight, margins) {
-               const me = this;
-               const tickOpts = me.options.ticks;
-               const sampleSize = tickOpts.sampleSize;
-
-               // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
-               me.beforeUpdate();
-
-               // Absorb the master measurements
-               me.maxWidth = maxWidth;
-               me.maxHeight = maxHeight;
-               me._margins = Object.assign({
-                       left: 0,
-                       right: 0,
-                       top: 0,
-                       bottom: 0
-               }, margins);
-
-               me.ticks = null;
-               me._labelSizes = null;
-               me._gridLineItems = null;
-               me._labelItems = null;
-
-               // Dimensions
-               me.beforeSetDimensions();
-               me.setDimensions();
-               me.afterSetDimensions();
-
-               // Data min/max
-               if (!me._dataLimitsCached) {
-                       me.beforeDataLimits();
-                       me.determineDataLimits();
-                       me.afterDataLimits();
-                       me._dataLimitsCached = true;
-               }
-
-               me.beforeBuildTicks();
-
-               me.ticks = me.buildTicks() || [];
-
-               // Allow modification of ticks in callback.
-               me.afterBuildTicks();
-
-               // Compute tick rotation and fit using a sampled subset of labels
-               // We generally don't need to compute the size of every single label for determining scale size
-               const samplingEnabled = sampleSize < me.ticks.length;
-               me._convertTicksToLabels(samplingEnabled ? sample(me.ticks, sampleSize) : me.ticks);
-
-               // configure is called twice, once here, once from core.controller.updateLayout.
-               // Here we haven't been positioned yet, but dimensions are correct.
-               // Variables set in configure are needed for calculateLabelRotation, and
-               // it's ok that coordinates are not correct there, only dimensions matter.
-               me.configure();
-
-               // Tick Rotation
-               me.beforeCalculateLabelRotation();
-               me.calculateLabelRotation(); // Preconditions: number of ticks and sizes of largest labels must be calculated beforehand
-               me.afterCalculateLabelRotation();
-
-               me.beforeFit();
-               me.fit(); // Preconditions: label rotation and label sizes must be calculated beforehand
-               me.afterFit();
-
-               // Auto-skip
-               me.ticks = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(me.ticks) : me.ticks;
-
-               if (samplingEnabled) {
-                       // Generate labels using all non-skipped ticks
-                       me._convertTicksToLabels(me.ticks);
-               }
-
-               // IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
-
-               me.afterUpdate();
-       }
-
-       /**
+  update(maxWidth, maxHeight, margins) {
+    const me = this;
+    const tickOpts = me.options.ticks;
+    const sampleSize = tickOpts.sampleSize;
+
+    // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+    me.beforeUpdate();
+
+    // Absorb the master measurements
+    me.maxWidth = maxWidth;
+    me.maxHeight = maxHeight;
+    me._margins = Object.assign({
+      left: 0,
+      right: 0,
+      top: 0,
+      bottom: 0
+    }, margins);
+
+    me.ticks = null;
+    me._labelSizes = null;
+    me._gridLineItems = null;
+    me._labelItems = null;
+
+    // Dimensions
+    me.beforeSetDimensions();
+    me.setDimensions();
+    me.afterSetDimensions();
+
+    // Data min/max
+    if (!me._dataLimitsCached) {
+      me.beforeDataLimits();
+      me.determineDataLimits();
+      me.afterDataLimits();
+      me._dataLimitsCached = true;
+    }
+
+    me.beforeBuildTicks();
+
+    me.ticks = me.buildTicks() || [];
+
+    // Allow modification of ticks in callback.
+    me.afterBuildTicks();
+
+    // Compute tick rotation and fit using a sampled subset of labels
+    // We generally don't need to compute the size of every single label for determining scale size
+    const samplingEnabled = sampleSize < me.ticks.length;
+    me._convertTicksToLabels(samplingEnabled ? sample(me.ticks, sampleSize) : me.ticks);
+
+    // configure is called twice, once here, once from core.controller.updateLayout.
+    // Here we haven't been positioned yet, but dimensions are correct.
+    // Variables set in configure are needed for calculateLabelRotation, and
+    // it's ok that coordinates are not correct there, only dimensions matter.
+    me.configure();
+
+    // Tick Rotation
+    me.beforeCalculateLabelRotation();
+    me.calculateLabelRotation(); // Preconditions: number of ticks and sizes of largest labels must be calculated beforehand
+    me.afterCalculateLabelRotation();
+
+    me.beforeFit();
+    me.fit(); // Preconditions: label rotation and label sizes must be calculated beforehand
+    me.afterFit();
+
+    // Auto-skip
+    me.ticks = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(me.ticks) : me.ticks;
+
+    if (samplingEnabled) {
+      // Generate labels using all non-skipped ticks
+      me._convertTicksToLabels(me.ticks);
+    }
+
+    // IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!
+
+    me.afterUpdate();
+  }
+
+  /**
         * @protected
         */
-       configure() {
-               const me = this;
-               let reversePixels = me.options.reverse;
-               let startPixel, endPixel;
-
-               if (me.isHorizontal()) {
-                       startPixel = me.left;
-                       endPixel = me.right;
-               } else {
-                       startPixel = me.top;
-                       endPixel = me.bottom;
-                       // by default vertical scales are from bottom to top, so pixels are reversed
-                       reversePixels = !reversePixels;
-               }
-               me._startPixel = startPixel;
-               me._endPixel = endPixel;
-               me._reversePixels = reversePixels;
-               me._length = endPixel - startPixel;
-       }
-
-       afterUpdate() {
-               call(this.options.afterUpdate, [this]);
-       }
-
-       //
-
-       beforeSetDimensions() {
-               call(this.options.beforeSetDimensions, [this]);
-       }
-       setDimensions() {
-               const me = this;
-               // Set the unconstrained dimension before label rotation
-               if (me.isHorizontal()) {
-                       // Reset position before calculating rotation
-                       me.width = me.maxWidth;
-                       me.left = 0;
-                       me.right = me.width;
-               } else {
-                       me.height = me.maxHeight;
-
-                       // Reset position before calculating rotation
-                       me.top = 0;
-                       me.bottom = me.height;
-               }
-
-               // Reset padding
-               me.paddingLeft = 0;
-               me.paddingTop = 0;
-               me.paddingRight = 0;
-               me.paddingBottom = 0;
-       }
-       afterSetDimensions() {
-               call(this.options.afterSetDimensions, [this]);
-       }
-
-       _callHooks(name) {
-               const me = this;
-               me.chart.notifyPlugins(name, me.getContext());
-               call(me.options[name], [me]);
-       }
-
-       // Data limits
-       beforeDataLimits() {
-               this._callHooks('beforeDataLimits');
-       }
-       determineDataLimits() {}
-       afterDataLimits() {
-               this._callHooks('afterDataLimits');
-       }
-
-       //
-       beforeBuildTicks() {
-               this._callHooks('beforeBuildTicks');
-       }
-       /**
+  configure() {
+    const me = this;
+    let reversePixels = me.options.reverse;
+    let startPixel, endPixel;
+
+    if (me.isHorizontal()) {
+      startPixel = me.left;
+      endPixel = me.right;
+    } else {
+      startPixel = me.top;
+      endPixel = me.bottom;
+      // by default vertical scales are from bottom to top, so pixels are reversed
+      reversePixels = !reversePixels;
+    }
+    me._startPixel = startPixel;
+    me._endPixel = endPixel;
+    me._reversePixels = reversePixels;
+    me._length = endPixel - startPixel;
+  }
+
+  afterUpdate() {
+    call(this.options.afterUpdate, [this]);
+  }
+
+  //
+
+  beforeSetDimensions() {
+    call(this.options.beforeSetDimensions, [this]);
+  }
+  setDimensions() {
+    const me = this;
+    // Set the unconstrained dimension before label rotation
+    if (me.isHorizontal()) {
+      // Reset position before calculating rotation
+      me.width = me.maxWidth;
+      me.left = 0;
+      me.right = me.width;
+    } else {
+      me.height = me.maxHeight;
+
+      // Reset position before calculating rotation
+      me.top = 0;
+      me.bottom = me.height;
+    }
+
+    // Reset padding
+    me.paddingLeft = 0;
+    me.paddingTop = 0;
+    me.paddingRight = 0;
+    me.paddingBottom = 0;
+  }
+  afterSetDimensions() {
+    call(this.options.afterSetDimensions, [this]);
+  }
+
+  _callHooks(name) {
+    const me = this;
+    me.chart.notifyPlugins(name, me.getContext());
+    call(me.options[name], [me]);
+  }
+
+  // Data limits
+  beforeDataLimits() {
+    this._callHooks('beforeDataLimits');
+  }
+  determineDataLimits() {}
+  afterDataLimits() {
+    this._callHooks('afterDataLimits');
+  }
+
+  //
+  beforeBuildTicks() {
+    this._callHooks('beforeBuildTicks');
+  }
+  /**
         * @return {object[]} the ticks
         */
-       buildTicks() {
-               return [];
-       }
-       afterBuildTicks() {
-               this._callHooks('afterBuildTicks');
-       }
-
-       beforeTickToLabelConversion() {
-               call(this.options.beforeTickToLabelConversion, [this]);
-       }
-       /**
+  buildTicks() {
+    return [];
+  }
+  afterBuildTicks() {
+    this._callHooks('afterBuildTicks');
+  }
+
+  beforeTickToLabelConversion() {
+    call(this.options.beforeTickToLabelConversion, [this]);
+  }
+  /**
         * Convert ticks to label strings
         * @param {Tick[]} ticks
         */
-       generateTickLabels(ticks) {
-               const me = this;
-               const tickOpts = me.options.ticks;
-               let i, ilen, tick;
-               for (i = 0, ilen = ticks.length; i < ilen; i++) {
-                       tick = ticks[i];
-                       tick.label = call(tickOpts.callback, [tick.value, i, ticks], me);
-               }
-       }
-       afterTickToLabelConversion() {
-               call(this.options.afterTickToLabelConversion, [this]);
-       }
-
-       //
-
-       beforeCalculateLabelRotation() {
-               call(this.options.beforeCalculateLabelRotation, [this]);
-       }
-       calculateLabelRotation() {
-               const me = this;
-               const options = me.options;
-               const tickOpts = options.ticks;
-               const numTicks = me.ticks.length;
-               const minRotation = tickOpts.minRotation || 0;
-               const maxRotation = tickOpts.maxRotation;
-               let labelRotation = minRotation;
-               let tickWidth, maxHeight, maxLabelDiagonal;
-
-               if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {
-                       me.labelRotation = minRotation;
-                       return;
-               }
-
-               const labelSizes = me._getLabelSizes();
-               const maxLabelWidth = labelSizes.widest.width;
-               const maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;
-
-               // Estimate the width of each grid based on the canvas width, the maximum
-               // label width and the number of tick intervals
-               const maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);
-               tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);
-
-               // Allow 3 pixels x2 padding either side for label readability
-               if (maxLabelWidth + 6 > tickWidth) {
-                       tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
-                       maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)
+  generateTickLabels(ticks) {
+    const me = this;
+    const tickOpts = me.options.ticks;
+    let i, ilen, tick;
+    for (i = 0, ilen = ticks.length; i < ilen; i++) {
+      tick = ticks[i];
+      tick.label = call(tickOpts.callback, [tick.value, i, ticks], me);
+    }
+  }
+  afterTickToLabelConversion() {
+    call(this.options.afterTickToLabelConversion, [this]);
+  }
+
+  //
+
+  beforeCalculateLabelRotation() {
+    call(this.options.beforeCalculateLabelRotation, [this]);
+  }
+  calculateLabelRotation() {
+    const me = this;
+    const options = me.options;
+    const tickOpts = options.ticks;
+    const numTicks = me.ticks.length;
+    const minRotation = tickOpts.minRotation || 0;
+    const maxRotation = tickOpts.maxRotation;
+    let labelRotation = minRotation;
+    let tickWidth, maxHeight, maxLabelDiagonal;
+
+    if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {
+      me.labelRotation = minRotation;
+      return;
+    }
+
+    const labelSizes = me._getLabelSizes();
+    const maxLabelWidth = labelSizes.widest.width;
+    const maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;
+
+    // Estimate the width of each grid based on the canvas width, the maximum
+    // label width and the number of tick intervals
+    const maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);
+    tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);
+
+    // Allow 3 pixels x2 padding either side for label readability
+    if (maxLabelWidth + 6 > tickWidth) {
+      tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
+      maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)
                                - tickOpts.padding - getScaleLabelHeight(options.scaleLabel, me.chart.options.font);
-                       maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
-                       labelRotation = toDegrees(Math.min(
-                               Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),
-                               Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)
-                       ));
-                       labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
-               }
-
-               me.labelRotation = labelRotation;
-       }
-       afterCalculateLabelRotation() {
-               call(this.options.afterCalculateLabelRotation, [this]);
-       }
-
-       //
-
-       beforeFit() {
-               call(this.options.beforeFit, [this]);
-       }
-       fit() {
-               const me = this;
-               // Reset
-               const minSize = {
-                       width: 0,
-                       height: 0
-               };
-
-               const chart = me.chart;
-               const opts = me.options;
-               const tickOpts = opts.ticks;
-               const scaleLabelOpts = opts.scaleLabel;
-               const gridLineOpts = opts.gridLines;
-               const display = me._isVisible();
-               const labelsBelowTicks = opts.position !== 'top' && me.axis === 'x';
-               const isHorizontal = me.isHorizontal();
-               const scaleLabelHeight = display && getScaleLabelHeight(scaleLabelOpts, chart.options.font);
-
-               // Width
-               if (isHorizontal) {
-                       minSize.width = me.maxWidth;
-               } else if (display) {
-                       minSize.width = getTickMarkLength(gridLineOpts) + scaleLabelHeight;
-               }
-
-               // height
-               if (!isHorizontal) {
-                       minSize.height = me.maxHeight; // fill all the height
-               } else if (display) {
-                       minSize.height = getTickMarkLength(gridLineOpts) + scaleLabelHeight;
-               }
-
-               // Don't bother fitting the ticks if we are not showing the labels
-               if (tickOpts.display && display && me.ticks.length) {
-                       const labelSizes = me._getLabelSizes();
-                       const firstLabelSize = labelSizes.first;
-                       const lastLabelSize = labelSizes.last;
-                       const widestLabelSize = labelSizes.widest;
-                       const highestLabelSize = labelSizes.highest;
-                       const lineSpace = highestLabelSize.offset * 0.8;
-                       const tickPadding = tickOpts.padding;
-
-                       if (isHorizontal) {
-                               // A horizontal axis is more constrained by the height.
-                               const isRotated = me.labelRotation !== 0;
-                               const angleRadians = toRadians(me.labelRotation);
-                               const cosRotation = Math.cos(angleRadians);
-                               const sinRotation = Math.sin(angleRadians);
-
-                               const labelHeight = sinRotation * widestLabelSize.width
+      maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
+      labelRotation = toDegrees(Math.min(
+        Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),
+        Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)
+      ));
+      labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
+    }
+
+    me.labelRotation = labelRotation;
+  }
+  afterCalculateLabelRotation() {
+    call(this.options.afterCalculateLabelRotation, [this]);
+  }
+
+  //
+
+  beforeFit() {
+    call(this.options.beforeFit, [this]);
+  }
+  fit() {
+    const me = this;
+    // Reset
+    const minSize = {
+      width: 0,
+      height: 0
+    };
+
+    const chart = me.chart;
+    const opts = me.options;
+    const tickOpts = opts.ticks;
+    const scaleLabelOpts = opts.scaleLabel;
+    const gridLineOpts = opts.gridLines;
+    const display = me._isVisible();
+    const labelsBelowTicks = opts.position !== 'top' && me.axis === 'x';
+    const isHorizontal = me.isHorizontal();
+    const scaleLabelHeight = display && getScaleLabelHeight(scaleLabelOpts, chart.options.font);
+
+    // Width
+    if (isHorizontal) {
+      minSize.width = me.maxWidth;
+    } else if (display) {
+      minSize.width = getTickMarkLength(gridLineOpts) + scaleLabelHeight;
+    }
+
+    // height
+    if (!isHorizontal) {
+      minSize.height = me.maxHeight; // fill all the height
+    } else if (display) {
+      minSize.height = getTickMarkLength(gridLineOpts) + scaleLabelHeight;
+    }
+
+    // Don't bother fitting the ticks if we are not showing the labels
+    if (tickOpts.display && display && me.ticks.length) {
+      const labelSizes = me._getLabelSizes();
+      const firstLabelSize = labelSizes.first;
+      const lastLabelSize = labelSizes.last;
+      const widestLabelSize = labelSizes.widest;
+      const highestLabelSize = labelSizes.highest;
+      const lineSpace = highestLabelSize.offset * 0.8;
+      const tickPadding = tickOpts.padding;
+
+      if (isHorizontal) {
+        // A horizontal axis is more constrained by the height.
+        const isRotated = me.labelRotation !== 0;
+        const angleRadians = toRadians(me.labelRotation);
+        const cosRotation = Math.cos(angleRadians);
+        const sinRotation = Math.sin(angleRadians);
+
+        const labelHeight = sinRotation * widestLabelSize.width
                                        + cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0))
                                        + (isRotated ? 0 : lineSpace); // padding
 
-                               minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
-
-                               const offsetLeft = me.getPixelForTick(0) - me.left;
-                               const offsetRight = me.right - me.getPixelForTick(me.ticks.length - 1);
-                               let paddingLeft, paddingRight;
-
-                               // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
-                               // which means that the right padding is dominated by the font height
-                               if (isRotated) {
-                                       paddingLeft = labelsBelowTicks ?
-                                               cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :
-                                               sinRotation * (firstLabelSize.height - firstLabelSize.offset);
-                                       paddingRight = labelsBelowTicks ?
-                                               sinRotation * (lastLabelSize.height - lastLabelSize.offset) :
-                                               cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;
-                               } else if (tickOpts.align === 'start') {
-                                       paddingLeft = 0;
-                                       paddingRight = lastLabelSize.width;
-                               } else if (tickOpts.align === 'end') {
-                                       paddingLeft = firstLabelSize.width;
-                                       paddingRight = 0;
-                               } else {
-                                       paddingLeft = firstLabelSize.width / 2;
-                                       paddingRight = lastLabelSize.width / 2;
-                               }
-
-                               // Adjust padding taking into account changes in offsets
-                               // and add 3 px to move away from canvas edges
-                               me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
-                               me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;
-                       } else {
-                               // A vertical axis is more constrained by the width. Labels are the
-                               // dominant factor here, so get that length first and account for padding
-                               const labelWidth = tickOpts.mirror ? 0 :
-                                       // use lineSpace for consistency with horizontal axis
-                                       // tickPadding is not implemented for horizontal
-                                       widestLabelSize.width + tickPadding + lineSpace;
-
-                               minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);
-
-                               let paddingTop = lastLabelSize.height / 2;
-                               let paddingBottom = firstLabelSize.height / 2;
-
-                               if (tickOpts.align === 'start') {
-                                       paddingTop = 0;
-                                       paddingBottom = firstLabelSize.height;
-                               } else if (tickOpts.align === 'end') {
-                                       paddingTop = lastLabelSize.height;
-                                       paddingBottom = 0;
-                               }
-
-                               me.paddingTop = paddingTop;
-                               me.paddingBottom = paddingBottom;
-                       }
-               }
-
-               me._handleMargins();
-
-               if (isHorizontal) {
-                       me.width = me._length = chart.width - me._margins.left - me._margins.right;
-                       me.height = minSize.height;
-               } else {
-                       me.width = minSize.width;
-                       me.height = me._length = chart.height - me._margins.top - me._margins.bottom;
-               }
-       }
-
-       /**
+        minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
+
+        const offsetLeft = me.getPixelForTick(0) - me.left;
+        const offsetRight = me.right - me.getPixelForTick(me.ticks.length - 1);
+        let paddingLeft, paddingRight;
+
+        // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
+        // which means that the right padding is dominated by the font height
+        if (isRotated) {
+          paddingLeft = labelsBelowTicks ?
+            cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :
+            sinRotation * (firstLabelSize.height - firstLabelSize.offset);
+          paddingRight = labelsBelowTicks ?
+            sinRotation * (lastLabelSize.height - lastLabelSize.offset) :
+            cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;
+        } else if (tickOpts.align === 'start') {
+          paddingLeft = 0;
+          paddingRight = lastLabelSize.width;
+        } else if (tickOpts.align === 'end') {
+          paddingLeft = firstLabelSize.width;
+          paddingRight = 0;
+        } else {
+          paddingLeft = firstLabelSize.width / 2;
+          paddingRight = lastLabelSize.width / 2;
+        }
+
+        // Adjust padding taking into account changes in offsets
+        // and add 3 px to move away from canvas edges
+        me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
+        me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;
+      } else {
+        // A vertical axis is more constrained by the width. Labels are the
+        // dominant factor here, so get that length first and account for padding
+        const labelWidth = tickOpts.mirror ? 0 :
+        // use lineSpace for consistency with horizontal axis
+        // tickPadding is not implemented for horizontal
+          widestLabelSize.width + tickPadding + lineSpace;
+
+        minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);
+
+        let paddingTop = lastLabelSize.height / 2;
+        let paddingBottom = firstLabelSize.height / 2;
+
+        if (tickOpts.align === 'start') {
+          paddingTop = 0;
+          paddingBottom = firstLabelSize.height;
+        } else if (tickOpts.align === 'end') {
+          paddingTop = lastLabelSize.height;
+          paddingBottom = 0;
+        }
+
+        me.paddingTop = paddingTop;
+        me.paddingBottom = paddingBottom;
+      }
+    }
+
+    me._handleMargins();
+
+    if (isHorizontal) {
+      me.width = me._length = chart.width - me._margins.left - me._margins.right;
+      me.height = minSize.height;
+    } else {
+      me.width = minSize.width;
+      me.height = me._length = chart.height - me._margins.top - me._margins.bottom;
+    }
+  }
+
+  /**
         * Handle margins and padding interactions
         * @private
         */
-       _handleMargins() {
-               const me = this;
-               if (me._margins) {
-                       me._margins.left = Math.max(me.paddingLeft, me._margins.left);
-                       me._margins.top = Math.max(me.paddingTop, me._margins.top);
-                       me._margins.right = Math.max(me.paddingRight, me._margins.right);
-                       me._margins.bottom = Math.max(me.paddingBottom, me._margins.bottom);
-               }
-       }
-
-       afterFit() {
-               call(this.options.afterFit, [this]);
-       }
-
-       // Shared Methods
-       /**
+  _handleMargins() {
+    const me = this;
+    if (me._margins) {
+      me._margins.left = Math.max(me.paddingLeft, me._margins.left);
+      me._margins.top = Math.max(me.paddingTop, me._margins.top);
+      me._margins.right = Math.max(me.paddingRight, me._margins.right);
+      me._margins.bottom = Math.max(me.paddingBottom, me._margins.bottom);
+    }
+  }
+
+  afterFit() {
+    call(this.options.afterFit, [this]);
+  }
+
+  // Shared Methods
+  /**
         * @return {boolean}
         */
-       isHorizontal() {
-               const {axis, position} = this.options;
-               return position === 'top' || position === 'bottom' || axis === 'x';
-       }
-       /**
+  isHorizontal() {
+    const {axis, position} = this.options;
+    return position === 'top' || position === 'bottom' || axis === 'x';
+  }
+  /**
         * @return {boolean}
         */
-       isFullSize() {
-               return this.options.fullSize;
-       }
+  isFullSize() {
+    return this.options.fullSize;
+  }
 
-       /**
+  /**
         * @param {Tick[]} ticks
         * @private
         */
-       _convertTicksToLabels(ticks) {
-               const me = this;
+  _convertTicksToLabels(ticks) {
+    const me = this;
 
-               me.beforeTickToLabelConversion();
+    me.beforeTickToLabelConversion();
 
-               me.generateTickLabels(ticks);
+    me.generateTickLabels(ticks);
 
-               me.afterTickToLabelConversion();
-       }
+    me.afterTickToLabelConversion();
+  }
 
-       /**
+  /**
         * @return {{ first: object, last: object, widest: object, highest: object }}
         * @private
         */
-       _getLabelSizes() {
-               const me = this;
-               let labelSizes = me._labelSizes;
+  _getLabelSizes() {
+    const me = this;
+    let labelSizes = me._labelSizes;
 
-               if (!labelSizes) {
-                       me._labelSizes = labelSizes = me._computeLabelSizes();
-               }
+    if (!labelSizes) {
+      me._labelSizes = labelSizes = me._computeLabelSizes();
+    }
 
-               return labelSizes;
-       }
+    return labelSizes;
+  }
 
-       /**
+  /**
         * Returns {width, height, offset} objects for the first, last, widest, highest tick
         * labels where offset indicates the anchor point offset from the top in pixels.
         * @return {{ first: object, last: object, widest: object, highest: object }}
         * @private
         */
-       _computeLabelSizes() {
-               const me = this;
-               const ctx = me.ctx;
-               const caches = me._longestTextCache;
-               const sampleSize = me.options.ticks.sampleSize;
-               const widths = [];
-               const heights = [];
-               const offsets = [];
-               let widestLabelSize = 0;
-               let highestLabelSize = 0;
-               let ticks = me.ticks;
-               if (sampleSize < ticks.length) {
-                       ticks = sample(ticks, sampleSize);
-               }
-               const length = ticks.length;
-               let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
-
-               for (i = 0; i < length; ++i) {
-                       label = ticks[i].label;
-                       tickFont = me._resolveTickFontOptions(i);
-                       ctx.font = fontString = tickFont.string;
-                       cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
-                       lineHeight = tickFont.lineHeight;
-                       width = height = 0;
-                       // Undefined labels and arrays should not be measured
-                       if (!isNullOrUndef(label) && !isArray(label)) {
-                               width = _measureText(ctx, cache.data, cache.gc, width, label);
-                               height = lineHeight;
-                       } else if (isArray(label)) {
-                               // if it is an array let's measure each element
-                               for (j = 0, jlen = label.length; j < jlen; ++j) {
-                                       nestedLabel = label[j];
-                                       // Undefined labels and arrays should not be measured
-                                       if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
-                                               width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);
-                                               height += lineHeight;
-                                       }
-                               }
-                       }
-                       widths.push(width);
-                       heights.push(height);
-                       offsets.push(lineHeight / 2);
-                       widestLabelSize = Math.max(width, widestLabelSize);
-                       highestLabelSize = Math.max(height, highestLabelSize);
-               }
-               garbageCollect(caches, length);
-
-               const widest = widths.indexOf(widestLabelSize);
-               const highest = heights.indexOf(highestLabelSize);
-
-               function valueAt(idx) {
-                       return {
-                               width: widths[idx] || 0,
-                               height: heights[idx] || 0,
-                               offset: offsets[idx] || 0
-                       };
-               }
-
-               return {
-                       first: valueAt(0),
-                       last: valueAt(length - 1),
-                       widest: valueAt(widest),
-                       highest: valueAt(highest)
-               };
-       }
-
-       /**
+  _computeLabelSizes() {
+    const me = this;
+    const ctx = me.ctx;
+    const caches = me._longestTextCache;
+    const sampleSize = me.options.ticks.sampleSize;
+    const widths = [];
+    const heights = [];
+    const offsets = [];
+    let widestLabelSize = 0;
+    let highestLabelSize = 0;
+    let ticks = me.ticks;
+    if (sampleSize < ticks.length) {
+      ticks = sample(ticks, sampleSize);
+    }
+    const length = ticks.length;
+    let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
+
+    for (i = 0; i < length; ++i) {
+      label = ticks[i].label;
+      tickFont = me._resolveTickFontOptions(i);
+      ctx.font = fontString = tickFont.string;
+      cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
+      lineHeight = tickFont.lineHeight;
+      width = height = 0;
+      // Undefined labels and arrays should not be measured
+      if (!isNullOrUndef(label) && !isArray(label)) {
+        width = _measureText(ctx, cache.data, cache.gc, width, label);
+        height = lineHeight;
+      } else if (isArray(label)) {
+        // if it is an array let's measure each element
+        for (j = 0, jlen = label.length; j < jlen; ++j) {
+          nestedLabel = label[j];
+          // Undefined labels and arrays should not be measured
+          if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
+            width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);
+            height += lineHeight;
+          }
+        }
+      }
+      widths.push(width);
+      heights.push(height);
+      offsets.push(lineHeight / 2);
+      widestLabelSize = Math.max(width, widestLabelSize);
+      highestLabelSize = Math.max(height, highestLabelSize);
+    }
+    garbageCollect(caches, length);
+
+    const widest = widths.indexOf(widestLabelSize);
+    const highest = heights.indexOf(highestLabelSize);
+
+    function valueAt(idx) {
+      return {
+        width: widths[idx] || 0,
+        height: heights[idx] || 0,
+        offset: offsets[idx] || 0
+      };
+    }
+
+    return {
+      first: valueAt(0),
+      last: valueAt(length - 1),
+      widest: valueAt(widest),
+      highest: valueAt(highest)
+    };
+  }
+
+  /**
         * Used to get the label to display in the tooltip for the given value
         * @param {*} value
         * @return {string}
         */
-       getLabelForValue(value) {
-               return value;
-       }
+  getLabelForValue(value) {
+    return value;
+  }
 
-       /**
+  /**
         * Returns the location of the given data point. Value can either be an index or a numerical value
         * The coordinate (0, 0) is at the upper-left corner of the canvas
         * @param {*} value
         * @param {number} [index]
         * @return {number}
         */
-       getPixelForValue(value, index) { // eslint-disable-line no-unused-vars
-               return NaN;
-       }
+  getPixelForValue(value, index) { // eslint-disable-line no-unused-vars
+    return NaN;
+  }
 
-       /**
+  /**
         * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
         * The coordinate (0, 0) is at the upper-left corner of the canvas
         * @param {number} pixel
         * @return {*}
         */
-       getValueForPixel(pixel) {} // eslint-disable-line no-unused-vars
+  getValueForPixel(pixel) {} // eslint-disable-line no-unused-vars
 
-       /**
+  /**
         * Returns the location of the tick at the given index
         * The coordinate (0, 0) is at the upper-left corner of the canvas
         * @param {number} index
         * @return {number}
         */
-       getPixelForTick(index) {
-               const ticks = this.ticks;
-               if (index < 0 || index > ticks.length - 1) {
-                       return null;
-               }
-               return this.getPixelForValue(ticks[index].value);
-       }
-
-       /**
+  getPixelForTick(index) {
+    const ticks = this.ticks;
+    if (index < 0 || index > ticks.length - 1) {
+      return null;
+    }
+    return this.getPixelForValue(ticks[index].value);
+  }
+
+  /**
         * Utility for getting the pixel location of a percentage of scale
         * The coordinate (0, 0) is at the upper-left corner of the canvas
         * @param {number} decimal
         * @return {number}
         */
-       getPixelForDecimal(decimal) {
-               const me = this;
+  getPixelForDecimal(decimal) {
+    const me = this;
 
-               if (me._reversePixels) {
-                       decimal = 1 - decimal;
-               }
+    if (me._reversePixels) {
+      decimal = 1 - decimal;
+    }
 
-               return _int16Range(me._startPixel + decimal * me._length);
-       }
+    return _int16Range(me._startPixel + decimal * me._length);
+  }
 
-       /**
+  /**
         * @param {number} pixel
         * @return {number}
         */
-       getDecimalForPixel(pixel) {
-               const decimal = (pixel - this._startPixel) / this._length;
-               return this._reversePixels ? 1 - decimal : decimal;
-       }
+  getDecimalForPixel(pixel) {
+    const decimal = (pixel - this._startPixel) / this._length;
+    return this._reversePixels ? 1 - decimal : decimal;
+  }
 
-       /**
+  /**
         * Returns the pixel for the minimum chart value
         * The coordinate (0, 0) is at the upper-left corner of the canvas
         * @return {number}
         */
-       getBasePixel() {
-               return this.getPixelForValue(this.getBaseValue());
-       }
+  getBasePixel() {
+    return this.getPixelForValue(this.getBaseValue());
+  }
 
-       /**
+  /**
         * @return {number}
         */
-       getBaseValue() {
-               const {min, max} = this;
+  getBaseValue() {
+    const {min, max} = this;
 
-               return min < 0 && max < 0 ? max :
-                       min > 0 && max > 0 ? min :
-                       0;
-       }
+    return min < 0 && max < 0 ? max :
+      min > 0 && max > 0 ? min :
+      0;
+  }
 
-       /**
+  /**
         * @protected
         */
-       getContext(index) {
-               const me = this;
-               const ticks = me.ticks || [];
+  getContext(index) {
+    const me = this;
+    const ticks = me.ticks || [];
 
-               if (index >= 0 && index < ticks.length) {
-                       const tick = ticks[index];
-                       return tick.$context ||
+    if (index >= 0 && index < ticks.length) {
+      const tick = ticks[index];
+      return tick.$context ||
                                (tick.$context = createTickContext(me.getContext(), index, tick));
-               }
-               return me.$context ||
+    }
+    return me.$context ||
                        (me.$context = createScaleContext(me.chart.getContext(), me));
-       }
+  }
 
-       /**
+  /**
         * Returns a subset of ticks to be plotted to avoid overlapping labels.
         * @param {Tick[]} ticks
         * @return {Tick[]}
         * @private
         */
-       _autoSkip(ticks) {
-               const me = this;
-               const tickOpts = me.options.ticks;
-               const ticksLimit = tickOpts.maxTicksLimit || me._length / me._tickSize();
-               const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
-               const numMajorIndices = majorIndices.length;
-               const first = majorIndices[0];
-               const last = majorIndices[numMajorIndices - 1];
-               const newTicks = [];
-
-               // If there are too many major ticks to display them all
-               if (numMajorIndices > ticksLimit) {
-                       skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
-                       return newTicks;
-               }
-
-               const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
-
-               if (numMajorIndices > 0) {
-                       let i, ilen;
-                       const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
-                       skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
-                       for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
-                               skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
-                       }
-                       skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
-                       return newTicks;
-               }
-               skip(ticks, newTicks, spacing);
-               return newTicks;
-       }
-
-       /**
+  _autoSkip(ticks) {
+    const me = this;
+    const tickOpts = me.options.ticks;
+    const ticksLimit = tickOpts.maxTicksLimit || me._length / me._tickSize();
+    const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
+    const numMajorIndices = majorIndices.length;
+    const first = majorIndices[0];
+    const last = majorIndices[numMajorIndices - 1];
+    const newTicks = [];
+
+    // If there are too many major ticks to display them all
+    if (numMajorIndices > ticksLimit) {
+      skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
+      return newTicks;
+    }
+
+    const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
+
+    if (numMajorIndices > 0) {
+      let i, ilen;
+      const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
+      skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
+      for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
+        skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
+      }
+      skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
+      return newTicks;
+    }
+    skip(ticks, newTicks, spacing);
+    return newTicks;
+  }
+
+  /**
         * @return {number}
         * @private
         */
-       _tickSize() {
-               const me = this;
-               const optionTicks = me.options.ticks;
-
-               // Calculate space needed by label in axis direction.
-               const rot = toRadians(me.labelRotation);
-               const cos = Math.abs(Math.cos(rot));
-               const sin = Math.abs(Math.sin(rot));
-
-               const labelSizes = me._getLabelSizes();
-               const padding = optionTicks.autoSkipPadding || 0;
-               const w = labelSizes ? labelSizes.widest.width + padding : 0;
-               const h = labelSizes ? labelSizes.highest.height + padding : 0;
-
-               // Calculate space needed for 1 tick in axis direction.
-               return me.isHorizontal()
-                       ? h * cos > w * sin ? w / cos : h / sin
-                       : h * sin < w * cos ? h / cos : w / sin;
-       }
-
-       /**
+  _tickSize() {
+    const me = this;
+    const optionTicks = me.options.ticks;
+
+    // Calculate space needed by label in axis direction.
+    const rot = toRadians(me.labelRotation);
+    const cos = Math.abs(Math.cos(rot));
+    const sin = Math.abs(Math.sin(rot));
+
+    const labelSizes = me._getLabelSizes();
+    const padding = optionTicks.autoSkipPadding || 0;
+    const w = labelSizes ? labelSizes.widest.width + padding : 0;
+    const h = labelSizes ? labelSizes.highest.height + padding : 0;
+
+    // Calculate space needed for 1 tick in axis direction.
+    return me.isHorizontal()
+      ? h * cos > w * sin ? w / cos : h / sin
+      : h * sin < w * cos ? h / cos : w / sin;
+  }
+
+  /**
         * @return {boolean}
         * @private
         */
-       _isVisible() {
-               const display = this.options.display;
+  _isVisible() {
+    const display = this.options.display;
 
-               if (display !== 'auto') {
-                       return !!display;
-               }
+    if (display !== 'auto') {
+      return !!display;
+    }
 
-               return this.getMatchingVisibleMetas().length > 0;
-       }
+    return this.getMatchingVisibleMetas().length > 0;
+  }
 
-       /**
+  /**
         * @private
         */
-       _computeGridLineItems(chartArea) {
-               const me = this;
-               const axis = me.axis;
-               const chart = me.chart;
-               const options = me.options;
-               const {gridLines, position} = options;
-               const offsetGridLines = gridLines.offsetGridLines;
-               const isHorizontal = me.isHorizontal();
-               const ticks = me.ticks;
-               const ticksLength = ticks.length + (offsetGridLines ? 1 : 0);
-               const tl = getTickMarkLength(gridLines);
-               const items = [];
-
-               let context = this.getContext(0);
-               const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0;
-               const axisHalfWidth = axisWidth / 2;
-               const alignBorderValue = function(pixel) {
-                       return _alignPixel(chart, pixel, axisWidth);
-               };
-               let borderValue, i, lineValue, alignedLineValue;
-               let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
-
-               if (position === 'top') {
-                       borderValue = alignBorderValue(me.bottom);
-                       ty1 = me.bottom - tl;
-                       ty2 = borderValue - axisHalfWidth;
-                       y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
-                       y2 = chartArea.bottom;
-               } else if (position === 'bottom') {
-                       borderValue = alignBorderValue(me.top);
-                       y1 = chartArea.top;
-                       y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
-                       ty1 = borderValue + axisHalfWidth;
-                       ty2 = me.top + tl;
-               } else if (position === 'left') {
-                       borderValue = alignBorderValue(me.right);
-                       tx1 = me.right - tl;
-                       tx2 = borderValue - axisHalfWidth;
-                       x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
-                       x2 = chartArea.right;
-               } else if (position === 'right') {
-                       borderValue = alignBorderValue(me.left);
-                       x1 = chartArea.left;
-                       x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
-                       tx1 = borderValue + axisHalfWidth;
-                       tx2 = me.left + tl;
-               } else if (axis === 'x') {
-                       if (position === 'center') {
-                               borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2);
-                       } else if (isObject(position)) {
-                               const positionAxisID = Object.keys(position)[0];
-                               const value = position[positionAxisID];
-                               borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value));
-                       }
-
-                       y1 = chartArea.top;
-                       y2 = chartArea.bottom;
-                       ty1 = borderValue + axisHalfWidth;
-                       ty2 = ty1 + tl;
-               } else if (axis === 'y') {
-                       if (position === 'center') {
-                               borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
-                       } else if (isObject(position)) {
-                               const positionAxisID = Object.keys(position)[0];
-                               const value = position[positionAxisID];
-                               borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value));
-                       }
-
-                       tx1 = borderValue - axisHalfWidth;
-                       tx2 = tx1 - tl;
-                       x1 = chartArea.left;
-                       x2 = chartArea.right;
-               }
-
-               for (i = 0; i < ticksLength; ++i) {
-                       context = this.getContext(i);
-
-                       const lineWidth = resolve([gridLines.lineWidth], context, i);
-                       const lineColor = resolve([gridLines.color], context, i);
-                       const borderDash = gridLines.borderDash || [];
-                       const borderDashOffset = resolve([gridLines.borderDashOffset], context, i);
-
-                       const tickWidth = resolve([gridLines.tickWidth, lineWidth], context, i);
-                       const tickColor = resolve([gridLines.tickColor, lineColor], context, i);
-                       const tickBorderDash = gridLines.tickBorderDash || borderDash;
-                       const tickBorderDashOffset = resolve([gridLines.tickBorderDashOffset, borderDashOffset], context, i);
-
-                       lineValue = getPixelForGridLine(me, i, offsetGridLines);
-
-                       // Skip if the pixel is out of the range
-                       if (lineValue === undefined) {
-                               continue;
-                       }
-
-                       alignedLineValue = _alignPixel(chart, lineValue, lineWidth);
-
-                       if (isHorizontal) {
-                               tx1 = tx2 = x1 = x2 = alignedLineValue;
-                       } else {
-                               ty1 = ty2 = y1 = y2 = alignedLineValue;
-                       }
-
-                       items.push({
-                               tx1,
-                               ty1,
-                               tx2,
-                               ty2,
-                               x1,
-                               y1,
-                               x2,
-                               y2,
-                               width: lineWidth,
-                               color: lineColor,
-                               borderDash,
-                               borderDashOffset,
-                               tickWidth,
-                               tickColor,
-                               tickBorderDash,
-                               tickBorderDashOffset,
-                       });
-               }
-
-               me._ticksLength = ticksLength;
-               me._borderValue = borderValue;
-
-               return items;
-       }
-
-       /**
+  _computeGridLineItems(chartArea) {
+    const me = this;
+    const axis = me.axis;
+    const chart = me.chart;
+    const options = me.options;
+    const {gridLines, position} = options;
+    const offsetGridLines = gridLines.offsetGridLines;
+    const isHorizontal = me.isHorizontal();
+    const ticks = me.ticks;
+    const ticksLength = ticks.length + (offsetGridLines ? 1 : 0);
+    const tl = getTickMarkLength(gridLines);
+    const items = [];
+
+    let context = this.getContext(0);
+    const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0;
+    const axisHalfWidth = axisWidth / 2;
+    const alignBorderValue = function(pixel) {
+      return _alignPixel(chart, pixel, axisWidth);
+    };
+    let borderValue, i, lineValue, alignedLineValue;
+    let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
+
+    if (position === 'top') {
+      borderValue = alignBorderValue(me.bottom);
+      ty1 = me.bottom - tl;
+      ty2 = borderValue - axisHalfWidth;
+      y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
+      y2 = chartArea.bottom;
+    } else if (position === 'bottom') {
+      borderValue = alignBorderValue(me.top);
+      y1 = chartArea.top;
+      y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
+      ty1 = borderValue + axisHalfWidth;
+      ty2 = me.top + tl;
+    } else if (position === 'left') {
+      borderValue = alignBorderValue(me.right);
+      tx1 = me.right - tl;
+      tx2 = borderValue - axisHalfWidth;
+      x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
+      x2 = chartArea.right;
+    } else if (position === 'right') {
+      borderValue = alignBorderValue(me.left);
+      x1 = chartArea.left;
+      x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
+      tx1 = borderValue + axisHalfWidth;
+      tx2 = me.left + tl;
+    } else if (axis === 'x') {
+      if (position === 'center') {
+        borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2);
+      } else if (isObject(position)) {
+        const positionAxisID = Object.keys(position)[0];
+        const value = position[positionAxisID];
+        borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value));
+      }
+
+      y1 = chartArea.top;
+      y2 = chartArea.bottom;
+      ty1 = borderValue + axisHalfWidth;
+      ty2 = ty1 + tl;
+    } else if (axis === 'y') {
+      if (position === 'center') {
+        borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
+      } else if (isObject(position)) {
+        const positionAxisID = Object.keys(position)[0];
+        const value = position[positionAxisID];
+        borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value));
+      }
+
+      tx1 = borderValue - axisHalfWidth;
+      tx2 = tx1 - tl;
+      x1 = chartArea.left;
+      x2 = chartArea.right;
+    }
+
+    for (i = 0; i < ticksLength; ++i) {
+      context = this.getContext(i);
+
+      const lineWidth = resolve([gridLines.lineWidth], context, i);
+      const lineColor = resolve([gridLines.color], context, i);
+      const borderDash = gridLines.borderDash || [];
+      const borderDashOffset = resolve([gridLines.borderDashOffset], context, i);
+
+      const tickWidth = resolve([gridLines.tickWidth, lineWidth], context, i);
+      const tickColor = resolve([gridLines.tickColor, lineColor], context, i);
+      const tickBorderDash = gridLines.tickBorderDash || borderDash;
+      const tickBorderDashOffset = resolve([gridLines.tickBorderDashOffset, borderDashOffset], context, i);
+
+      lineValue = getPixelForGridLine(me, i, offsetGridLines);
+
+      // Skip if the pixel is out of the range
+      if (lineValue === undefined) {
+        continue;
+      }
+
+      alignedLineValue = _alignPixel(chart, lineValue, lineWidth);
+
+      if (isHorizontal) {
+        tx1 = tx2 = x1 = x2 = alignedLineValue;
+      } else {
+        ty1 = ty2 = y1 = y2 = alignedLineValue;
+      }
+
+      items.push({
+        tx1,
+        ty1,
+        tx2,
+        ty2,
+        x1,
+        y1,
+        x2,
+        y2,
+        width: lineWidth,
+        color: lineColor,
+        borderDash,
+        borderDashOffset,
+        tickWidth,
+        tickColor,
+        tickBorderDash,
+        tickBorderDashOffset,
+      });
+    }
+
+    me._ticksLength = ticksLength;
+    me._borderValue = borderValue;
+
+    return items;
+  }
+
+  /**
         * @private
         */
-       _computeLabelItems(chartArea) {
-               const me = this;
-               const axis = me.axis;
-               const options = me.options;
-               const {position, ticks: optionTicks} = options;
-               const isHorizontal = me.isHorizontal();
-               const ticks = me.ticks;
-               const {align, crossAlign, padding} = optionTicks;
-               const tl = getTickMarkLength(options.gridLines);
-               const tickAndPadding = tl + padding;
-               const rotation = -toRadians(me.labelRotation);
-               const items = [];
-               let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
-               let textBaseline = 'middle';
-
-               if (position === 'top') {
-                       y = me.bottom - tickAndPadding;
-                       textAlign = me._getXAxisLabelAlignment();
-               } else if (position === 'bottom') {
-                       y = me.top + tickAndPadding;
-                       textAlign = me._getXAxisLabelAlignment();
-               } else if (position === 'left') {
-                       const ret = this._getYAxisLabelAlignment(tl);
-                       textAlign = ret.textAlign;
-                       x = ret.x;
-               } else if (position === 'right') {
-                       const ret = this._getYAxisLabelAlignment(tl);
-                       textAlign = ret.textAlign;
-                       x = ret.x;
-               } else if (axis === 'x') {
-                       if (position === 'center') {
-                               y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding;
-                       } else if (isObject(position)) {
-                               const positionAxisID = Object.keys(position)[0];
-                               const value = position[positionAxisID];
-                               y = me.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
-                       }
-                       textAlign = me._getXAxisLabelAlignment();
-               } else if (axis === 'y') {
-                       if (position === 'center') {
-                               x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding;
-                       } else if (isObject(position)) {
-                               const positionAxisID = Object.keys(position)[0];
-                               const value = position[positionAxisID];
-                               x = me.chart.scales[positionAxisID].getPixelForValue(value);
-                       }
-                       textAlign = this._getYAxisLabelAlignment(tl).textAlign;
-               }
-
-               if (axis === 'y') {
-                       if (align === 'start') {
-                               textBaseline = 'top';
-                       } else if (align === 'end') {
-                               textBaseline = 'bottom';
-                       }
-               }
-
-               const labelSizes = me._getLabelSizes();
-               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
-                       tick = ticks[i];
-                       label = tick.label;
-
-                       pixel = me.getPixelForTick(i) + optionTicks.labelOffset;
-                       font = me._resolveTickFontOptions(i);
-                       lineHeight = font.lineHeight;
-                       lineCount = isArray(label) ? label.length : 1;
-                       const halfCount = lineCount / 2;
-                       const color = resolve([optionTicks.color], me.getContext(i), i);
-                       const strokeColor = resolve([optionTicks.textStrokeColor], me.getContext(i), i);
-                       const strokeWidth = resolve([optionTicks.textStrokeWidth], me.getContext(i), i);
-
-                       if (isHorizontal) {
-                               x = pixel;
-                               if (position === 'top') {
-                                       if (crossAlign === 'near' || rotation !== 0) {
-                                               textOffset = (Math.sin(rotation) * halfCount + 0.5) * lineHeight;
-                                               textOffset -= (rotation === 0 ? (lineCount - 0.5) : Math.cos(rotation) * halfCount) * lineHeight;
-                                       } else if (crossAlign === 'center') {
-                                               textOffset = -1 * (labelSizes.highest.height / 2);
-                                               textOffset -= halfCount * lineHeight;
-                                       } else {
-                                               textOffset = (-1 * labelSizes.highest.height) + (0.5 * lineHeight);
-                                       }
-                               } else {
-                                       // eslint-disable-next-line no-lonely-if
-                                       if (crossAlign === 'near' || rotation !== 0) {
-                                               textOffset = Math.sin(rotation) * halfCount * lineHeight;
-                                               textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * halfCount) * lineHeight;
-                                       } else if (crossAlign === 'center') {
-                                               textOffset = labelSizes.highest.height / 2;
-                                               textOffset -= halfCount * lineHeight;
-                                       } else {
-                                               textOffset = labelSizes.highest.height - ((lineCount - 0.5) * lineHeight);
-                                       }
-                               }
-                       } else {
-                               y = pixel;
-                               textOffset = (1 - lineCount) * lineHeight / 2;
-                       }
-
-                       items.push({
-                               rotation,
-                               label,
-                               font,
-                               color,
-                               strokeColor,
-                               strokeWidth,
-                               textOffset,
-                               textAlign,
-                               textBaseline,
-                               translation: [x, y]
-                       });
-               }
-
-               return items;
-       }
-
-       _getXAxisLabelAlignment() {
-               const me = this;
-               const {position, ticks} = me.options;
-               const rotation = -toRadians(me.labelRotation);
-
-               if (rotation) {
-                       return position === 'top' ? 'left' : 'right';
-               }
-
-               let align = 'center';
-
-               if (ticks.align === 'start') {
-                       align = 'left';
-               } else if (ticks.align === 'end') {
-                       align = 'right';
-               }
-
-               return align;
-       }
-
-       _getYAxisLabelAlignment(tl) {
-               const me = this;
-               const {position, ticks} = me.options;
-               const {crossAlign, mirror, padding} = ticks;
-               const labelSizes = me._getLabelSizes();
-               const tickAndPadding = tl + padding;
-               const widest = labelSizes.widest.width;
-               const lineSpace = labelSizes.highest.offset * 0.8;
-
-               let textAlign;
-               let x;
-
-               if (position === 'left') {
-                       if (mirror) {
-                               textAlign = 'left';
-                               x = me.right - padding;
-                       } else {
-                               x = me.right - tickAndPadding;
-
-                               if (crossAlign === 'near') {
-                                       textAlign = 'right';
-                               } else if (crossAlign === 'center') {
-                                       textAlign = 'center';
-                                       x -= (widest / 2);
-                               } else {
-                                       textAlign = 'left';
-                                       x = me.left + lineSpace;
-                               }
-                       }
-               } else if (position === 'right') {
-                       if (mirror) {
-                               textAlign = 'right';
-                               x = me.left + padding;
-                       } else {
-                               x = me.left + tickAndPadding;
-
-                               if (crossAlign === 'near') {
-                                       textAlign = 'left';
-                               } else if (crossAlign === 'center') {
-                                       textAlign = 'center';
-                                       x += widest / 2;
-                               } else {
-                                       textAlign = 'right';
-                                       x = me.right - lineSpace;
-                               }
-                       }
-               } else {
-                       textAlign = 'right';
-               }
-
-               return {textAlign, x};
-       }
-
-       /**
+  _computeLabelItems(chartArea) {
+    const me = this;
+    const axis = me.axis;
+    const options = me.options;
+    const {position, ticks: optionTicks} = options;
+    const isHorizontal = me.isHorizontal();
+    const ticks = me.ticks;
+    const {align, crossAlign, padding} = optionTicks;
+    const tl = getTickMarkLength(options.gridLines);
+    const tickAndPadding = tl + padding;
+    const rotation = -toRadians(me.labelRotation);
+    const items = [];
+    let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
+    let textBaseline = 'middle';
+
+    if (position === 'top') {
+      y = me.bottom - tickAndPadding;
+      textAlign = me._getXAxisLabelAlignment();
+    } else if (position === 'bottom') {
+      y = me.top + tickAndPadding;
+      textAlign = me._getXAxisLabelAlignment();
+    } else if (position === 'left') {
+      const ret = this._getYAxisLabelAlignment(tl);
+      textAlign = ret.textAlign;
+      x = ret.x;
+    } else if (position === 'right') {
+      const ret = this._getYAxisLabelAlignment(tl);
+      textAlign = ret.textAlign;
+      x = ret.x;
+    } else if (axis === 'x') {
+      if (position === 'center') {
+        y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding;
+      } else if (isObject(position)) {
+        const positionAxisID = Object.keys(position)[0];
+        const value = position[positionAxisID];
+        y = me.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
+      }
+      textAlign = me._getXAxisLabelAlignment();
+    } else if (axis === 'y') {
+      if (position === 'center') {
+        x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding;
+      } else if (isObject(position)) {
+        const positionAxisID = Object.keys(position)[0];
+        const value = position[positionAxisID];
+        x = me.chart.scales[positionAxisID].getPixelForValue(value);
+      }
+      textAlign = this._getYAxisLabelAlignment(tl).textAlign;
+    }
+
+    if (axis === 'y') {
+      if (align === 'start') {
+        textBaseline = 'top';
+      } else if (align === 'end') {
+        textBaseline = 'bottom';
+      }
+    }
+
+    const labelSizes = me._getLabelSizes();
+    for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+      tick = ticks[i];
+      label = tick.label;
+
+      pixel = me.getPixelForTick(i) + optionTicks.labelOffset;
+      font = me._resolveTickFontOptions(i);
+      lineHeight = font.lineHeight;
+      lineCount = isArray(label) ? label.length : 1;
+      const halfCount = lineCount / 2;
+      const color = resolve([optionTicks.color], me.getContext(i), i);
+      const strokeColor = resolve([optionTicks.textStrokeColor], me.getContext(i), i);
+      const strokeWidth = resolve([optionTicks.textStrokeWidth], me.getContext(i), i);
+
+      if (isHorizontal) {
+        x = pixel;
+        if (position === 'top') {
+          if (crossAlign === 'near' || rotation !== 0) {
+            textOffset = (Math.sin(rotation) * halfCount + 0.5) * lineHeight;
+            textOffset -= (rotation === 0 ? (lineCount - 0.5) : Math.cos(rotation) * halfCount) * lineHeight;
+          } else if (crossAlign === 'center') {
+            textOffset = -1 * (labelSizes.highest.height / 2);
+            textOffset -= halfCount * lineHeight;
+          } else {
+            textOffset = (-1 * labelSizes.highest.height) + (0.5 * lineHeight);
+          }
+        } else {
+          // eslint-disable-next-line no-lonely-if
+          if (crossAlign === 'near' || rotation !== 0) {
+            textOffset = Math.sin(rotation) * halfCount * lineHeight;
+            textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * halfCount) * lineHeight;
+          } else if (crossAlign === 'center') {
+            textOffset = labelSizes.highest.height / 2;
+            textOffset -= halfCount * lineHeight;
+          } else {
+            textOffset = labelSizes.highest.height - ((lineCount - 0.5) * lineHeight);
+          }
+        }
+      } else {
+        y = pixel;
+        textOffset = (1 - lineCount) * lineHeight / 2;
+      }
+
+      items.push({
+        rotation,
+        label,
+        font,
+        color,
+        strokeColor,
+        strokeWidth,
+        textOffset,
+        textAlign,
+        textBaseline,
+        translation: [x, y]
+      });
+    }
+
+    return items;
+  }
+
+  _getXAxisLabelAlignment() {
+    const me = this;
+    const {position, ticks} = me.options;
+    const rotation = -toRadians(me.labelRotation);
+
+    if (rotation) {
+      return position === 'top' ? 'left' : 'right';
+    }
+
+    let align = 'center';
+
+    if (ticks.align === 'start') {
+      align = 'left';
+    } else if (ticks.align === 'end') {
+      align = 'right';
+    }
+
+    return align;
+  }
+
+  _getYAxisLabelAlignment(tl) {
+    const me = this;
+    const {position, ticks} = me.options;
+    const {crossAlign, mirror, padding} = ticks;
+    const labelSizes = me._getLabelSizes();
+    const tickAndPadding = tl + padding;
+    const widest = labelSizes.widest.width;
+    const lineSpace = labelSizes.highest.offset * 0.8;
+
+    let textAlign;
+    let x;
+
+    if (position === 'left') {
+      if (mirror) {
+        textAlign = 'left';
+        x = me.right - padding;
+      } else {
+        x = me.right - tickAndPadding;
+
+        if (crossAlign === 'near') {
+          textAlign = 'right';
+        } else if (crossAlign === 'center') {
+          textAlign = 'center';
+          x -= (widest / 2);
+        } else {
+          textAlign = 'left';
+          x = me.left + lineSpace;
+        }
+      }
+    } else if (position === 'right') {
+      if (mirror) {
+        textAlign = 'right';
+        x = me.left + padding;
+      } else {
+        x = me.left + tickAndPadding;
+
+        if (crossAlign === 'near') {
+          textAlign = 'left';
+        } else if (crossAlign === 'center') {
+          textAlign = 'center';
+          x += widest / 2;
+        } else {
+          textAlign = 'right';
+          x = me.right - lineSpace;
+        }
+      }
+    } else {
+      textAlign = 'right';
+    }
+
+    return {textAlign, x};
+  }
+
+  /**
         * @private
         */
-       _computeLabelArea() {
-               const me = this;
-               const chart = me.chart;
-               const position = me.options.position;
+  _computeLabelArea() {
+    const me = this;
+    const chart = me.chart;
+    const position = me.options.position;
 
-               if (position === 'left' || position === 'right') {
-                       return {top: 0, left: me.left, bottom: chart.height, right: me.right};
-               } if (position === 'top' || position === 'bottom') {
-                       return {top: me.top, left: 0, bottom: me.bottom, right: chart.width};
-               }
+    if (position === 'left' || position === 'right') {
+      return {top: 0, left: me.left, bottom: chart.height, right: me.right};
+    } if (position === 'top' || position === 'bottom') {
+      return {top: me.top, left: 0, bottom: me.bottom, right: chart.width};
+    }
 
-               return null;
-       }
+    return null;
+  }
 
-       /**
+  /**
         * @protected
         */
-       drawGrid(chartArea) {
-               const me = this;
-               const gridLines = me.options.gridLines;
-               const ctx = me.ctx;
-               const chart = me.chart;
-               let context = me.getContext(0);
-               const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0;
-               const items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));
-               let i, ilen;
-
-               if (gridLines.display) {
-                       for (i = 0, ilen = items.length; i < ilen; ++i) {
-                               const item = items[i];
-                               const {color, tickColor, tickWidth, width} = item;
-
-                               if (width && color && gridLines.drawOnChartArea) {
-                                       ctx.save();
-                                       ctx.lineWidth = width;
-                                       ctx.strokeStyle = color;
-                                       if (ctx.setLineDash) {
-                                               ctx.setLineDash(item.borderDash);
-                                               ctx.lineDashOffset = item.borderDashOffset;
-                                       }
-
-                                       ctx.beginPath();
-                                       ctx.moveTo(item.x1, item.y1);
-                                       ctx.lineTo(item.x2, item.y2);
-                                       ctx.stroke();
-                                       ctx.restore();
-                               }
-
-                               if (tickWidth && tickColor && gridLines.drawTicks) {
-                                       ctx.save();
-                                       ctx.lineWidth = tickWidth;
-                                       ctx.strokeStyle = tickColor;
-                                       if (ctx.setLineDash) {
-                                               ctx.setLineDash(item.tickBorderDash);
-                                               ctx.lineDashOffset = item.tickBorderDashOffset;
-                                       }
-
-                                       ctx.beginPath();
-                                       ctx.moveTo(item.tx1, item.ty1);
-                                       ctx.lineTo(item.tx2, item.ty2);
-                                       ctx.stroke();
-                                       ctx.restore();
-                               }
-                       }
-               }
-
-               if (axisWidth) {
-                       // Draw the line at the edge of the axis
-                       const firstLineWidth = axisWidth;
-                       context = me.getContext(me._ticksLength - 1);
-                       const lastLineWidth = resolve([gridLines.lineWidth, 1], context, me._ticksLength - 1);
-                       const borderValue = me._borderValue;
-                       let x1, x2, y1, y2;
-
-                       if (me.isHorizontal()) {
-                               x1 = _alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
-                               x2 = _alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
-                               y1 = y2 = borderValue;
-                       } else {
-                               y1 = _alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
-                               y2 = _alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
-                               x1 = x2 = borderValue;
-                       }
-
-                       ctx.lineWidth = axisWidth;
-                       ctx.strokeStyle = resolve([gridLines.borderColor, gridLines.color], context, 0);
-                       ctx.beginPath();
-                       ctx.moveTo(x1, y1);
-                       ctx.lineTo(x2, y2);
-                       ctx.stroke();
-               }
-       }
-
-       /**
+  drawGrid(chartArea) {
+    const me = this;
+    const gridLines = me.options.gridLines;
+    const ctx = me.ctx;
+    const chart = me.chart;
+    let context = me.getContext(0);
+    const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0;
+    const items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));
+    let i, ilen;
+
+    if (gridLines.display) {
+      for (i = 0, ilen = items.length; i < ilen; ++i) {
+        const item = items[i];
+        const {color, tickColor, tickWidth, width} = item;
+
+        if (width && color && gridLines.drawOnChartArea) {
+          ctx.save();
+          ctx.lineWidth = width;
+          ctx.strokeStyle = color;
+          if (ctx.setLineDash) {
+            ctx.setLineDash(item.borderDash);
+            ctx.lineDashOffset = item.borderDashOffset;
+          }
+
+          ctx.beginPath();
+          ctx.moveTo(item.x1, item.y1);
+          ctx.lineTo(item.x2, item.y2);
+          ctx.stroke();
+          ctx.restore();
+        }
+
+        if (tickWidth && tickColor && gridLines.drawTicks) {
+          ctx.save();
+          ctx.lineWidth = tickWidth;
+          ctx.strokeStyle = tickColor;
+          if (ctx.setLineDash) {
+            ctx.setLineDash(item.tickBorderDash);
+            ctx.lineDashOffset = item.tickBorderDashOffset;
+          }
+
+          ctx.beginPath();
+          ctx.moveTo(item.tx1, item.ty1);
+          ctx.lineTo(item.tx2, item.ty2);
+          ctx.stroke();
+          ctx.restore();
+        }
+      }
+    }
+
+    if (axisWidth) {
+      // Draw the line at the edge of the axis
+      const firstLineWidth = axisWidth;
+      context = me.getContext(me._ticksLength - 1);
+      const lastLineWidth = resolve([gridLines.lineWidth, 1], context, me._ticksLength - 1);
+      const borderValue = me._borderValue;
+      let x1, x2, y1, y2;
+
+      if (me.isHorizontal()) {
+        x1 = _alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;
+        x2 = _alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;
+        y1 = y2 = borderValue;
+      } else {
+        y1 = _alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;
+        y2 = _alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;
+        x1 = x2 = borderValue;
+      }
+
+      ctx.lineWidth = axisWidth;
+      ctx.strokeStyle = resolve([gridLines.borderColor, gridLines.color], context, 0);
+      ctx.beginPath();
+      ctx.moveTo(x1, y1);
+      ctx.lineTo(x2, y2);
+      ctx.stroke();
+    }
+  }
+
+  /**
         * @protected
         */
-       drawLabels(chartArea) {
-               const me = this;
-               const optionTicks = me.options.ticks;
-
-               if (!optionTicks.display) {
-                       return;
-               }
-
-               const ctx = me.ctx;
-
-               const area = me._computeLabelArea();
-               if (area) {
-                       clipArea(ctx, area);
-               }
-
-               const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea));
-               let i, ilen;
-
-               for (i = 0, ilen = items.length; i < ilen; ++i) {
-                       const item = items[i];
-                       const tickFont = item.font;
-                       const label = item.label;
-                       let y = item.textOffset;
-                       renderText(ctx, label, 0, y, tickFont, item);
-               }
-
-               if (area) {
-                       unclipArea(ctx);
-               }
-       }
-
-       /**
+  drawLabels(chartArea) {
+    const me = this;
+    const optionTicks = me.options.ticks;
+
+    if (!optionTicks.display) {
+      return;
+    }
+
+    const ctx = me.ctx;
+
+    const area = me._computeLabelArea();
+    if (area) {
+      clipArea(ctx, area);
+    }
+
+    const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea));
+    let i, ilen;
+
+    for (i = 0, ilen = items.length; i < ilen; ++i) {
+      const item = items[i];
+      const tickFont = item.font;
+      const label = item.label;
+      let y = item.textOffset;
+      renderText(ctx, label, 0, y, tickFont, item);
+    }
+
+    if (area) {
+      unclipArea(ctx);
+    }
+  }
+
+  /**
         * @protected
         */
-       drawTitle(chartArea) { // eslint-disable-line no-unused-vars
-               const me = this;
-               const ctx = me.ctx;
-               const options = me.options;
-               const scaleLabel = options.scaleLabel;
-
-               if (!scaleLabel.display) {
-                       return;
-               }
-
-               const scaleLabelFont = toFont(scaleLabel.font, me.chart.options.font);
-               const scaleLabelPadding = toPadding(scaleLabel.padding);
-               const halfLineHeight = scaleLabelFont.lineHeight / 2;
-               const scaleLabelAlign = scaleLabel.align;
-               const position = options.position;
-               const isReverse = me.options.reverse;
-               let rotation = 0;
-               /** @type CanvasTextAlign */
-               let textAlign;
-               let scaleLabelX, scaleLabelY;
-
-               if (me.isHorizontal()) {
-                       switch (scaleLabelAlign) {
-                       case 'start':
-                               scaleLabelX = me.left + (isReverse ? me.width : 0);
-                               textAlign = isReverse ? 'right' : 'left';
-                               break;
-                       case 'end':
-                               scaleLabelX = me.left + (isReverse ? 0 : me.width);
-                               textAlign = isReverse ? 'left' : 'right';
-                               break;
-                       default:
-                               scaleLabelX = me.left + me.width / 2;
-                               textAlign = 'center';
-                       }
-                       scaleLabelY = position === 'top'
-                               ? me.top + halfLineHeight + scaleLabelPadding.top
-                               : me.bottom - halfLineHeight - scaleLabelPadding.bottom;
-               } else {
-                       const isLeft = position === 'left';
-                       scaleLabelX = isLeft
-                               ? me.left + halfLineHeight + scaleLabelPadding.top
-                               : me.right - halfLineHeight - scaleLabelPadding.top;
-                       switch (scaleLabelAlign) {
-                       case 'start':
-                               scaleLabelY = me.top + (isReverse ? 0 : me.height);
-                               textAlign = isReverse === isLeft ? 'right' : 'left';
-                               break;
-                       case 'end':
-                               scaleLabelY = me.top + (isReverse ? me.height : 0);
-                               textAlign = isReverse === isLeft ? 'left' : 'right';
-                               break;
-                       default:
-                               scaleLabelY = me.top + me.height / 2;
-                               textAlign = 'center';
-                       }
-                       rotation = isLeft ? -HALF_PI : HALF_PI;
-               }
-
-               renderText(ctx, scaleLabel.labelString, 0, 0, scaleLabelFont, {
-                       color: scaleLabel.color,
-                       rotation,
-                       textAlign,
-                       textBaseline: 'middle',
-                       translation: [scaleLabelX, scaleLabelY],
-               });
-       }
-
-       draw(chartArea) {
-               const me = this;
-
-               if (!me._isVisible()) {
-                       return;
-               }
-
-               me.drawGrid(chartArea);
-               me.drawTitle();
-               me.drawLabels(chartArea);
-       }
-
-       /**
+  drawTitle(chartArea) { // eslint-disable-line no-unused-vars
+    const me = this;
+    const ctx = me.ctx;
+    const options = me.options;
+    const scaleLabel = options.scaleLabel;
+
+    if (!scaleLabel.display) {
+      return;
+    }
+
+    const scaleLabelFont = toFont(scaleLabel.font, me.chart.options.font);
+    const scaleLabelPadding = toPadding(scaleLabel.padding);
+    const halfLineHeight = scaleLabelFont.lineHeight / 2;
+    const scaleLabelAlign = scaleLabel.align;
+    const position = options.position;
+    const isReverse = me.options.reverse;
+    let rotation = 0;
+    /** @type CanvasTextAlign */
+    let textAlign;
+    let scaleLabelX, scaleLabelY;
+
+    if (me.isHorizontal()) {
+      switch (scaleLabelAlign) {
+      case 'start':
+        scaleLabelX = me.left + (isReverse ? me.width : 0);
+        textAlign = isReverse ? 'right' : 'left';
+        break;
+      case 'end':
+        scaleLabelX = me.left + (isReverse ? 0 : me.width);
+        textAlign = isReverse ? 'left' : 'right';
+        break;
+      default:
+        scaleLabelX = me.left + me.width / 2;
+        textAlign = 'center';
+      }
+      scaleLabelY = position === 'top'
+        ? me.top + halfLineHeight + scaleLabelPadding.top
+        : me.bottom - halfLineHeight - scaleLabelPadding.bottom;
+    } else {
+      const isLeft = position === 'left';
+      scaleLabelX = isLeft
+        ? me.left + halfLineHeight + scaleLabelPadding.top
+        : me.right - halfLineHeight - scaleLabelPadding.top;
+      switch (scaleLabelAlign) {
+      case 'start':
+        scaleLabelY = me.top + (isReverse ? 0 : me.height);
+        textAlign = isReverse === isLeft ? 'right' : 'left';
+        break;
+      case 'end':
+        scaleLabelY = me.top + (isReverse ? me.height : 0);
+        textAlign = isReverse === isLeft ? 'left' : 'right';
+        break;
+      default:
+        scaleLabelY = me.top + me.height / 2;
+        textAlign = 'center';
+      }
+      rotation = isLeft ? -HALF_PI : HALF_PI;
+    }
+
+    renderText(ctx, scaleLabel.labelString, 0, 0, scaleLabelFont, {
+      color: scaleLabel.color,
+      rotation,
+      textAlign,
+      textBaseline: 'middle',
+      translation: [scaleLabelX, scaleLabelY],
+    });
+  }
+
+  draw(chartArea) {
+    const me = this;
+
+    if (!me._isVisible()) {
+      return;
+    }
+
+    me.drawGrid(chartArea);
+    me.drawTitle();
+    me.drawLabels(chartArea);
+  }
+
+  /**
         * @return {object[]}
         * @private
         */
-       _layers() {
-               const me = this;
-               const opts = me.options;
-               const tz = opts.ticks && opts.ticks.z || 0;
-               const gz = opts.gridLines && opts.gridLines.z || 0;
-
-               if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
-                       // backward compatibility: draw has been overridden by custom scale
-                       return [{
-                               z: tz,
-                               draw(chartArea) {
-                                       me.draw(chartArea);
-                               }
-                       }];
-               }
-
-               return [{
-                       z: gz,
-                       draw(chartArea) {
-                               me.drawGrid(chartArea);
-                               me.drawTitle();
-                       }
-               }, {
-                       z: tz,
-                       draw(chartArea) {
-                               me.drawLabels(chartArea);
-                       }
-               }];
-       }
-
-       /**
+  _layers() {
+    const me = this;
+    const opts = me.options;
+    const tz = opts.ticks && opts.ticks.z || 0;
+    const gz = opts.gridLines && opts.gridLines.z || 0;
+
+    if (!me._isVisible() || tz === gz || me.draw !== me._draw) {
+      // backward compatibility: draw has been overridden by custom scale
+      return [{
+        z: tz,
+        draw(chartArea) {
+          me.draw(chartArea);
+        }
+      }];
+    }
+
+    return [{
+      z: gz,
+      draw(chartArea) {
+        me.drawGrid(chartArea);
+        me.drawTitle();
+      }
+    }, {
+      z: tz,
+      draw(chartArea) {
+        me.drawLabels(chartArea);
+      }
+    }];
+  }
+
+  /**
         * Returns visible dataset metas that are attached to this scale
         * @param {string} [type] - if specified, also filter by dataset type
         * @return {object[]}
         */
-       getMatchingVisibleMetas(type) {
-               const me = this;
-               const metas = me.chart.getSortedVisibleDatasetMetas();
-               const axisID = me.axis + 'AxisID';
-               const result = [];
-               let i, ilen;
-
-               for (i = 0, ilen = metas.length; i < ilen; ++i) {
-                       const meta = metas[i];
-                       if (meta[axisID] === me.id && (!type || meta.type === type)) {
-                               result.push(meta);
-                       }
-               }
-               return result;
-       }
-
-       /**
+  getMatchingVisibleMetas(type) {
+    const me = this;
+    const metas = me.chart.getSortedVisibleDatasetMetas();
+    const axisID = me.axis + 'AxisID';
+    const result = [];
+    let i, ilen;
+
+    for (i = 0, ilen = metas.length; i < ilen; ++i) {
+      const meta = metas[i];
+      if (meta[axisID] === me.id && (!type || meta.type === type)) {
+        result.push(meta);
+      }
+    }
+    return result;
+  }
+
+  /**
         * @param {number} index
         * @return {object}
         * @protected
         */
-       _resolveTickFontOptions(index) {
-               const me = this;
-               const chart = me.chart;
-               const options = me.options.ticks;
-               const context = me.getContext(index);
-               return toFont(resolve([options.font], context), chart.options.font);
-       }
+  _resolveTickFontOptions(index) {
+    const me = this;
+    const chart = me.chart;
+    const options = me.options.ticks;
+    const context = me.getContext(index);
+    return toFont(resolve([options.font], context), chart.options.font);
+  }
 }
 
 Scale.prototype._draw = Scale.prototype.draw;
index 1e6770d643dc4aa06022945fe46998abd2de8c50..8e4086574c697487a2ae033a8c33b99772aafc30 100644 (file)
@@ -7,17 +7,17 @@ import {formatNumber} from './core.intl';
  * @namespace Chart.Ticks.formatters
  */
 const formatters = {
-       /**
+  /**
         * Formatter for value labels
         * @method Chart.Ticks.formatters.values
         * @param value the value to display
         * @return {string|string[]} the label to display
         */
-       values(value) {
-               return isArray(value) ? value : '' + value;
-       },
+  values(value) {
+    return isArray(value) ? value : '' + value;
+  },
 
-       /**
+  /**
         * Formatter for numeric ticks
         * @method Chart.Ticks.formatters.numeric
         * @param tickValue {number} the value to be formatted
@@ -25,38 +25,38 @@ const formatters = {
         * @param ticks {object[]} the list of ticks being converted
         * @return {string} string representation of the tickValue parameter
         */
-       numeric(tickValue, index, ticks) {
-               if (tickValue === 0) {
-                       return '0'; // never show decimal places for 0
-               }
+  numeric(tickValue, index, ticks) {
+    if (tickValue === 0) {
+      return '0'; // never show decimal places for 0
+    }
 
-               const locale = this.chart.options.locale;
+    const locale = this.chart.options.locale;
 
-               // all ticks are small or there huge numbers; use scientific notation
-               const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
-               let notation;
-               if (maxTick < 1e-4 || maxTick > 1e+15) {
-                       notation = 'scientific';
-               }
+    // all ticks are small or there huge numbers; use scientific notation
+    const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
+    let notation;
+    if (maxTick < 1e-4 || maxTick > 1e+15) {
+      notation = 'scientific';
+    }
 
-               // Figure out how many digits to show
-               // The space between the first two ticks might be smaller than normal spacing
-               let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
+    // Figure out how many digits to show
+    // The space between the first two ticks might be smaller than normal spacing
+    let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
 
-               // If we have a number like 2.5 as the delta, figure out how many decimal places we need
-               if (Math.abs(delta) > 1 && tickValue !== Math.floor(tickValue)) {
-                       // not an integer
-                       delta = tickValue - Math.floor(tickValue);
-               }
+    // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+    if (Math.abs(delta) > 1 && tickValue !== Math.floor(tickValue)) {
+      // not an integer
+      delta = tickValue - Math.floor(tickValue);
+    }
 
-               const logDelta = log10(Math.abs(delta));
-               const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); // toFixed has a max of 20 decimal places
+    const logDelta = log10(Math.abs(delta));
+    const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); // toFixed has a max of 20 decimal places
 
-               const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal};
-               Object.assign(options, this.options.ticks.format);
+    const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal};
+    Object.assign(options, this.options.ticks.format);
 
-               return formatNumber(tickValue, locale, options);
-       }
+    return formatNumber(tickValue, locale, options);
+  }
 };
 
 /**
@@ -68,14 +68,14 @@ const formatters = {
  * @return {string} string representation of the tickValue parameter
  */
 formatters.logarithmic = function(tickValue, index, ticks) {
-       if (tickValue === 0) {
-               return '0';
-       }
-       const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue))));
-       if (remain === 1 || remain === 2 || remain === 5) {
-               return formatters.numeric.call(this, tickValue, index, ticks);
-       }
-       return '';
+  if (tickValue === 0) {
+    return '0';
+  }
+  const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue))));
+  if (remain === 1 || remain === 2 || remain === 5) {
+    return formatters.numeric.call(this, tickValue, index, ticks);
+  }
+  return '';
 };
 
 /**
index 0f80b2df42b54a3ecb87bacc294c8044ceb50bca..45df85a1d1777f91dc829b8cf4f568a1fd3a94cc 100644 (file)
@@ -5,103 +5,103 @@ import defaults from './core.defaults';
  */
 
 export default class TypedRegistry {
-       constructor(type, scope) {
-               this.type = type;
-               this.scope = scope;
-               this.items = Object.create(null);
-       }
+  constructor(type, scope) {
+    this.type = type;
+    this.scope = scope;
+    this.items = Object.create(null);
+  }
 
-       isForType(type) {
-               return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
-       }
+  isForType(type) {
+    return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
+  }
 
-       /**
+  /**
         * @param {IChartComponent} item
         * @returns {string} The scope where items defaults were registered to.
         */
-       register(item) {
-               const proto = Object.getPrototypeOf(item);
-               let parentScope;
+  register(item) {
+    const proto = Object.getPrototypeOf(item);
+    let parentScope;
 
-               if (isIChartComponent(proto)) {
-                       // Make sure the parent is registered and note the scope where its defaults are.
-                       parentScope = this.register(proto);
-               }
+    if (isIChartComponent(proto)) {
+      // Make sure the parent is registered and note the scope where its defaults are.
+      parentScope = this.register(proto);
+    }
 
-               const items = this.items;
-               const id = item.id;
-               const baseScope = this.scope;
-               const scope = baseScope ? baseScope + '.' + id : id;
+    const items = this.items;
+    const id = item.id;
+    const baseScope = this.scope;
+    const scope = baseScope ? baseScope + '.' + id : id;
 
-               if (!id) {
-                       throw new Error('class does not have id: ' + item);
-               }
+    if (!id) {
+      throw new Error('class does not have id: ' + item);
+    }
 
-               if (id in items) {
-                       // already registered
-                       return scope;
-               }
+    if (id in items) {
+      // already registered
+      return scope;
+    }
 
-               items[id] = item;
-               registerDefaults(item, scope, parentScope);
+    items[id] = item;
+    registerDefaults(item, scope, parentScope);
 
-               return scope;
-       }
+    return scope;
+  }
 
-       /**
+  /**
         * @param {string} id
         * @returns {object?}
         */
-       get(id) {
-               return this.items[id];
-       }
+  get(id) {
+    return this.items[id];
+  }
 
-       /**
+  /**
         * @param {IChartComponent} item
         */
-       unregister(item) {
-               const items = this.items;
-               const id = item.id;
-               const scope = this.scope;
-
-               if (id in items) {
-                       delete items[id];
-               }
-
-               if (scope && id in defaults[scope]) {
-                       delete defaults[scope][id];
-               }
-       }
+  unregister(item) {
+    const items = this.items;
+    const id = item.id;
+    const scope = this.scope;
+
+    if (id in items) {
+      delete items[id];
+    }
+
+    if (scope && id in defaults[scope]) {
+      delete defaults[scope][id];
+    }
+  }
 }
 
 function registerDefaults(item, scope, parentScope) {
-       // Inherit the parent's defaults and keep existing defaults
-       const itemDefaults = Object.assign(
-               Object.create(null),
-               parentScope && defaults.get(parentScope),
-               item.defaults,
-               defaults.get(scope)
-       );
-
-       defaults.set(scope, itemDefaults);
-
-       if (item.defaultRoutes) {
-               routeDefaults(scope, item.defaultRoutes);
-       }
+  // Inherit the parent's defaults and keep existing defaults
+  const itemDefaults = Object.assign(
+    Object.create(null),
+    parentScope && defaults.get(parentScope),
+    item.defaults,
+    defaults.get(scope)
+  );
+
+  defaults.set(scope, itemDefaults);
+
+  if (item.defaultRoutes) {
+    routeDefaults(scope, item.defaultRoutes);
+  }
 }
 
 function routeDefaults(scope, routes) {
-       Object.keys(routes).forEach(property => {
-               const propertyParts = property.split('.');
-               const sourceName = propertyParts.pop();
-               const sourceScope = [scope].concat(propertyParts).join('.');
-               const parts = routes[property].split('.');
-               const targetName = parts.pop();
-               const targetScope = parts.join('.');
-               defaults.route(sourceScope, sourceName, targetScope, targetName);
-       });
+  Object.keys(routes).forEach(property => {
+    const propertyParts = property.split('.');
+    const sourceName = propertyParts.pop();
+    const sourceScope = [scope].concat(propertyParts).join('.');
+    const parts = routes[property].split('.');
+    const targetName = parts.pop();
+    const targetScope = parts.join('.');
+    defaults.route(sourceScope, sourceName, targetScope, targetName);
+  });
 }
 
 function isIChartComponent(proto) {
-       return 'id' in proto && 'defaults' in proto;
+  return 'id' in proto && 'defaults' in proto;
 }
index 7769353138f3b873e976c150d0e06d36facd7909..286008c347668f9834207a7046fb3ce93a7a6afe 100644 (file)
@@ -2,207 +2,207 @@ import Element from '../core/core.element';
 import {_angleBetween, getAngleFromPoint, TAU, HALF_PI} from '../helpers/index';
 
 function clipArc(ctx, element) {
-       const {startAngle, endAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
-       let angleMargin = pixelMargin / outerRadius;
-
-       // Draw an inner border by clipping the arc and drawing a double-width border
-       // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
-       ctx.beginPath();
-       ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
-       if (innerRadius > pixelMargin) {
-               angleMargin = pixelMargin / innerRadius;
-               ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
-       } else {
-               ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);
-       }
-       ctx.closePath();
-       ctx.clip();
+  const {startAngle, endAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
+  let angleMargin = pixelMargin / outerRadius;
+
+  // Draw an inner border by clipping the arc and drawing a double-width border
+  // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
+  ctx.beginPath();
+  ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
+  if (innerRadius > pixelMargin) {
+    angleMargin = pixelMargin / innerRadius;
+    ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
+  } else {
+    ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);
+  }
+  ctx.closePath();
+  ctx.clip();
 }
 
 
 function pathArc(ctx, element) {
-       const {x, y, startAngle, endAngle, pixelMargin} = element;
-       const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);
-       const innerRadius = element.innerRadius + pixelMargin;
-
-       ctx.beginPath();
-       ctx.arc(x, y, outerRadius, startAngle, endAngle);
-       ctx.arc(x, y, innerRadius, endAngle, startAngle, true);
-       ctx.closePath();
+  const {x, y, startAngle, endAngle, pixelMargin} = element;
+  const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);
+  const innerRadius = element.innerRadius + pixelMargin;
+
+  ctx.beginPath();
+  ctx.arc(x, y, outerRadius, startAngle, endAngle);
+  ctx.arc(x, y, innerRadius, endAngle, startAngle, true);
+  ctx.closePath();
 }
 
 function drawArc(ctx, element) {
-       if (element.fullCircles) {
-               element.endAngle = element.startAngle + TAU;
+  if (element.fullCircles) {
+    element.endAngle = element.startAngle + TAU;
 
-               pathArc(ctx, element);
+    pathArc(ctx, element);
 
-               for (let i = 0; i < element.fullCircles; ++i) {
-                       ctx.fill();
-               }
-               element.endAngle = element.startAngle + element.circumference % TAU;
-       }
+    for (let i = 0; i < element.fullCircles; ++i) {
+      ctx.fill();
+    }
+    element.endAngle = element.startAngle + element.circumference % TAU;
+  }
 
-       pathArc(ctx, element);
-       ctx.fill();
+  pathArc(ctx, element);
+  ctx.fill();
 }
 
 function drawFullCircleBorders(ctx, element, inner) {
-       const {x, y, startAngle, endAngle, pixelMargin} = element;
-       const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);
-       const innerRadius = element.innerRadius + pixelMargin;
-
-       let i;
-
-       if (inner) {
-               element.endAngle = element.startAngle + TAU;
-               clipArc(ctx, element);
-               element.endAngle = endAngle;
-               if (element.endAngle === element.startAngle) {
-                       element.endAngle += TAU;
-                       element.fullCircles--;
-               }
-       }
-
-       ctx.beginPath();
-       ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true);
-       for (i = 0; i < element.fullCircles; ++i) {
-               ctx.stroke();
-       }
-
-       ctx.beginPath();
-       ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU);
-       for (i = 0; i < element.fullCircles; ++i) {
-               ctx.stroke();
-       }
+  const {x, y, startAngle, endAngle, pixelMargin} = element;
+  const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);
+  const innerRadius = element.innerRadius + pixelMargin;
+
+  let i;
+
+  if (inner) {
+    element.endAngle = element.startAngle + TAU;
+    clipArc(ctx, element);
+    element.endAngle = endAngle;
+    if (element.endAngle === element.startAngle) {
+      element.endAngle += TAU;
+      element.fullCircles--;
+    }
+  }
+
+  ctx.beginPath();
+  ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true);
+  for (i = 0; i < element.fullCircles; ++i) {
+    ctx.stroke();
+  }
+
+  ctx.beginPath();
+  ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU);
+  for (i = 0; i < element.fullCircles; ++i) {
+    ctx.stroke();
+  }
 }
 
 function drawBorder(ctx, element) {
-       const {x, y, startAngle, endAngle, pixelMargin, options} = element;
-       const outerRadius = element.outerRadius;
-       const innerRadius = element.innerRadius + pixelMargin;
-       const inner = options.borderAlign === 'inner';
-
-       if (!options.borderWidth) {
-               return;
-       }
-
-       if (inner) {
-               ctx.lineWidth = options.borderWidth * 2;
-               ctx.lineJoin = 'round';
-       } else {
-               ctx.lineWidth = options.borderWidth;
-               ctx.lineJoin = 'bevel';
-       }
-
-       if (element.fullCircles) {
-               drawFullCircleBorders(ctx, element, inner);
-       }
-
-       if (inner) {
-               clipArc(ctx, element);
-       }
-
-       ctx.beginPath();
-       ctx.arc(x, y, outerRadius, startAngle, endAngle);
-       ctx.arc(x, y, innerRadius, endAngle, startAngle, true);
-       ctx.closePath();
-       ctx.stroke();
+  const {x, y, startAngle, endAngle, pixelMargin, options} = element;
+  const outerRadius = element.outerRadius;
+  const innerRadius = element.innerRadius + pixelMargin;
+  const inner = options.borderAlign === 'inner';
+
+  if (!options.borderWidth) {
+    return;
+  }
+
+  if (inner) {
+    ctx.lineWidth = options.borderWidth * 2;
+    ctx.lineJoin = 'round';
+  } else {
+    ctx.lineWidth = options.borderWidth;
+    ctx.lineJoin = 'bevel';
+  }
+
+  if (element.fullCircles) {
+    drawFullCircleBorders(ctx, element, inner);
+  }
+
+  if (inner) {
+    clipArc(ctx, element);
+  }
+
+  ctx.beginPath();
+  ctx.arc(x, y, outerRadius, startAngle, endAngle);
+  ctx.arc(x, y, innerRadius, endAngle, startAngle, true);
+  ctx.closePath();
+  ctx.stroke();
 }
 
 export default class ArcElement extends Element {
 
-       constructor(cfg) {
-               super();
+  constructor(cfg) {
+    super();
 
-               this.options = undefined;
-               this.circumference = undefined;
-               this.startAngle = undefined;
-               this.endAngle = undefined;
-               this.innerRadius = undefined;
-               this.outerRadius = undefined;
-               this.pixelMargin = 0;
-               this.fullCircles = 0;
+    this.options = undefined;
+    this.circumference = undefined;
+    this.startAngle = undefined;
+    this.endAngle = undefined;
+    this.innerRadius = undefined;
+    this.outerRadius = undefined;
+    this.pixelMargin = 0;
+    this.fullCircles = 0;
 
-               if (cfg) {
-                       Object.assign(this, cfg);
-               }
-       }
+    if (cfg) {
+      Object.assign(this, cfg);
+    }
+  }
 
-       /**
+  /**
         * @param {number} chartX
         * @param {number} chartY
         * @param {boolean} [useFinalPosition]
         */
-       inRange(chartX, chartY, useFinalPosition) {
-               const point = this.getProps(['x', 'y'], useFinalPosition);
-               const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY});
-               const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([
-                       'startAngle',
-                       'endAngle',
-                       'innerRadius',
-                       'outerRadius',
-                       'circumference'
-               ], useFinalPosition);
-               const betweenAngles = circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
-               const withinRadius = (distance >= innerRadius && distance <= outerRadius);
-
-               return (betweenAngles && withinRadius);
-       }
-
-       /**
+  inRange(chartX, chartY, useFinalPosition) {
+    const point = this.getProps(['x', 'y'], useFinalPosition);
+    const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY});
+    const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([
+      'startAngle',
+      'endAngle',
+      'innerRadius',
+      'outerRadius',
+      'circumference'
+    ], useFinalPosition);
+    const betweenAngles = circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
+    const withinRadius = (distance >= innerRadius && distance <= outerRadius);
+
+    return (betweenAngles && withinRadius);
+  }
+
+  /**
         * @param {boolean} [useFinalPosition]
         */
-       getCenterPoint(useFinalPosition) {
-               const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([
-                       'x',
-                       'y',
-                       'startAngle',
-                       'endAngle',
-                       'innerRadius',
-                       'outerRadius'
-               ], useFinalPosition);
-               const halfAngle = (startAngle + endAngle) / 2;
-               const halfRadius = (innerRadius + outerRadius) / 2;
-               return {
-                       x: x + Math.cos(halfAngle) * halfRadius,
-                       y: y + Math.sin(halfAngle) * halfRadius
-               };
-       }
-
-       /**
+  getCenterPoint(useFinalPosition) {
+    const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([
+      'x',
+      'y',
+      'startAngle',
+      'endAngle',
+      'innerRadius',
+      'outerRadius'
+    ], useFinalPosition);
+    const halfAngle = (startAngle + endAngle) / 2;
+    const halfRadius = (innerRadius + outerRadius) / 2;
+    return {
+      x: x + Math.cos(halfAngle) * halfRadius,
+      y: y + Math.sin(halfAngle) * halfRadius
+    };
+  }
+
+  /**
         * @param {boolean} [useFinalPosition]
         */
-       tooltipPosition(useFinalPosition) {
-               return this.getCenterPoint(useFinalPosition);
-       }
+  tooltipPosition(useFinalPosition) {
+    return this.getCenterPoint(useFinalPosition);
+  }
 
-       draw(ctx) {
-               const me = this;
-               const options = me.options;
-               const offset = options.offset || 0;
-               me.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;
-               me.fullCircles = Math.floor(me.circumference / TAU);
+  draw(ctx) {
+    const me = this;
+    const options = me.options;
+    const offset = options.offset || 0;
+    me.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;
+    me.fullCircles = Math.floor(me.circumference / TAU);
 
-               if (me.circumference === 0 || me.innerRadius < 0 || me.outerRadius < 0) {
-                       return;
-               }
+    if (me.circumference === 0 || me.innerRadius < 0 || me.outerRadius < 0) {
+      return;
+    }
 
-               ctx.save();
+    ctx.save();
 
-               if (offset && me.circumference < TAU) {
-                       const halfAngle = (me.startAngle + me.endAngle) / 2;
-                       ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
-               }
+    if (offset && me.circumference < TAU) {
+      const halfAngle = (me.startAngle + me.endAngle) / 2;
+      ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);
+    }
 
-               ctx.fillStyle = options.backgroundColor;
-               ctx.strokeStyle = options.borderColor;
+    ctx.fillStyle = options.backgroundColor;
+    ctx.strokeStyle = options.borderColor;
 
-               drawArc(ctx, me);
-               drawBorder(ctx, me);
+    drawArc(ctx, me);
+    drawBorder(ctx, me);
 
-               ctx.restore();
-       }
+    ctx.restore();
+  }
 }
 
 ArcElement.id = 'arc';
@@ -211,15 +211,15 @@ ArcElement.id = 'arc';
  * @type {any}
  */
 ArcElement.defaults = {
-       borderAlign: 'center',
-       borderColor: '#fff',
-       borderWidth: 2,
-       offset: 0
+  borderAlign: 'center',
+  borderColor: '#fff',
+  borderWidth: 2,
+  offset: 0
 };
 
 /**
  * @type {any}
  */
 ArcElement.defaultRoutes = {
-       backgroundColor: 'backgroundColor'
+  backgroundColor: 'backgroundColor'
 };
index 498fdfea716d095cde0f29a0362c8a58527e12b9..c12b7a45324a05098310ca0c16994abf4cd7eac1 100644 (file)
@@ -10,135 +10,135 @@ import {PI, HALF_PI} from '../helpers/helpers.math';
  * @private
  */
 function getBarBounds(bar, useFinalPosition) {
-       const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition);
-
-       let left, right, top, bottom, half;
-
-       if (bar.horizontal) {
-               half = height / 2;
-               left = Math.min(x, base);
-               right = Math.max(x, base);
-               top = y - half;
-               bottom = y + half;
-       } else {
-               half = width / 2;
-               left = x - half;
-               right = x + half;
-               top = Math.min(y, base);
-               bottom = Math.max(y, base);
-       }
-
-       return {left, top, right, bottom};
+  const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition);
+
+  let left, right, top, bottom, half;
+
+  if (bar.horizontal) {
+    half = height / 2;
+    left = Math.min(x, base);
+    right = Math.max(x, base);
+    top = y - half;
+    bottom = y + half;
+  } else {
+    half = width / 2;
+    left = x - half;
+    right = x + half;
+    top = Math.min(y, base);
+    bottom = Math.max(y, base);
+  }
+
+  return {left, top, right, bottom};
 }
 
 function parseBorderSkipped(bar) {
-       let edge = bar.options.borderSkipped;
-       const res = {};
+  let edge = bar.options.borderSkipped;
+  const res = {};
 
-       if (!edge) {
-               return res;
-       }
+  if (!edge) {
+    return res;
+  }
 
-       edge = bar.horizontal
-               ? parseEdge(edge, 'left', 'right', bar.base > bar.x)
-               : parseEdge(edge, 'bottom', 'top', bar.base < bar.y);
+  edge = bar.horizontal
+    ? parseEdge(edge, 'left', 'right', bar.base > bar.x)
+    : parseEdge(edge, 'bottom', 'top', bar.base < bar.y);
 
-       res[edge] = true;
-       return res;
+  res[edge] = true;
+  return res;
 }
 
 function parseEdge(edge, a, b, reverse) {
-       if (reverse) {
-               edge = swap(edge, a, b);
-               edge = startEnd(edge, b, a);
-       } else {
-               edge = startEnd(edge, a, b);
-       }
-       return edge;
+  if (reverse) {
+    edge = swap(edge, a, b);
+    edge = startEnd(edge, b, a);
+  } else {
+    edge = startEnd(edge, a, b);
+  }
+  return edge;
 }
 
 function swap(orig, v1, v2) {
-       return orig === v1 ? v2 : orig === v2 ? v1 : orig;
+  return orig === v1 ? v2 : orig === v2 ? v1 : orig;
 }
 
 function startEnd(v, start, end) {
-       return v === 'start' ? start : v === 'end' ? end : v;
+  return v === 'start' ? start : v === 'end' ? end : v;
 }
 
 function skipOrLimit(skip, value, min, max) {
-       return skip ? 0 : Math.max(Math.min(value, max), min);
+  return skip ? 0 : Math.max(Math.min(value, max), min);
 }
 
 function parseBorderWidth(bar, maxW, maxH) {
-       const value = bar.options.borderWidth;
-       const skip = parseBorderSkipped(bar);
-       const o = toTRBL(value);
-
-       return {
-               t: skipOrLimit(skip.top, o.top, 0, maxH),
-               r: skipOrLimit(skip.right, o.right, 0, maxW),
-               b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
-               l: skipOrLimit(skip.left, o.left, 0, maxW)
-       };
+  const value = bar.options.borderWidth;
+  const skip = parseBorderSkipped(bar);
+  const o = toTRBL(value);
+
+  return {
+    t: skipOrLimit(skip.top, o.top, 0, maxH),
+    r: skipOrLimit(skip.right, o.right, 0, maxW),
+    b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
+    l: skipOrLimit(skip.left, o.left, 0, maxW)
+  };
 }
 
 function parseBorderRadius(bar, maxW, maxH) {
-       const value = bar.options.borderRadius;
-       const o = toTRBLCorners(value);
-       const maxR = Math.min(maxW, maxH);
-       const skip = parseBorderSkipped(bar);
-
-       return {
-               topLeft: skipOrLimit(skip.top || skip.left, o.topLeft, 0, maxR),
-               topRight: skipOrLimit(skip.top || skip.right, o.topRight, 0, maxR),
-               bottomLeft: skipOrLimit(skip.bottom || skip.left, o.bottomLeft, 0, maxR),
-               bottomRight: skipOrLimit(skip.bottom || skip.right, o.bottomRight, 0, maxR)
-       };
+  const value = bar.options.borderRadius;
+  const o = toTRBLCorners(value);
+  const maxR = Math.min(maxW, maxH);
+  const skip = parseBorderSkipped(bar);
+
+  return {
+    topLeft: skipOrLimit(skip.top || skip.left, o.topLeft, 0, maxR),
+    topRight: skipOrLimit(skip.top || skip.right, o.topRight, 0, maxR),
+    bottomLeft: skipOrLimit(skip.bottom || skip.left, o.bottomLeft, 0, maxR),
+    bottomRight: skipOrLimit(skip.bottom || skip.right, o.bottomRight, 0, maxR)
+  };
 }
 
 function boundingRects(bar) {
-       const bounds = getBarBounds(bar);
-       const width = bounds.right - bounds.left;
-       const height = bounds.bottom - bounds.top;
-       const border = parseBorderWidth(bar, width / 2, height / 2);
-       const radius = parseBorderRadius(bar, width / 2, height / 2);
-
-       return {
-               outer: {
-                       x: bounds.left,
-                       y: bounds.top,
-                       w: width,
-                       h: height,
-                       radius
-               },
-               inner: {
-                       x: bounds.left + border.l,
-                       y: bounds.top + border.t,
-                       w: width - border.l - border.r,
-                       h: height - border.t - border.b,
-                       radius: {
-                               topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
-                               topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
-                               bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
-                               bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)),
-                       }
-               }
-       };
+  const bounds = getBarBounds(bar);
+  const width = bounds.right - bounds.left;
+  const height = bounds.bottom - bounds.top;
+  const border = parseBorderWidth(bar, width / 2, height / 2);
+  const radius = parseBorderRadius(bar, width / 2, height / 2);
+
+  return {
+    outer: {
+      x: bounds.left,
+      y: bounds.top,
+      w: width,
+      h: height,
+      radius
+    },
+    inner: {
+      x: bounds.left + border.l,
+      y: bounds.top + border.t,
+      w: width - border.l - border.r,
+      h: height - border.t - border.b,
+      radius: {
+        topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
+        topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
+        bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
+        bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)),
+      }
+    }
+  };
 }
 
 function inRange(bar, x, y, useFinalPosition) {
-       const skipX = x === null;
-       const skipY = y === null;
-       const skipBoth = skipX && skipY;
-       const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
+  const skipX = x === null;
+  const skipY = y === null;
+  const skipBoth = skipX && skipY;
+  const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
 
-       return bounds
+  return bounds
                && (skipX || x >= bounds.left && x <= bounds.right)
                && (skipY || y >= bounds.top && y <= bounds.bottom);
 }
 
 function hasRadius(radius) {
-       return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
+  return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
 }
 
 /**
@@ -147,31 +147,31 @@ function hasRadius(radius) {
  * @param {*} rect Bounding rect
  */
 function addRoundedRectPath(ctx, rect) {
-       const {x, y, w, h, radius} = rect;
+  const {x, y, w, h, radius} = rect;
 
-       // top left arc
-       ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true);
+  // top left arc
+  ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true);
 
-       // line from top left to bottom left
-       ctx.lineTo(x, y + h - radius.bottomLeft);
+  // line from top left to bottom left
+  ctx.lineTo(x, y + h - radius.bottomLeft);
 
-       // bottom left arc
-       ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
+  // bottom left arc
+  ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
 
-       // line from bottom left to bottom right
-       ctx.lineTo(x + w - radius.bottomRight, y + h);
+  // line from bottom left to bottom right
+  ctx.lineTo(x + w - radius.bottomRight, y + h);
 
-       // bottom right arc
-       ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
+  // bottom right arc
+  ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
 
-       // line from bottom right to top right
-       ctx.lineTo(x + w, y + radius.topRight);
+  // line from bottom right to top right
+  ctx.lineTo(x + w, y + radius.topRight);
 
-       // top right arc
-       ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
+  // top right arc
+  ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
 
-       // line from top right to top left
-       ctx.lineTo(x + radius.topLeft, y);
+  // line from top right to top left
+  ctx.lineTo(x + radius.topLeft, y);
 }
 
 /**
@@ -180,72 +180,72 @@ function addRoundedRectPath(ctx, rect) {
  * @param {*} rect Bounding rect
  */
 function addNormalRectPath(ctx, rect) {
-       ctx.rect(rect.x, rect.y, rect.w, rect.h);
+  ctx.rect(rect.x, rect.y, rect.w, rect.h);
 }
 
 export default class BarElement extends Element {
 
-       constructor(cfg) {
-               super();
-
-               this.options = undefined;
-               this.horizontal = undefined;
-               this.base = undefined;
-               this.width = undefined;
-               this.height = undefined;
-
-               if (cfg) {
-                       Object.assign(this, cfg);
-               }
-       }
-
-       draw(ctx) {
-               const options = this.options;
-               const {inner, outer} = boundingRects(this);
-               const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;
-
-               ctx.save();
-
-               if (outer.w !== inner.w || outer.h !== inner.h) {
-                       ctx.beginPath();
-                       addRectPath(ctx, outer);
-                       ctx.clip();
-                       addRectPath(ctx, inner);
-                       ctx.fillStyle = options.borderColor;
-                       ctx.fill('evenodd');
-               }
-
-               ctx.beginPath();
-               addRectPath(ctx, inner);
-               ctx.fillStyle = options.backgroundColor;
-               ctx.fill();
-
-               ctx.restore();
-       }
-
-       inRange(mouseX, mouseY, useFinalPosition) {
-               return inRange(this, mouseX, mouseY, useFinalPosition);
-       }
-
-       inXRange(mouseX, useFinalPosition) {
-               return inRange(this, mouseX, null, useFinalPosition);
-       }
-
-       inYRange(mouseY, useFinalPosition) {
-               return inRange(this, null, mouseY, useFinalPosition);
-       }
-
-       getCenterPoint(useFinalPosition) {
-               const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition);
-               return {
-                       x: horizontal ? (x + base) / 2 : x,
-                       y: horizontal ? y : (y + base) / 2
-               };
-       }
-
-       getRange(axis) {
-               return axis === 'x' ? this.width / 2 : this.height / 2;
-       }
+  constructor(cfg) {
+    super();
+
+    this.options = undefined;
+    this.horizontal = undefined;
+    this.base = undefined;
+    this.width = undefined;
+    this.height = undefined;
+
+    if (cfg) {
+      Object.assign(this, cfg);
+    }
+  }
+
+  draw(ctx) {
+    const options = this.options;
+    const {inner, outer} = boundingRects(this);
+    const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;
+
+    ctx.save();
+
+    if (outer.w !== inner.w || outer.h !== inner.h) {
+      ctx.beginPath();
+      addRectPath(ctx, outer);
+      ctx.clip();
+      addRectPath(ctx, inner);
+      ctx.fillStyle = options.borderColor;
+      ctx.fill('evenodd');
+    }
+
+    ctx.beginPath();
+    addRectPath(ctx, inner);
+    ctx.fillStyle = options.backgroundColor;
+    ctx.fill();
+
+    ctx.restore();
+  }
+
+  inRange(mouseX, mouseY, useFinalPosition) {
+    return inRange(this, mouseX, mouseY, useFinalPosition);
+  }
+
+  inXRange(mouseX, useFinalPosition) {
+    return inRange(this, mouseX, null, useFinalPosition);
+  }
+
+  inYRange(mouseY, useFinalPosition) {
+    return inRange(this, null, mouseY, useFinalPosition);
+  }
+
+  getCenterPoint(useFinalPosition) {
+    const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition);
+    return {
+      x: horizontal ? (x + base) / 2 : x,
+      y: horizontal ? y : (y + base) / 2
+    };
+  }
+
+  getRange(axis) {
+    return axis === 'x' ? this.width / 2 : this.height / 2;
+  }
 }
 
 BarElement.id = 'bar';
@@ -254,15 +254,15 @@ BarElement.id = 'bar';
  * @type {any}
  */
 BarElement.defaults = {
-       borderSkipped: 'start',
-       borderWidth: 0,
-       borderRadius: 0
+  borderSkipped: 'start',
+  borderWidth: 0,
+  borderRadius: 0
 };
 
 /**
  * @type {any}
  */
 BarElement.defaultRoutes = {
-       backgroundColor: 'backgroundColor',
-       borderColor: 'borderColor'
+  backgroundColor: 'backgroundColor',
+  borderColor: 'borderColor'
 };
index 9379bae53f724c1ceadee83fb7db8ed33bb4c736..9aec82a729a08f48300b018e7921f3c3ea2018cd 100644 (file)
@@ -9,42 +9,42 @@ import {_updateBezierControlPoints} from '../helpers/helpers.curve';
  */
 
 function setStyle(ctx, vm) {
-       ctx.lineCap = vm.borderCapStyle;
-       ctx.setLineDash(vm.borderDash);
-       ctx.lineDashOffset = vm.borderDashOffset;
-       ctx.lineJoin = vm.borderJoinStyle;
-       ctx.lineWidth = vm.borderWidth;
-       ctx.strokeStyle = vm.borderColor;
+  ctx.lineCap = vm.borderCapStyle;
+  ctx.setLineDash(vm.borderDash);
+  ctx.lineDashOffset = vm.borderDashOffset;
+  ctx.lineJoin = vm.borderJoinStyle;
+  ctx.lineWidth = vm.borderWidth;
+  ctx.strokeStyle = vm.borderColor;
 }
 
 function lineTo(ctx, previous, target) {
-       ctx.lineTo(target.x, target.y);
+  ctx.lineTo(target.x, target.y);
 }
 
 function getLineMethod(options) {
-       if (options.stepped) {
-               return _steppedLineTo;
-       }
+  if (options.stepped) {
+    return _steppedLineTo;
+  }
 
-       if (options.tension) {
-               return _bezierCurveTo;
-       }
+  if (options.tension) {
+    return _bezierCurveTo;
+  }
 
-       return lineTo;
+  return lineTo;
 }
 
 function pathVars(points, segment, params) {
-       params = params || {};
-       const count = points.length;
-       const start = Math.max(params.start || 0, segment.start);
-       const end = Math.min(params.end || count - 1, segment.end);
-
-       return {
-               count,
-               start,
-               loop: segment.loop,
-               ilen: end < start ? count + end - start : end - start
-       };
+  params = params || {};
+  const count = points.length;
+  const start = Math.max(params.start || 0, segment.start);
+  const end = Math.min(params.end || count - 1, segment.end);
+
+  return {
+    count,
+    start,
+    loop: segment.loop,
+    ilen: end < start ? count + end - start : end - start
+  };
 }
 
 /**
@@ -63,35 +63,35 @@ function pathVars(points, segment, params) {
  * @param {number} params.end - limit segment to points ending at `start` + `count` index
  */
 function pathSegment(ctx, line, segment, params) {
-       const {points, options} = line;
-       const {count, start, loop, ilen} = pathVars(points, segment, params);
-       const lineMethod = getLineMethod(options);
-       // eslint-disable-next-line prefer-const
-       let {move = true, reverse} = params || {};
-       let i, point, prev;
-
-       for (i = 0; i <= ilen; ++i) {
-               point = points[(start + (reverse ? ilen - i : i)) % count];
-
-               if (point.skip) {
-                       // If there is a skipped point inside a segment, spanGaps must be true
-                       continue;
-               } else if (move) {
-                       ctx.moveTo(point.x, point.y);
-                       move = false;
-               } else {
-                       lineMethod(ctx, prev, point, reverse, options.stepped);
-               }
-
-               prev = point;
-       }
-
-       if (loop) {
-               point = points[(start + (reverse ? ilen : 0)) % count];
-               lineMethod(ctx, prev, point, reverse, options.stepped);
-       }
-
-       return !!loop;
+  const {points, options} = line;
+  const {count, start, loop, ilen} = pathVars(points, segment, params);
+  const lineMethod = getLineMethod(options);
+  // eslint-disable-next-line prefer-const
+  let {move = true, reverse} = params || {};
+  let i, point, prev;
+
+  for (i = 0; i <= ilen; ++i) {
+    point = points[(start + (reverse ? ilen - i : i)) % count];
+
+    if (point.skip) {
+      // If there is a skipped point inside a segment, spanGaps must be true
+      continue;
+    } else if (move) {
+      ctx.moveTo(point.x, point.y);
+      move = false;
+    } else {
+      lineMethod(ctx, prev, point, reverse, options.stepped);
+    }
+
+    prev = point;
+  }
+
+  if (loop) {
+    point = points[(start + (reverse ? ilen : 0)) % count];
+    lineMethod(ctx, prev, point, reverse, options.stepped);
+  }
+
+  return !!loop;
 }
 
 /**
@@ -110,65 +110,65 @@ function pathSegment(ctx, line, segment, params) {
  * @param {number} params.end - limit segment to points ending at `start` + `count` index
  */
 function fastPathSegment(ctx, line, segment, params) {
-       const points = line.points;
-       const {count, start, ilen} = pathVars(points, segment, params);
-       const {move = true, reverse} = params || {};
-       let avgX = 0;
-       let countX = 0;
-       let i, point, prevX, minY, maxY, lastY;
-
-       const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count;
-       const drawX = () => {
-               if (minY !== maxY) {
-                       // Draw line to maxY and minY, using the average x-coordinate
-                       ctx.lineTo(avgX, maxY);
-                       ctx.lineTo(avgX, minY);
-                       // Line to y-value of last point in group. So the line continues
-                       // from correct position. Not using move, to have solid path.
-                       ctx.lineTo(avgX, lastY);
-               }
-       };
-
-       if (move) {
-               point = points[pointIndex(0)];
-               ctx.moveTo(point.x, point.y);
-       }
-
-       for (i = 0; i <= ilen; ++i) {
-               point = points[pointIndex(i)];
-
-               if (point.skip) {
-                       // If there is a skipped point inside a segment, spanGaps must be true
-                       continue;
-               }
-
-               const x = point.x;
-               const y = point.y;
-               const truncX = x | 0; // truncated x-coordinate
-
-               if (truncX === prevX) {
-                       // Determine `minY` / `maxY` and `avgX` while we stay within same x-position
-                       if (y < minY) {
-                               minY = y;
-                       } else if (y > maxY) {
-                               maxY = y;
-                       }
-                       // For first point in group, countX is `0`, so average will be `x` / 1.
-                       avgX = (countX * avgX + x) / ++countX;
-               } else {
-                       drawX();
-                       // Draw line to next x-position, using the first (or only)
-                       // y-value in that group
-                       ctx.lineTo(x, y);
-
-                       prevX = truncX;
-                       countX = 0;
-                       minY = maxY = y;
-               }
-               // Keep track of the last y-value in group
-               lastY = y;
-       }
-       drawX();
+  const points = line.points;
+  const {count, start, ilen} = pathVars(points, segment, params);
+  const {move = true, reverse} = params || {};
+  let avgX = 0;
+  let countX = 0;
+  let i, point, prevX, minY, maxY, lastY;
+
+  const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count;
+  const drawX = () => {
+    if (minY !== maxY) {
+      // Draw line to maxY and minY, using the average x-coordinate
+      ctx.lineTo(avgX, maxY);
+      ctx.lineTo(avgX, minY);
+      // Line to y-value of last point in group. So the line continues
+      // from correct position. Not using move, to have solid path.
+      ctx.lineTo(avgX, lastY);
+    }
+  };
+
+  if (move) {
+    point = points[pointIndex(0)];
+    ctx.moveTo(point.x, point.y);
+  }
+
+  for (i = 0; i <= ilen; ++i) {
+    point = points[pointIndex(i)];
+
+    if (point.skip) {
+      // If there is a skipped point inside a segment, spanGaps must be true
+      continue;
+    }
+
+    const x = point.x;
+    const y = point.y;
+    const truncX = x | 0; // truncated x-coordinate
+
+    if (truncX === prevX) {
+      // Determine `minY` / `maxY` and `avgX` while we stay within same x-position
+      if (y < minY) {
+        minY = y;
+      } else if (y > maxY) {
+        maxY = y;
+      }
+      // For first point in group, countX is `0`, so average will be `x` / 1.
+      avgX = (countX * avgX + x) / ++countX;
+    } else {
+      drawX();
+      // Draw line to next x-position, using the first (or only)
+      // y-value in that group
+      ctx.lineTo(x, y);
+
+      prevX = truncX;
+      countX = 0;
+      minY = maxY = y;
+    }
+    // Keep track of the last y-value in group
+    lastY = y;
+  }
+  drawX();
 }
 
 /**
@@ -177,131 +177,131 @@ function fastPathSegment(ctx, line, segment, params) {
  * @private
  */
 function _getSegmentMethod(line) {
-       const opts = line.options;
-       const borderDash = opts.borderDash && opts.borderDash.length;
-       const useFastPath = !line._loop && !opts.tension && !opts.stepped && !borderDash;
-       return useFastPath ? fastPathSegment : pathSegment;
+  const opts = line.options;
+  const borderDash = opts.borderDash && opts.borderDash.length;
+  const useFastPath = !line._loop && !opts.tension && !opts.stepped && !borderDash;
+  return useFastPath ? fastPathSegment : pathSegment;
 }
 
 /**
  * @private
  */
 function _getInterpolationMethod(options) {
-       if (options.stepped) {
-               return _steppedInterpolation;
-       }
+  if (options.stepped) {
+    return _steppedInterpolation;
+  }
 
-       if (options.tension) {
-               return _bezierInterpolation;
-       }
+  if (options.tension) {
+    return _bezierInterpolation;
+  }
 
-       return _pointInLine;
+  return _pointInLine;
 }
 
 export default class LineElement extends Element {
 
-       constructor(cfg) {
-               super();
-
-               this.animated = true;
-               this.options = undefined;
-               this._loop = undefined;
-               this._fullLoop = undefined;
-               this._path = undefined;
-               this._points = undefined;
-               this._segments = undefined;
-               this._pointsUpdated = false;
-
-               if (cfg) {
-                       Object.assign(this, cfg);
-               }
-       }
-
-       updateControlPoints(chartArea) {
-               const me = this;
-               const options = me.options;
-               if (options.tension && !options.stepped && !me._pointsUpdated) {
-                       const loop = options.spanGaps ? me._loop : me._fullLoop;
-                       _updateBezierControlPoints(me._points, options, chartArea, loop);
-                       me._pointsUpdated = true;
-               }
-       }
-
-       set points(points) {
-               const me = this;
-               me._points = points;
-               delete me._segments;
-               delete me._path;
-               me._pointsUpdated = false;
-       }
-
-       get points() {
-               return this._points;
-       }
-
-       get segments() {
-               return this._segments || (this._segments = _computeSegments(this));
-       }
-
-       /**
+  constructor(cfg) {
+    super();
+
+    this.animated = true;
+    this.options = undefined;
+    this._loop = undefined;
+    this._fullLoop = undefined;
+    this._path = undefined;
+    this._points = undefined;
+    this._segments = undefined;
+    this._pointsUpdated = false;
+
+    if (cfg) {
+      Object.assign(this, cfg);
+    }
+  }
+
+  updateControlPoints(chartArea) {
+    const me = this;
+    const options = me.options;
+    if (options.tension && !options.stepped && !me._pointsUpdated) {
+      const loop = options.spanGaps ? me._loop : me._fullLoop;
+      _updateBezierControlPoints(me._points, options, chartArea, loop);
+      me._pointsUpdated = true;
+    }
+  }
+
+  set points(points) {
+    const me = this;
+    me._points = points;
+    delete me._segments;
+    delete me._path;
+    me._pointsUpdated = false;
+  }
+
+  get points() {
+    return this._points;
+  }
+
+  get segments() {
+    return this._segments || (this._segments = _computeSegments(this));
+  }
+
+  /**
         * First non-skipped point on this line
         * @returns {PointElement|undefined}
         */
-       first() {
-               const segments = this.segments;
-               const points = this.points;
-               return segments.length && points[segments[0].start];
-       }
+  first() {
+    const segments = this.segments;
+    const points = this.points;
+    return segments.length && points[segments[0].start];
+  }
 
-       /**
+  /**
         * Last non-skipped point on this line
         * @returns {PointElement|undefined}
         */
-       last() {
-               const segments = this.segments;
-               const points = this.points;
-               const count = segments.length;
-               return count && points[segments[count - 1].end];
-       }
-
-       /**
+  last() {
+    const segments = this.segments;
+    const points = this.points;
+    const count = segments.length;
+    return count && points[segments[count - 1].end];
+  }
+
+  /**
         * Interpolate a point in this line at the same value on `property` as
         * the reference `point` provided
         * @param {PointElement} point - the reference point
         * @param {string} property - the property to match on
         * @returns {PointElement|undefined}
         */
-       interpolate(point, property) {
-               const me = this;
-               const options = me.options;
-               const value = point[property];
-               const points = me.points;
-               const segments = _boundSegments(me, {property, start: value, end: value});
-
-               if (!segments.length) {
-                       return;
-               }
-
-               const result = [];
-               const _interpolate = _getInterpolationMethod(options);
-               let i, ilen;
-               for (i = 0, ilen = segments.length; i < ilen; ++i) {
-                       const {start, end} = segments[i];
-                       const p1 = points[start];
-                       const p2 = points[end];
-                       if (p1 === p2) {
-                               result.push(p1);
-                               continue;
-                       }
-                       const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
-                       const interpolated = _interpolate(p1, p2, t, options.stepped);
-                       interpolated[property] = point[property];
-                       result.push(interpolated);
-               }
-               return result.length === 1 ? result[0] : result;
-       }
-
-       /**
+  interpolate(point, property) {
+    const me = this;
+    const options = me.options;
+    const value = point[property];
+    const points = me.points;
+    const segments = _boundSegments(me, {property, start: value, end: value});
+
+    if (!segments.length) {
+      return;
+    }
+
+    const result = [];
+    const _interpolate = _getInterpolationMethod(options);
+    let i, ilen;
+    for (i = 0, ilen = segments.length; i < ilen; ++i) {
+      const {start, end} = segments[i];
+      const p1 = points[start];
+      const p2 = points[end];
+      if (p1 === p2) {
+        result.push(p1);
+        continue;
+      }
+      const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
+      const interpolated = _interpolate(p1, p2, t, options.stepped);
+      interpolated[property] = point[property];
+      result.push(interpolated);
+    }
+    return result.length === 1 ? result[0] : result;
+  }
+
+  /**
         * Append a segment of this line to current path.
         * @param {CanvasRenderingContext2D} ctx
         * @param {object} segment
@@ -315,72 +315,72 @@ export default class LineElement extends Element {
         * @param {number} params.end - limit segment to points ending at `start` + `count` index
         * @returns {undefined|boolean} - true if the segment is a full loop (path should be closed)
         */
-       pathSegment(ctx, segment, params) {
-               const segmentMethod = _getSegmentMethod(this);
-               return segmentMethod(ctx, this, segment, params);
-       }
+  pathSegment(ctx, segment, params) {
+    const segmentMethod = _getSegmentMethod(this);
+    return segmentMethod(ctx, this, segment, params);
+  }
 
-       /**
+  /**
         * Append all segments of this line to current path.
         * @param {CanvasRenderingContext2D|Path2D} ctx
         * @param {number} [start]
         * @param {number} [count]
         * @returns {undefined|boolean} - true if line is a full loop (path should be closed)
         */
-       path(ctx, start, count) {
-               const me = this;
-               const segments = me.segments;
-               const ilen = segments.length;
-               const segmentMethod = _getSegmentMethod(me);
-               let loop = me._loop;
-
-               start = start || 0;
-               count = count || (me.points.length - start);
-
-               for (let i = 0; i < ilen; ++i) {
-                       loop &= segmentMethod(ctx, me, segments[i], {start, end: start + count - 1});
-               }
-               return !!loop;
-       }
-
-       /**
+  path(ctx, start, count) {
+    const me = this;
+    const segments = me.segments;
+    const ilen = segments.length;
+    const segmentMethod = _getSegmentMethod(me);
+    let loop = me._loop;
+
+    start = start || 0;
+    count = count || (me.points.length - start);
+
+    for (let i = 0; i < ilen; ++i) {
+      loop &= segmentMethod(ctx, me, segments[i], {start, end: start + count - 1});
+    }
+    return !!loop;
+  }
+
+  /**
         * Draw
         * @param {CanvasRenderingContext2D} ctx
         * @param {object} chartArea
         * @param {number} [start]
         * @param {number} [count]
         */
-       draw(ctx, chartArea, start, count) {
-               const me = this;
-               const options = me.options || {};
-               const points = me.points || [];
+  draw(ctx, chartArea, start, count) {
+    const me = this;
+    const options = me.options || {};
+    const points = me.points || [];
 
-               if (!points.length || !options.borderWidth) {
-                       return;
-               }
+    if (!points.length || !options.borderWidth) {
+      return;
+    }
 
-               ctx.save();
+    ctx.save();
 
-               setStyle(ctx, options);
+    setStyle(ctx, options);
 
-               let path = me._path;
-               if (!path) {
-                       path = me._path = new Path2D();
-                       if (me.path(path, start, count)) {
-                               path.closePath();
-                       }
-               }
+    let path = me._path;
+    if (!path) {
+      path = me._path = new Path2D();
+      if (me.path(path, start, count)) {
+        path.closePath();
+      }
+    }
 
-               ctx.stroke(path);
+    ctx.stroke(path);
 
-               ctx.restore();
+    ctx.restore();
 
-               if (me.animated) {
-                       // When line is animated, the control points and path are not cached.
-                       me._pointsUpdated = false;
-                       me._path = undefined;
-               }
-       }
+    if (me.animated) {
+      // When line is animated, the control points and path are not cached.
+      me._pointsUpdated = false;
+      me._path = undefined;
+    }
+  }
 }
 
 LineElement.id = 'line';
@@ -389,20 +389,20 @@ LineElement.id = 'line';
  * @type {any}
  */
 LineElement.defaults = {
-       borderCapStyle: 'butt',
-       borderDash: [],
-       borderDashOffset: 0,
-       borderJoinStyle: 'miter',
-       borderWidth: 3,
-       capBezierPoints: true,
-       fill: false,
-       tension: 0
+  borderCapStyle: 'butt',
+  borderDash: [],
+  borderDashOffset: 0,
+  borderJoinStyle: 'miter',
+  borderWidth: 3,
+  capBezierPoints: true,
+  fill: false,
+  tension: 0
 };
 
 /**
  * @type {any}
  */
 LineElement.defaultRoutes = {
-       backgroundColor: 'backgroundColor',
-       borderColor: 'borderColor'
+  backgroundColor: 'backgroundColor',
+  borderColor: 'borderColor'
 };
index 7f7e75bb050464380a1a0c473bdca403ac634357..8ee204c29f08b192ff14a0a547d95aa221eb4a97 100644 (file)
@@ -3,67 +3,67 @@ import {drawPoint} from '../helpers/helpers.canvas';
 
 export default class PointElement extends Element {
 
-       constructor(cfg) {
-               super();
-
-               this.options = undefined;
-               this.skip = undefined;
-               this.stop = undefined;
-
-               if (cfg) {
-                       Object.assign(this, cfg);
-               }
-       }
-
-       inRange(mouseX, mouseY, useFinalPosition) {
-               const options = this.options;
-               const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
-               return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2));
-       }
-
-       inXRange(mouseX, useFinalPosition) {
-               const options = this.options;
-               const {x} = this.getProps(['x'], useFinalPosition);
-
-               return (Math.abs(mouseX - x) < options.radius + options.hitRadius);
-       }
-
-       inYRange(mouseY, useFinalPosition) {
-               const options = this.options;
-               const {y} = this.getProps(['x'], useFinalPosition);
-               return (Math.abs(mouseY - y) < options.radius + options.hitRadius);
-       }
-
-       getCenterPoint(useFinalPosition) {
-               const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
-               return {x, y};
-       }
-
-       size() {
-               const options = this.options || {};
-               const radius = Math.max(options.radius, options.hoverRadius) || 0;
-               const borderWidth = radius && options.borderWidth || 0;
-               return (radius + borderWidth) * 2;
-       }
-
-       draw(ctx) {
-               const me = this;
-               const options = me.options;
-
-               if (me.skip || options.radius < 0.1) {
-                       return;
-               }
-
-               ctx.strokeStyle = options.borderColor;
-               ctx.lineWidth = options.borderWidth;
-               ctx.fillStyle = options.backgroundColor;
-               drawPoint(ctx, options, me.x, me.y);
-       }
-
-       getRange() {
-               const options = this.options || {};
-               return options.radius + options.hitRadius;
-       }
+  constructor(cfg) {
+    super();
+
+    this.options = undefined;
+    this.skip = undefined;
+    this.stop = undefined;
+
+    if (cfg) {
+      Object.assign(this, cfg);
+    }
+  }
+
+  inRange(mouseX, mouseY, useFinalPosition) {
+    const options = this.options;
+    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+    return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2));
+  }
+
+  inXRange(mouseX, useFinalPosition) {
+    const options = this.options;
+    const {x} = this.getProps(['x'], useFinalPosition);
+
+    return (Math.abs(mouseX - x) < options.radius + options.hitRadius);
+  }
+
+  inYRange(mouseY, useFinalPosition) {
+    const options = this.options;
+    const {y} = this.getProps(['x'], useFinalPosition);
+    return (Math.abs(mouseY - y) < options.radius + options.hitRadius);
+  }
+
+  getCenterPoint(useFinalPosition) {
+    const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+    return {x, y};
+  }
+
+  size() {
+    const options = this.options || {};
+    const radius = Math.max(options.radius, options.hoverRadius) || 0;
+    const borderWidth = radius && options.borderWidth || 0;
+    return (radius + borderWidth) * 2;
+  }
+
+  draw(ctx) {
+    const me = this;
+    const options = me.options;
+
+    if (me.skip || options.radius < 0.1) {
+      return;
+    }
+
+    ctx.strokeStyle = options.borderColor;
+    ctx.lineWidth = options.borderWidth;
+    ctx.fillStyle = options.backgroundColor;
+    drawPoint(ctx, options, me.x, me.y);
+  }
+
+  getRange() {
+    const options = this.options || {};
+    return options.radius + options.hitRadius;
+  }
 }
 
 PointElement.id = 'point';
@@ -72,18 +72,18 @@ PointElement.id = 'point';
  * @type {any}
  */
 PointElement.defaults = {
-       borderWidth: 1,
-       hitRadius: 1,
-       hoverBorderWidth: 1,
-       hoverRadius: 4,
-       pointStyle: 'circle',
-       radius: 3
+  borderWidth: 1,
+  hitRadius: 1,
+  hoverBorderWidth: 1,
+  hoverRadius: 4,
+  pointStyle: 'circle',
+  radius: 3
 };
 
 /**
  * @type {any}
  */
 PointElement.defaultRoutes = {
-       backgroundColor: 'backgroundColor',
-       borderColor: 'borderColor'
+  backgroundColor: 'backgroundColor',
+  borderColor: 'borderColor'
 };
index 25fcfc4bf82e5a98726d6f920cec4ba83006ee23..02adec42c25cc5d5661b16460ec3766e7e5a424e 100644 (file)
@@ -16,11 +16,11 @@ import {PI, TAU, HALF_PI, QUARTER_PI, TWO_THIRDS_PI, RAD_PER_DEG} from './helper
  * @private
  */
 export function toFontString(font) {
-       if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
-               return null;
-       }
+  if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
+    return null;
+  }
 
-       return (font.style ? font.style + ' ' : '')
+  return (font.style ? font.style + ' ' : '')
                + (font.weight ? font.weight + ' ' : '')
                + font.size + 'px '
                + font.family;
@@ -30,66 +30,66 @@ export function toFontString(font) {
  * @private
  */
 export function _measureText(ctx, data, gc, longest, string) {
-       let textWidth = data[string];
-       if (!textWidth) {
-               textWidth = data[string] = ctx.measureText(string).width;
-               gc.push(string);
-       }
-       if (textWidth > longest) {
-               longest = textWidth;
-       }
-       return longest;
+  let textWidth = data[string];
+  if (!textWidth) {
+    textWidth = data[string] = ctx.measureText(string).width;
+    gc.push(string);
+  }
+  if (textWidth > longest) {
+    longest = textWidth;
+  }
+  return longest;
 }
 
 /**
  * @private
  */
 export function _longestText(ctx, font, arrayOfThings, cache) {
-       cache = cache || {};
-       let data = cache.data = cache.data || {};
-       let gc = cache.garbageCollect = cache.garbageCollect || [];
-
-       if (cache.font !== font) {
-               data = cache.data = {};
-               gc = cache.garbageCollect = [];
-               cache.font = font;
-       }
-
-       ctx.save();
-
-       ctx.font = font;
-       let longest = 0;
-       const ilen = arrayOfThings.length;
-       let i, j, jlen, thing, nestedThing;
-       for (i = 0; i < ilen; i++) {
-               thing = arrayOfThings[i];
-
-               // Undefined strings and arrays should not be measured
-               if (thing !== undefined && thing !== null && isArray(thing) !== true) {
-                       longest = _measureText(ctx, data, gc, longest, thing);
-               } else if (isArray(thing)) {
-                       // if it is an array lets measure each element
-                       // to do maybe simplify this function a bit so we can do this more recursively?
-                       for (j = 0, jlen = thing.length; j < jlen; j++) {
-                               nestedThing = thing[j];
-                               // Undefined strings and arrays should not be measured
-                               if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
-                                       longest = _measureText(ctx, data, gc, longest, nestedThing);
-                               }
-                       }
-               }
-       }
-
-       ctx.restore();
-
-       const gcLen = gc.length / 2;
-       if (gcLen > arrayOfThings.length) {
-               for (i = 0; i < gcLen; i++) {
-                       delete data[gc[i]];
-               }
-               gc.splice(0, gcLen);
-       }
-       return longest;
+  cache = cache || {};
+  let data = cache.data = cache.data || {};
+  let gc = cache.garbageCollect = cache.garbageCollect || [];
+
+  if (cache.font !== font) {
+    data = cache.data = {};
+    gc = cache.garbageCollect = [];
+    cache.font = font;
+  }
+
+  ctx.save();
+
+  ctx.font = font;
+  let longest = 0;
+  const ilen = arrayOfThings.length;
+  let i, j, jlen, thing, nestedThing;
+  for (i = 0; i < ilen; i++) {
+    thing = arrayOfThings[i];
+
+    // Undefined strings and arrays should not be measured
+    if (thing !== undefined && thing !== null && isArray(thing) !== true) {
+      longest = _measureText(ctx, data, gc, longest, thing);
+    } else if (isArray(thing)) {
+      // if it is an array lets measure each element
+      // to do maybe simplify this function a bit so we can do this more recursively?
+      for (j = 0, jlen = thing.length; j < jlen; j++) {
+        nestedThing = thing[j];
+        // Undefined strings and arrays should not be measured
+        if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
+          longest = _measureText(ctx, data, gc, longest, nestedThing);
+        }
+      }
+    }
+  }
+
+  ctx.restore();
+
+  const gcLen = gc.length / 2;
+  if (gcLen > arrayOfThings.length) {
+    for (i = 0; i < gcLen; i++) {
+      delete data[gc[i]];
+    }
+    gc.splice(0, gcLen);
+  }
+  return longest;
 }
 
 /**
@@ -101,9 +101,9 @@ export function _longestText(ctx, font, arrayOfThings, cache) {
  * @private
  */
 export function _alignPixel(chart, pixel, width) {
-       const devicePixelRatio = chart.currentDevicePixelRatio;
-       const halfWidth = width / 2;
-       return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
+  const devicePixelRatio = chart.currentDevicePixelRatio;
+  const halfWidth = width / 2;
+  return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
 }
 
 /**
@@ -112,132 +112,132 @@ export function _alignPixel(chart, pixel, width) {
  * @param {CanvasRenderingContext2D} [ctx]
  */
 export function clearCanvas(canvas, ctx) {
-       ctx = ctx || canvas.getContext('2d');
-
-       ctx.save();
-       // canvas.width and canvas.height do not consider the canvas transform,
-       // while clearRect does
-       ctx.resetTransform();
-       ctx.clearRect(0, 0, canvas.width, canvas.height);
-       ctx.restore();
+  ctx = ctx || canvas.getContext('2d');
+
+  ctx.save();
+  // canvas.width and canvas.height do not consider the canvas transform,
+  // while clearRect does
+  ctx.resetTransform();
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+  ctx.restore();
 }
 
 export function drawPoint(ctx, options, x, y) {
-       let type, xOffset, yOffset, size, cornerRadius;
-       const style = options.pointStyle;
-       const rotation = options.rotation;
-       const radius = options.radius;
-       let rad = (rotation || 0) * RAD_PER_DEG;
-
-       if (style && typeof style === 'object') {
-               type = style.toString();
-               if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
-                       ctx.save();
-                       ctx.translate(x, y);
-                       ctx.rotate(rad);
-                       ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
-                       ctx.restore();
-                       return;
-               }
-       }
-
-       if (isNaN(radius) || radius <= 0) {
-               return;
-       }
-
-       ctx.beginPath();
-
-       switch (style) {
-       // Default includes circle
-       default:
-               ctx.arc(x, y, radius, 0, TAU);
-               ctx.closePath();
-               break;
-       case 'triangle':
-               ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
-               rad += TWO_THIRDS_PI;
-               ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
-               rad += TWO_THIRDS_PI;
-               ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
-               ctx.closePath();
-               break;
-       case 'rectRounded':
-               // NOTE: the rounded rect implementation changed to use `arc` instead of
-               // `quadraticCurveTo` since it generates better results when rect is
-               // almost a circle. 0.516 (instead of 0.5) produces results with visually
-               // closer proportion to the previous impl and it is inscribed in the
-               // circle with `radius`. For more details, see the following PRs:
-               // https://github.com/chartjs/Chart.js/issues/5597
-               // https://github.com/chartjs/Chart.js/issues/5858
-               cornerRadius = radius * 0.516;
-               size = radius - cornerRadius;
-               xOffset = Math.cos(rad + QUARTER_PI) * size;
-               yOffset = Math.sin(rad + QUARTER_PI) * size;
-               ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
-               ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
-               ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
-               ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
-               ctx.closePath();
-               break;
-       case 'rect':
-               if (!rotation) {
-                       size = Math.SQRT1_2 * radius;
-                       ctx.rect(x - size, y - size, 2 * size, 2 * size);
-                       break;
-               }
-               rad += QUARTER_PI;
-               /* falls through */
-       case 'rectRot':
-               xOffset = Math.cos(rad) * radius;
-               yOffset = Math.sin(rad) * radius;
-               ctx.moveTo(x - xOffset, y - yOffset);
-               ctx.lineTo(x + yOffset, y - xOffset);
-               ctx.lineTo(x + xOffset, y + yOffset);
-               ctx.lineTo(x - yOffset, y + xOffset);
-               ctx.closePath();
-               break;
-       case 'crossRot':
-               rad += QUARTER_PI;
-               /* falls through */
-       case 'cross':
-               xOffset = Math.cos(rad) * radius;
-               yOffset = Math.sin(rad) * radius;
-               ctx.moveTo(x - xOffset, y - yOffset);
-               ctx.lineTo(x + xOffset, y + yOffset);
-               ctx.moveTo(x + yOffset, y - xOffset);
-               ctx.lineTo(x - yOffset, y + xOffset);
-               break;
-       case 'star':
-               xOffset = Math.cos(rad) * radius;
-               yOffset = Math.sin(rad) * radius;
-               ctx.moveTo(x - xOffset, y - yOffset);
-               ctx.lineTo(x + xOffset, y + yOffset);
-               ctx.moveTo(x + yOffset, y - xOffset);
-               ctx.lineTo(x - yOffset, y + xOffset);
-               rad += QUARTER_PI;
-               xOffset = Math.cos(rad) * radius;
-               yOffset = Math.sin(rad) * radius;
-               ctx.moveTo(x - xOffset, y - yOffset);
-               ctx.lineTo(x + xOffset, y + yOffset);
-               ctx.moveTo(x + yOffset, y - xOffset);
-               ctx.lineTo(x - yOffset, y + xOffset);
-               break;
-       case 'line':
-               xOffset = Math.cos(rad) * radius;
-               yOffset = Math.sin(rad) * radius;
-               ctx.moveTo(x - xOffset, y - yOffset);
-               ctx.lineTo(x + xOffset, y + yOffset);
-               break;
-       case 'dash':
-               ctx.moveTo(x, y);
-               ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
-               break;
-       }
-
-       ctx.fill();
-       if (options.borderWidth > 0) {
-               ctx.stroke();
-       }
+  let type, xOffset, yOffset, size, cornerRadius;
+  const style = options.pointStyle;
+  const rotation = options.rotation;
+  const radius = options.radius;
+  let rad = (rotation || 0) * RAD_PER_DEG;
+
+  if (style && typeof style === 'object') {
+    type = style.toString();
+    if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
+      ctx.save();
+      ctx.translate(x, y);
+      ctx.rotate(rad);
+      ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
+      ctx.restore();
+      return;
+    }
+  }
+
+  if (isNaN(radius) || radius <= 0) {
+    return;
+  }
+
+  ctx.beginPath();
+
+  switch (style) {
+  // Default includes circle
+  default:
+    ctx.arc(x, y, radius, 0, TAU);
+    ctx.closePath();
+    break;
+  case 'triangle':
+    ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+    rad += TWO_THIRDS_PI;
+    ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+    rad += TWO_THIRDS_PI;
+    ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+    ctx.closePath();
+    break;
+  case 'rectRounded':
+    // NOTE: the rounded rect implementation changed to use `arc` instead of
+    // `quadraticCurveTo` since it generates better results when rect is
+    // almost a circle. 0.516 (instead of 0.5) produces results with visually
+    // closer proportion to the previous impl and it is inscribed in the
+    // circle with `radius`. For more details, see the following PRs:
+    // https://github.com/chartjs/Chart.js/issues/5597
+    // https://github.com/chartjs/Chart.js/issues/5858
+    cornerRadius = radius * 0.516;
+    size = radius - cornerRadius;
+    xOffset = Math.cos(rad + QUARTER_PI) * size;
+    yOffset = Math.sin(rad + QUARTER_PI) * size;
+    ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
+    ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
+    ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
+    ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
+    ctx.closePath();
+    break;
+  case 'rect':
+    if (!rotation) {
+      size = Math.SQRT1_2 * radius;
+      ctx.rect(x - size, y - size, 2 * size, 2 * size);
+      break;
+    }
+    rad += QUARTER_PI;
+    /* falls through */
+  case 'rectRot':
+    xOffset = Math.cos(rad) * radius;
+    yOffset = Math.sin(rad) * radius;
+    ctx.moveTo(x - xOffset, y - yOffset);
+    ctx.lineTo(x + yOffset, y - xOffset);
+    ctx.lineTo(x + xOffset, y + yOffset);
+    ctx.lineTo(x - yOffset, y + xOffset);
+    ctx.closePath();
+    break;
+  case 'crossRot':
+    rad += QUARTER_PI;
+    /* falls through */
+  case 'cross':
+    xOffset = Math.cos(rad) * radius;
+    yOffset = Math.sin(rad) * radius;
+    ctx.moveTo(x - xOffset, y - yOffset);
+    ctx.lineTo(x + xOffset, y + yOffset);
+    ctx.moveTo(x + yOffset, y - xOffset);
+    ctx.lineTo(x - yOffset, y + xOffset);
+    break;
+  case 'star':
+    xOffset = Math.cos(rad) * radius;
+    yOffset = Math.sin(rad) * radius;
+    ctx.moveTo(x - xOffset, y - yOffset);
+    ctx.lineTo(x + xOffset, y + yOffset);
+    ctx.moveTo(x + yOffset, y - xOffset);
+    ctx.lineTo(x - yOffset, y + xOffset);
+    rad += QUARTER_PI;
+    xOffset = Math.cos(rad) * radius;
+    yOffset = Math.sin(rad) * radius;
+    ctx.moveTo(x - xOffset, y - yOffset);
+    ctx.lineTo(x + xOffset, y + yOffset);
+    ctx.moveTo(x + yOffset, y - xOffset);
+    ctx.lineTo(x - yOffset, y + xOffset);
+    break;
+  case 'line':
+    xOffset = Math.cos(rad) * radius;
+    yOffset = Math.sin(rad) * radius;
+    ctx.moveTo(x - xOffset, y - yOffset);
+    ctx.lineTo(x + xOffset, y + yOffset);
+    break;
+  case 'dash':
+    ctx.moveTo(x, y);
+    ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
+    break;
+  }
+
+  ctx.fill();
+  if (options.borderWidth > 0) {
+    ctx.stroke();
+  }
 }
 
 /**
@@ -248,131 +248,131 @@ export function drawPoint(ctx, options, x, y) {
  * @private
  */
 export function _isPointInArea(point, area) {
-       const epsilon = 0.5; // margin - to match rounded decimals
+  const epsilon = 0.5; // margin - to match rounded decimals
 
-       return point.x > area.left - epsilon && point.x < area.right + epsilon &&
+  return point.x > area.left - epsilon && point.x < area.right + epsilon &&
                point.y > area.top - epsilon && point.y < area.bottom + epsilon;
 }
 
 export function clipArea(ctx, area) {
-       ctx.save();
-       ctx.beginPath();
-       ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
-       ctx.clip();
+  ctx.save();
+  ctx.beginPath();
+  ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
+  ctx.clip();
 }
 
 export function unclipArea(ctx) {
-       ctx.restore();
+  ctx.restore();
 }
 
 /**
  * @private
  */
 export function _steppedLineTo(ctx, previous, target, flip, mode) {
-       if (!previous) {
-               return ctx.lineTo(target.x, target.y);
-       }
-       if (mode === 'middle') {
-               const midpoint = (previous.x + target.x) / 2.0;
-               ctx.lineTo(midpoint, previous.y);
-               ctx.lineTo(midpoint, target.y);
-       } else if (mode === 'after' !== !!flip) {
-               ctx.lineTo(previous.x, target.y);
-       } else {
-               ctx.lineTo(target.x, previous.y);
-       }
-       ctx.lineTo(target.x, target.y);
+  if (!previous) {
+    return ctx.lineTo(target.x, target.y);
+  }
+  if (mode === 'middle') {
+    const midpoint = (previous.x + target.x) / 2.0;
+    ctx.lineTo(midpoint, previous.y);
+    ctx.lineTo(midpoint, target.y);
+  } else if (mode === 'after' !== !!flip) {
+    ctx.lineTo(previous.x, target.y);
+  } else {
+    ctx.lineTo(target.x, previous.y);
+  }
+  ctx.lineTo(target.x, target.y);
 }
 
 /**
  * @private
  */
 export function _bezierCurveTo(ctx, previous, target, flip) {
-       if (!previous) {
-               return ctx.lineTo(target.x, target.y);
-       }
-       ctx.bezierCurveTo(
-               flip ? previous.controlPointPreviousX : previous.controlPointNextX,
-               flip ? previous.controlPointPreviousY : previous.controlPointNextY,
-               flip ? target.controlPointNextX : target.controlPointPreviousX,
-               flip ? target.controlPointNextY : target.controlPointPreviousY,
-               target.x,
-               target.y);
+  if (!previous) {
+    return ctx.lineTo(target.x, target.y);
+  }
+  ctx.bezierCurveTo(
+    flip ? previous.controlPointPreviousX : previous.controlPointNextX,
+    flip ? previous.controlPointPreviousY : previous.controlPointNextY,
+    flip ? target.controlPointNextX : target.controlPointPreviousX,
+    flip ? target.controlPointNextY : target.controlPointPreviousY,
+    target.x,
+    target.y);
 }
 
 /**
  * Render text onto the canvas
  */
 export function renderText(ctx, text, x, y, font, opts = {}) {
-       const lines = isArray(text) ? text : [text];
-       const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
-       let i, line;
+  const lines = isArray(text) ? text : [text];
+  const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
+  let i, line;
 
-       ctx.save();
+  ctx.save();
 
-       if (opts.translation) {
-               ctx.translate(opts.translation[0], opts.translation[1]);
-       }
+  if (opts.translation) {
+    ctx.translate(opts.translation[0], opts.translation[1]);
+  }
 
-       if (!isNullOrUndef(opts.rotation)) {
-               ctx.rotate(opts.rotation);
-       }
+  if (!isNullOrUndef(opts.rotation)) {
+    ctx.rotate(opts.rotation);
+  }
 
-       ctx.font = font.string;
+  ctx.font = font.string;
 
-       if (opts.color) {
-               ctx.fillStyle = opts.color;
-       }
+  if (opts.color) {
+    ctx.fillStyle = opts.color;
+  }
 
-       if (opts.textAlign) {
-               ctx.textAlign = opts.textAlign;
-       }
+  if (opts.textAlign) {
+    ctx.textAlign = opts.textAlign;
+  }
 
-       if (opts.textBaseline) {
-               ctx.textBaseline = opts.textBaseline;
-       }
+  if (opts.textBaseline) {
+    ctx.textBaseline = opts.textBaseline;
+  }
 
-       for (i = 0; i < lines.length; ++i) {
-               line = lines[i];
+  for (i = 0; i < lines.length; ++i) {
+    line = lines[i];
 
-               if (stroke) {
-                       if (opts.strokeColor) {
-                               ctx.strokeStyle = opts.strokeColor;
-                       }
+    if (stroke) {
+      if (opts.strokeColor) {
+        ctx.strokeStyle = opts.strokeColor;
+      }
 
-                       if (!isNullOrUndef(opts.strokeWidth)) {
-                               ctx.lineWidth = opts.strokeWidth;
-                       }
+      if (!isNullOrUndef(opts.strokeWidth)) {
+        ctx.lineWidth = opts.strokeWidth;
+      }
 
-                       ctx.strokeText(line, x, y, opts.maxWidth);
-               }
+      ctx.strokeText(line, x, y, opts.maxWidth);
+    }
 
-               ctx.fillText(line, x, y, opts.maxWidth);
+    ctx.fillText(line, x, y, opts.maxWidth);
 
-               if (opts.strikethrough || opts.underline) {
-                       /**
+    if (opts.strikethrough || opts.underline) {
+      /**
                         * Now that IE11 support has been dropped, we can use more
                         * of the TextMetrics object. The actual bounding boxes
                         * are unflagged in Chrome, Firefox, Edge, and Safari so they
                         * can be safely used.
                         * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility
                         */
-                       const metrics = ctx.measureText(line);
-                       const left = x - metrics.actualBoundingBoxLeft;
-                       const right = x + metrics.actualBoundingBoxRight;
-                       const top = y - metrics.actualBoundingBoxAscent;
-                       const bottom = y + metrics.actualBoundingBoxDescent;
-                       const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
-
-                       ctx.strokeStyle = ctx.fillStyle;
-                       ctx.beginPath();
-                       ctx.lineWidth = opts.decorationWidth || 2;
-                       ctx.moveTo(left, yDecoration);
-                       ctx.lineTo(right, yDecoration);
-                       ctx.stroke();
-               }
-               y += font.lineHeight;
-       }
-
-       ctx.restore();
+      const metrics = ctx.measureText(line);
+      const left = x - metrics.actualBoundingBoxLeft;
+      const right = x + metrics.actualBoundingBoxRight;
+      const top = y - metrics.actualBoundingBoxAscent;
+      const bottom = y + metrics.actualBoundingBoxDescent;
+      const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
+
+      ctx.strokeStyle = ctx.fillStyle;
+      ctx.beginPath();
+      ctx.lineWidth = opts.decorationWidth || 2;
+      ctx.moveTo(left, yDecoration);
+      ctx.lineTo(right, yDecoration);
+      ctx.stroke();
+    }
+    y += font.lineHeight;
+  }
+
+  ctx.restore();
 }
index d973464d2dd9a43168274eb99bafd871db803588..66f2a557b07a55c772ccf2429b6c546f6651f17e 100644 (file)
@@ -8,21 +8,21 @@ import {_capitalize} from './helpers.core';
  * @private
  */
 export function _lookup(table, value, cmp) {
-       cmp = cmp || ((index) => table[index] < value);
-       let hi = table.length - 1;
-       let lo = 0;
-       let mid;
-
-       while (hi - lo > 1) {
-               mid = (lo + hi) >> 1;
-               if (cmp(mid)) {
-                       lo = mid;
-               } else {
-                       hi = mid;
-               }
-       }
-
-       return {lo, hi};
+  cmp = cmp || ((index) => table[index] < value);
+  let hi = table.length - 1;
+  let lo = 0;
+  let mid;
+
+  while (hi - lo > 1) {
+    mid = (lo + hi) >> 1;
+    if (cmp(mid)) {
+      lo = mid;
+    } else {
+      hi = mid;
+    }
+  }
+
+  return {lo, hi};
 }
 
 /**
@@ -33,7 +33,7 @@ export function _lookup(table, value, cmp) {
  * @private
  */
 export const _lookupByKey = (table, key, value) =>
-       _lookup(table, value, index => table[index][key] < value);
+  _lookup(table, value, index => table[index][key] < value);
 
 /**
  * Reverse binary search
@@ -43,7 +43,7 @@ export const _lookupByKey = (table, key, value) =>
  * @private
  */
 export const _rlookupByKey = (table, key, value) =>
-       _lookup(table, value, index => table[index][key] >= value);
+  _lookup(table, value, index => table[index][key] >= value);
 
 /**
  * Return subset of `values` between `min` and `max` inclusive.
@@ -53,19 +53,19 @@ export const _rlookupByKey = (table, key, value) =>
  * @param {number} max - max value
  */
 export function _filterBetween(values, min, max) {
-       let start = 0;
-       let end = values.length;
-
-       while (start < end && values[start] < min) {
-               start++;
-       }
-       while (end > start && values[end - 1] > max) {
-               end--;
-       }
-
-       return start > 0 || end < values.length
-               ? values.slice(start, end)
-               : values;
+  let start = 0;
+  let end = values.length;
+
+  while (start < end && values[start] < min) {
+    start++;
+  }
+  while (end > start && values[end - 1] > max) {
+    end--;
+  }
+
+  return start > 0 || end < values.length
+    ? values.slice(start, end)
+    : values;
 }
 
 const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
@@ -76,39 +76,39 @@ const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
  * called on the '_onData*' callbacks (e.g. _onDataPush, etc.) with same arguments.
  */
 export function listenArrayEvents(array, listener) {
-       if (array._chartjs) {
-               array._chartjs.listeners.push(listener);
-               return;
-       }
-
-       Object.defineProperty(array, '_chartjs', {
-               configurable: true,
-               enumerable: false,
-               value: {
-                       listeners: [listener]
-               }
-       });
-
-       arrayEvents.forEach((key) => {
-               const method = '_onData' + _capitalize(key);
-               const base = array[key];
-
-               Object.defineProperty(array, key, {
-                       configurable: true,
-                       enumerable: false,
-                       value(...args) {
-                               const res = base.apply(this, args);
-
-                               array._chartjs.listeners.forEach((object) => {
-                                       if (typeof object[method] === 'function') {
-                                               object[method](...args);
-                                       }
-                               });
-
-                               return res;
-                       }
-               });
-       });
+  if (array._chartjs) {
+    array._chartjs.listeners.push(listener);
+    return;
+  }
+
+  Object.defineProperty(array, '_chartjs', {
+    configurable: true,
+    enumerable: false,
+    value: {
+      listeners: [listener]
+    }
+  });
+
+  arrayEvents.forEach((key) => {
+    const method = '_onData' + _capitalize(key);
+    const base = array[key];
+
+    Object.defineProperty(array, key, {
+      configurable: true,
+      enumerable: false,
+      value(...args) {
+        const res = base.apply(this, args);
+
+        array._chartjs.listeners.forEach((object) => {
+          if (typeof object[method] === 'function') {
+            object[method](...args);
+          }
+        });
+
+        return res;
+      }
+    });
+  });
 }
 
 
@@ -117,46 +117,46 @@ export function listenArrayEvents(array, listener) {
  * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
  */
 export function unlistenArrayEvents(array, listener) {
-       const stub = array._chartjs;
-       if (!stub) {
-               return;
-       }
-
-       const listeners = stub.listeners;
-       const index = listeners.indexOf(listener);
-       if (index !== -1) {
-               listeners.splice(index, 1);
-       }
-
-       if (listeners.length > 0) {
-               return;
-       }
-
-       arrayEvents.forEach((key) => {
-               delete array[key];
-       });
-
-       delete array._chartjs;
+  const stub = array._chartjs;
+  if (!stub) {
+    return;
+  }
+
+  const listeners = stub.listeners;
+  const index = listeners.indexOf(listener);
+  if (index !== -1) {
+    listeners.splice(index, 1);
+  }
+
+  if (listeners.length > 0) {
+    return;
+  }
+
+  arrayEvents.forEach((key) => {
+    delete array[key];
+  });
+
+  delete array._chartjs;
 }
 
 /**
  * @param {Array} items
  */
 export function _arrayUnique(items) {
-       const set = new Set();
-       let i, ilen;
-
-       for (i = 0, ilen = items.length; i < ilen; ++i) {
-               set.add(items[i]);
-       }
-
-       if (set.size === ilen) {
-               return items;
-       }
-
-       const result = [];
-       set.forEach(item => {
-               result.push(item);
-       });
-       return result;
+  const set = new Set();
+  let i, ilen;
+
+  for (i = 0, ilen = items.length; i < ilen; ++i) {
+    set.add(items[i]);
+  }
+
+  if (set.size === ilen) {
+    return items;
+  }
+
+  const result = [];
+  set.forEach(item => {
+    result.push(item);
+  });
+  return result;
 }
index 50d4fa4f78c8b55822af4bda9d039c25a8722822..62e66716153e4ddde1662891b4d19d19ae7b5523 100644 (file)
@@ -3,11 +3,11 @@ import colorLib from '@kurkle/color';
 const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern;
 
 export function color(value) {
-       return isPatternOrGradient(value) ? value : colorLib(value);
+  return isPatternOrGradient(value) ? value : colorLib(value);
 }
 
 export function getHoverColor(value) {
-       return isPatternOrGradient(value)
-               ? value
-               : colorLib(value).saturate(0.5).darken(0.1).hexString();
+  return isPatternOrGradient(value)
+    ? value
+    : colorLib(value).saturate(0.5).darken(0.1).hexString();
 }
index 5a4da3489a45f2d7737b85ba3b285d4592e08572..a0c63fde08ba67e0a49a2f4fb43f3cc000ccfad1 100644 (file)
@@ -12,10 +12,10 @@ export function noop() {}
  * @function
  */
 export const uid = (function() {
-       let id = 0;
-       return function() {
-               return id++;
-       };
+  let id = 0;
+  return function() {
+    return id++;
+  };
 }());
 
 /**
@@ -25,7 +25,7 @@ export const uid = (function() {
  * @since 2.7.0
  */
 export function isNullOrUndef(value) {
-       return value === null || typeof value === 'undefined';
+  return value === null || typeof value === 'undefined';
 }
 
 /**
@@ -35,14 +35,14 @@ export function isNullOrUndef(value) {
  * @function
  */
 export function isArray(value) {
-       if (Array.isArray && Array.isArray(value)) {
-               return true;
-       }
-       const type = Object.prototype.toString.call(value);
-       if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
-               return true;
-       }
-       return false;
+  if (Array.isArray && Array.isArray(value)) {
+    return true;
+  }
+  const type = Object.prototype.toString.call(value);
+  if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
+    return true;
+  }
+  return false;
 }
 
 /**
@@ -52,7 +52,7 @@ export function isArray(value) {
  * @since 2.7.0
  */
 export function isObject(value) {
-       return value !== null && Object.prototype.toString.call(value) === '[object Object]';
+  return value !== null && Object.prototype.toString.call(value) === '[object Object]';
 }
 
 /**
@@ -62,7 +62,7 @@ export function isObject(value) {
  */
 const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value);
 export {
-       isNumberFinite as isFinite,
+  isNumberFinite as isFinite,
 };
 
 /**
@@ -72,7 +72,7 @@ export {
  * @returns {*}
  */
 export function finiteOrDefault(value, defaultValue) {
-       return isNumberFinite(value) ? value : defaultValue;
+  return isNumberFinite(value) ? value : defaultValue;
 }
 
 /**
@@ -82,7 +82,7 @@ export function finiteOrDefault(value, defaultValue) {
  * @returns {*}
  */
 export function valueOrDefault(value, defaultValue) {
-       return typeof value === 'undefined' ? defaultValue : value;
+  return typeof value === 'undefined' ? defaultValue : value;
 }
 
 /**
@@ -94,9 +94,9 @@ export function valueOrDefault(value, defaultValue) {
  * @returns {*}
  */
 export function callback(fn, args, thisArg) {
-       if (fn && typeof fn.call === 'function') {
-               return fn.apply(thisArg, args);
-       }
+  if (fn && typeof fn.call === 'function') {
+    return fn.apply(thisArg, args);
+  }
 }
 
 /**
@@ -109,25 +109,25 @@ export function callback(fn, args, thisArg) {
  * @param {boolean} [reverse] - If true, iterates backward on the loopable.
  */
 export function each(loopable, fn, thisArg, reverse) {
-       let i, len, keys;
-       if (isArray(loopable)) {
-               len = loopable.length;
-               if (reverse) {
-                       for (i = len - 1; i >= 0; i--) {
-                               fn.call(thisArg, loopable[i], i);
-                       }
-               } else {
-                       for (i = 0; i < len; i++) {
-                               fn.call(thisArg, loopable[i], i);
-                       }
-               }
-       } else if (isObject(loopable)) {
-               keys = Object.keys(loopable);
-               len = keys.length;
-               for (i = 0; i < len; i++) {
-                       fn.call(thisArg, loopable[keys[i]], keys[i]);
-               }
-       }
+  let i, len, keys;
+  if (isArray(loopable)) {
+    len = loopable.length;
+    if (reverse) {
+      for (i = len - 1; i >= 0; i--) {
+        fn.call(thisArg, loopable[i], i);
+      }
+    } else {
+      for (i = 0; i < len; i++) {
+        fn.call(thisArg, loopable[i], i);
+      }
+    }
+  } else if (isObject(loopable)) {
+    keys = Object.keys(loopable);
+    len = keys.length;
+    for (i = 0; i < len; i++) {
+      fn.call(thisArg, loopable[keys[i]], keys[i]);
+    }
+  }
 }
 
 /**
@@ -138,22 +138,22 @@ export function each(loopable, fn, thisArg, reverse) {
  * @private
  */
 export function _elementsEqual(a0, a1) {
-       let i, ilen, v0, v1;
+  let i, ilen, v0, v1;
 
-       if (!a0 || !a1 || a0.length !== a1.length) {
-               return false;
-       }
+  if (!a0 || !a1 || a0.length !== a1.length) {
+    return false;
+  }
 
-       for (i = 0, ilen = a0.length; i < ilen; ++i) {
-               v0 = a0[i];
-               v1 = a1[i];
+  for (i = 0, ilen = a0.length; i < ilen; ++i) {
+    v0 = a0[i];
+    v1 = a1[i];
 
-               if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
-                       return false;
-               }
-       }
+    if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
+      return false;
+    }
+  }
 
-       return true;
+  return true;
 }
 
 /**
@@ -162,28 +162,28 @@ export function _elementsEqual(a0, a1) {
  * @returns {*}
  */
 export function clone(source) {
-       if (isArray(source)) {
-               return source.map(clone);
-       }
+  if (isArray(source)) {
+    return source.map(clone);
+  }
 
-       if (isObject(source)) {
-               const target = Object.create(null);
-               const keys = Object.keys(source);
-               const klen = keys.length;
-               let k = 0;
+  if (isObject(source)) {
+    const target = Object.create(null);
+    const keys = Object.keys(source);
+    const klen = keys.length;
+    let k = 0;
 
-               for (; k < klen; ++k) {
-                       target[keys[k]] = clone(source[keys[k]]);
-               }
+    for (; k < klen; ++k) {
+      target[keys[k]] = clone(source[keys[k]]);
+    }
 
-               return target;
-       }
+    return target;
+  }
 
-       return source;
+  return source;
 }
 
 function isValidKey(key) {
-       return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
+  return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
 }
 
 /**
@@ -192,19 +192,19 @@ function isValidKey(key) {
  * @private
  */
 export function _merger(key, target, source, options) {
-       if (!isValidKey(key)) {
-               return;
-       }
-
-       const tval = target[key];
-       const sval = source[key];
-
-       if (isObject(tval) && isObject(sval)) {
-               // eslint-disable-next-line no-use-before-define
-               merge(tval, sval, options);
-       } else {
-               target[key] = clone(sval);
-       }
+  if (!isValidKey(key)) {
+    return;
+  }
+
+  const tval = target[key];
+  const sval = source[key];
+
+  if (isObject(tval) && isObject(sval)) {
+    // eslint-disable-next-line no-use-before-define
+    merge(tval, sval, options);
+  } else {
+    target[key] = clone(sval);
+  }
 }
 
 /**
@@ -217,29 +217,29 @@ export function _merger(key, target, source, options) {
  * @returns {object} The `target` object.
  */
 export function merge(target, source, options) {
-       const sources = isArray(source) ? source : [source];
-       const ilen = sources.length;
+  const sources = isArray(source) ? source : [source];
+  const ilen = sources.length;
 
-       if (!isObject(target)) {
-               return target;
-       }
+  if (!isObject(target)) {
+    return target;
+  }
 
-       options = options || {};
-       const merger = options.merger || _merger;
+  options = options || {};
+  const merger = options.merger || _merger;
 
-       for (let i = 0; i < ilen; ++i) {
-               source = sources[i];
-               if (!isObject(source)) {
-                       continue;
-               }
+  for (let i = 0; i < ilen; ++i) {
+    source = sources[i];
+    if (!isObject(source)) {
+      continue;
+    }
 
-               const keys = Object.keys(source);
-               for (let k = 0, klen = keys.length; k < klen; ++k) {
-                       merger(keys[k], target, source, options);
-               }
-       }
+    const keys = Object.keys(source);
+    for (let k = 0, klen = keys.length; k < klen; ++k) {
+      merger(keys[k], target, source, options);
+    }
+  }
 
-       return target;
+  return target;
 }
 
 /**
@@ -250,8 +250,8 @@ export function merge(target, source, options) {
  * @returns {object} The `target` object.
  */
 export function mergeIf(target, source) {
-       // eslint-disable-next-line no-use-before-define
-       return merge(target, source, {merger: _mergerIf});
+  // eslint-disable-next-line no-use-before-define
+  return merge(target, source, {merger: _mergerIf});
 }
 
 /**
@@ -259,53 +259,53 @@ export function mergeIf(target, source) {
  * @private
  */
 export function _mergerIf(key, target, source) {
-       if (!isValidKey(key)) {
-               return;
-       }
-
-       const tval = target[key];
-       const sval = source[key];
-
-       if (isObject(tval) && isObject(sval)) {
-               mergeIf(tval, sval);
-       } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
-               target[key] = clone(sval);
-       }
+  if (!isValidKey(key)) {
+    return;
+  }
+
+  const tval = target[key];
+  const sval = source[key];
+
+  if (isObject(tval) && isObject(sval)) {
+    mergeIf(tval, sval);
+  } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
+    target[key] = clone(sval);
+  }
 }
 
 /**
  * @private
  */
 export function _deprecated(scope, value, previous, current) {
-       if (value !== undefined) {
-               console.warn(scope + ': "' + previous +
+  if (value !== undefined) {
+    console.warn(scope + ': "' + previous +
                        '" is deprecated. Please use "' + current + '" instead');
-       }
+  }
 }
 
 export function resolveObjectKey(obj, key) {
-       // Special cases for `x` and `y` keys. It's quite a lot faster to aceess this way.
-       // Those are the default keys Chart.js is resolving, so it makes sense to be fast.
-       if (key === 'x') {
-               return obj.x;
-       }
-       if (key === 'y') {
-               return obj.y;
-       }
-       const keys = key.split('.');
-       for (let i = 0, n = keys.length; i < n && obj; ++i) {
-               const k = keys[i];
-               if (!k) {
-                       break;
-               }
-               obj = obj[k];
-       }
-       return obj;
+  // Special cases for `x` and `y` keys. It's quite a lot faster to aceess this way.
+  // Those are the default keys Chart.js is resolving, so it makes sense to be fast.
+  if (key === 'x') {
+    return obj.x;
+  }
+  if (key === 'y') {
+    return obj.y;
+  }
+  const keys = key.split('.');
+  for (let i = 0, n = keys.length; i < n && obj; ++i) {
+    const k = keys[i];
+    if (!k) {
+      break;
+    }
+    obj = obj[k];
+  }
+  return obj;
 }
 
 /**
  * @private
  */
 export function _capitalize(str) {
-       return str.charAt(0).toUpperCase() + str.slice(1);
+  return str.charAt(0).toUpperCase() + str.slice(1);
 }
index b4a4fe9ab3852dc8fb5d6bfe61ee591dda74195c..4a2445cf60e599da5ad1b562f27a4f0c1782b60a 100644 (file)
@@ -4,184 +4,184 @@ import {_isPointInArea} from './helpers.canvas';
 const EPSILON = Number.EPSILON || 1e-14;
 
 export function splineCurve(firstPoint, middlePoint, afterPoint, t) {
-       // Props to Rob Spencer at scaled innovation for his post on splining between points
-       // http://scaledinnovation.com/analytics/splines/aboutSplines.html
-
-       // This function must also respect "skipped" points
-
-       const previous = firstPoint.skip ? middlePoint : firstPoint;
-       const current = middlePoint;
-       const next = afterPoint.skip ? middlePoint : afterPoint;
-
-       const d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
-       const d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
-
-       let s01 = d01 / (d01 + d12);
-       let s12 = d12 / (d01 + d12);
-
-       // If all points are the same, s01 & s02 will be inf
-       s01 = isNaN(s01) ? 0 : s01;
-       s12 = isNaN(s12) ? 0 : s12;
-
-       const fa = t * s01; // scaling factor for triangle Ta
-       const fb = t * s12;
-
-       return {
-               previous: {
-                       x: current.x - fa * (next.x - previous.x),
-                       y: current.y - fa * (next.y - previous.y)
-               },
-               next: {
-                       x: current.x + fb * (next.x - previous.x),
-                       y: current.y + fb * (next.y - previous.y)
-               }
-       };
+  // Props to Rob Spencer at scaled innovation for his post on splining between points
+  // http://scaledinnovation.com/analytics/splines/aboutSplines.html
+
+  // This function must also respect "skipped" points
+
+  const previous = firstPoint.skip ? middlePoint : firstPoint;
+  const current = middlePoint;
+  const next = afterPoint.skip ? middlePoint : afterPoint;
+
+  const d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
+  const d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
+
+  let s01 = d01 / (d01 + d12);
+  let s12 = d12 / (d01 + d12);
+
+  // If all points are the same, s01 & s02 will be inf
+  s01 = isNaN(s01) ? 0 : s01;
+  s12 = isNaN(s12) ? 0 : s12;
+
+  const fa = t * s01; // scaling factor for triangle Ta
+  const fb = t * s12;
+
+  return {
+    previous: {
+      x: current.x - fa * (next.x - previous.x),
+      y: current.y - fa * (next.y - previous.y)
+    },
+    next: {
+      x: current.x + fb * (next.x - previous.x),
+      y: current.y + fb * (next.y - previous.y)
+    }
+  };
 }
 
 export function splineCurveMonotone(points) {
-       // This function calculates Bézier control points in a similar way than |splineCurve|,
-       // but preserves monotonicity of the provided data and ensures no local extremums are added
-       // between the dataset discrete points due to the interpolation.
-       // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
-
-       const pointsWithTangents = (points || []).map((point) => ({
-               model: point,
-               deltaK: 0,
-               mK: 0
-       }));
-
-       // Calculate slopes (deltaK) and initialize tangents (mK)
-       const pointsLen = pointsWithTangents.length;
-       let i, pointBefore, pointCurrent, pointAfter;
-       for (i = 0; i < pointsLen; ++i) {
-               pointCurrent = pointsWithTangents[i];
-               if (pointCurrent.model.skip) {
-                       continue;
-               }
-
-               pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
-               pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
-               if (pointAfter && !pointAfter.model.skip) {
-                       const slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
-
-                       // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
-                       pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
-               }
-
-               if (!pointBefore || pointBefore.model.skip) {
-                       pointCurrent.mK = pointCurrent.deltaK;
-               } else if (!pointAfter || pointAfter.model.skip) {
-                       pointCurrent.mK = pointBefore.deltaK;
-               } else if (sign(pointBefore.deltaK) !== sign(pointCurrent.deltaK)) {
-                       pointCurrent.mK = 0;
-               } else {
-                       pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
-               }
-       }
-
-       // Adjust tangents to ensure monotonic properties
-       let alphaK, betaK, tauK, squaredMagnitude;
-       for (i = 0; i < pointsLen - 1; ++i) {
-               pointCurrent = pointsWithTangents[i];
-               pointAfter = pointsWithTangents[i + 1];
-               if (pointCurrent.model.skip || pointAfter.model.skip) {
-                       continue;
-               }
-
-               if (almostEquals(pointCurrent.deltaK, 0, EPSILON)) {
-                       pointCurrent.mK = pointAfter.mK = 0;
-                       continue;
-               }
-
-               alphaK = pointCurrent.mK / pointCurrent.deltaK;
-               betaK = pointAfter.mK / pointCurrent.deltaK;
-               squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
-               if (squaredMagnitude <= 9) {
-                       continue;
-               }
-
-               tauK = 3 / Math.sqrt(squaredMagnitude);
-               pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
-               pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
-       }
-
-       // Compute control points
-       let deltaX;
-       for (i = 0; i < pointsLen; ++i) {
-               pointCurrent = pointsWithTangents[i];
-               if (pointCurrent.model.skip) {
-                       continue;
-               }
-
-               pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
-               pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
-               if (pointBefore && !pointBefore.model.skip) {
-                       deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
-                       pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
-                       pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
-               }
-               if (pointAfter && !pointAfter.model.skip) {
-                       deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
-                       pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
-                       pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
-               }
-       }
+  // This function calculates Bézier control points in a similar way than |splineCurve|,
+  // but preserves monotonicity of the provided data and ensures no local extremums are added
+  // between the dataset discrete points due to the interpolation.
+  // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+
+  const pointsWithTangents = (points || []).map((point) => ({
+    model: point,
+    deltaK: 0,
+    mK: 0
+  }));
+
+  // Calculate slopes (deltaK) and initialize tangents (mK)
+  const pointsLen = pointsWithTangents.length;
+  let i, pointBefore, pointCurrent, pointAfter;
+  for (i = 0; i < pointsLen; ++i) {
+    pointCurrent = pointsWithTangents[i];
+    if (pointCurrent.model.skip) {
+      continue;
+    }
+
+    pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+    pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+    if (pointAfter && !pointAfter.model.skip) {
+      const slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
+
+      // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
+      pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
+    }
+
+    if (!pointBefore || pointBefore.model.skip) {
+      pointCurrent.mK = pointCurrent.deltaK;
+    } else if (!pointAfter || pointAfter.model.skip) {
+      pointCurrent.mK = pointBefore.deltaK;
+    } else if (sign(pointBefore.deltaK) !== sign(pointCurrent.deltaK)) {
+      pointCurrent.mK = 0;
+    } else {
+      pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
+    }
+  }
+
+  // Adjust tangents to ensure monotonic properties
+  let alphaK, betaK, tauK, squaredMagnitude;
+  for (i = 0; i < pointsLen - 1; ++i) {
+    pointCurrent = pointsWithTangents[i];
+    pointAfter = pointsWithTangents[i + 1];
+    if (pointCurrent.model.skip || pointAfter.model.skip) {
+      continue;
+    }
+
+    if (almostEquals(pointCurrent.deltaK, 0, EPSILON)) {
+      pointCurrent.mK = pointAfter.mK = 0;
+      continue;
+    }
+
+    alphaK = pointCurrent.mK / pointCurrent.deltaK;
+    betaK = pointAfter.mK / pointCurrent.deltaK;
+    squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
+    if (squaredMagnitude <= 9) {
+      continue;
+    }
+
+    tauK = 3 / Math.sqrt(squaredMagnitude);
+    pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
+    pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
+  }
+
+  // Compute control points
+  let deltaX;
+  for (i = 0; i < pointsLen; ++i) {
+    pointCurrent = pointsWithTangents[i];
+    if (pointCurrent.model.skip) {
+      continue;
+    }
+
+    pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
+    pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
+    if (pointBefore && !pointBefore.model.skip) {
+      deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
+      pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
+      pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
+    }
+    if (pointAfter && !pointAfter.model.skip) {
+      deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
+      pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
+      pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
+    }
+  }
 }
 
 function capControlPoint(pt, min, max) {
-       return Math.max(Math.min(pt, max), min);
+  return Math.max(Math.min(pt, max), min);
 }
 
 function capBezierPoints(points, area) {
-       let i, ilen, point;
-       for (i = 0, ilen = points.length; i < ilen; ++i) {
-               point = points[i];
-               if (!_isPointInArea(point, area)) {
-                       continue;
-               }
-               if (i > 0 && _isPointInArea(points[i - 1], area)) {
-                       point.controlPointPreviousX = capControlPoint(point.controlPointPreviousX, area.left, area.right);
-                       point.controlPointPreviousY = capControlPoint(point.controlPointPreviousY, area.top, area.bottom);
-               }
-               if (i < points.length - 1 && _isPointInArea(points[i + 1], area)) {
-                       point.controlPointNextX = capControlPoint(point.controlPointNextX, area.left, area.right);
-                       point.controlPointNextY = capControlPoint(point.controlPointNextY, area.top, area.bottom);
-               }
-       }
+  let i, ilen, point;
+  for (i = 0, ilen = points.length; i < ilen; ++i) {
+    point = points[i];
+    if (!_isPointInArea(point, area)) {
+      continue;
+    }
+    if (i > 0 && _isPointInArea(points[i - 1], area)) {
+      point.controlPointPreviousX = capControlPoint(point.controlPointPreviousX, area.left, area.right);
+      point.controlPointPreviousY = capControlPoint(point.controlPointPreviousY, area.top, area.bottom);
+    }
+    if (i < points.length - 1 && _isPointInArea(points[i + 1], area)) {
+      point.controlPointNextX = capControlPoint(point.controlPointNextX, area.left, area.right);
+      point.controlPointNextY = capControlPoint(point.controlPointNextY, area.top, area.bottom);
+    }
+  }
 }
 
 /**
  * @private
  */
 export function _updateBezierControlPoints(points, options, area, loop) {
-       let i, ilen, point, controlPoints;
-
-       // Only consider points that are drawn in case the spanGaps option is used
-       if (options.spanGaps) {
-               points = points.filter((pt) => !pt.skip);
-       }
-
-       if (options.cubicInterpolationMode === 'monotone') {
-               splineCurveMonotone(points);
-       } else {
-               let prev = loop ? points[points.length - 1] : points[0];
-               for (i = 0, ilen = points.length; i < ilen; ++i) {
-                       point = points[i];
-                       controlPoints = splineCurve(
-                               prev,
-                               point,
-                               points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen],
-                               options.tension
-                       );
-                       point.controlPointPreviousX = controlPoints.previous.x;
-                       point.controlPointPreviousY = controlPoints.previous.y;
-                       point.controlPointNextX = controlPoints.next.x;
-                       point.controlPointNextY = controlPoints.next.y;
-                       prev = point;
-               }
-       }
-
-       if (options.capBezierPoints) {
-               capBezierPoints(points, area);
-       }
+  let i, ilen, point, controlPoints;
+
+  // Only consider points that are drawn in case the spanGaps option is used
+  if (options.spanGaps) {
+    points = points.filter((pt) => !pt.skip);
+  }
+
+  if (options.cubicInterpolationMode === 'monotone') {
+    splineCurveMonotone(points);
+  } else {
+    let prev = loop ? points[points.length - 1] : points[0];
+    for (i = 0, ilen = points.length; i < ilen; ++i) {
+      point = points[i];
+      controlPoints = splineCurve(
+        prev,
+        point,
+        points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen],
+        options.tension
+      );
+      point.controlPointPreviousX = controlPoints.previous.x;
+      point.controlPointPreviousY = controlPoints.previous.y;
+      point.controlPointNextX = controlPoints.next.x;
+      point.controlPointNextY = controlPoints.next.y;
+      prev = point;
+    }
+  }
+
+  if (options.capBezierPoints) {
+    capBezierPoints(points, area);
+  }
 }
index 9eacb10614422002656820fdb34e646f60f50918..ea032113d1b8a6765605a06b60824f095fe77c8f 100644 (file)
@@ -4,11 +4,11 @@ import {INFINITY} from './helpers.math';
  * @private
  */
 export function _getParentNode(domNode) {
-       let parent = domNode.parentNode;
-       if (parent && parent.toString() === '[object ShadowRoot]') {
-               parent = parent.host;
-       }
-       return parent;
+  let parent = domNode.parentNode;
+  if (parent && parent.toString() === '[object ShadowRoot]') {
+    parent = parent.host;
+  }
+  return parent;
 }
 
 /**
@@ -16,146 +16,146 @@ export function _getParentNode(domNode) {
  * @private
  */
 function parseMaxStyle(styleValue, node, parentProperty) {
-       let valueInPixels;
-       if (typeof styleValue === 'string') {
-               valueInPixels = parseInt(styleValue, 10);
-
-               if (styleValue.indexOf('%') !== -1) {
-                       // percentage * size in dimension
-                       valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
-               }
-       } else {
-               valueInPixels = styleValue;
-       }
-
-       return valueInPixels;
+  let valueInPixels;
+  if (typeof styleValue === 'string') {
+    valueInPixels = parseInt(styleValue, 10);
+
+    if (styleValue.indexOf('%') !== -1) {
+      // percentage * size in dimension
+      valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+    }
+  } else {
+    valueInPixels = styleValue;
+  }
+
+  return valueInPixels;
 }
 
 const getComputedStyle = (element) => window.getComputedStyle(element, null);
 
 export function getStyle(el, property) {
-       return getComputedStyle(el).getPropertyValue(property);
+  return getComputedStyle(el).getPropertyValue(property);
 }
 
 const positions = ['top', 'right', 'bottom', 'left'];
 function getPositionedStyle(styles, style, suffix) {
-       const result = {};
-       suffix = suffix ? '-' + suffix : '';
-       for (let i = 0; i < 4; i++) {
-               const pos = positions[i];
-               result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
-       }
-       result.width = result.left + result.right;
-       result.height = result.top + result.bottom;
-       return result;
+  const result = {};
+  suffix = suffix ? '-' + suffix : '';
+  for (let i = 0; i < 4; i++) {
+    const pos = positions[i];
+    result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
+  }
+  result.width = result.left + result.right;
+  result.height = result.top + result.bottom;
+  return result;
 }
 
 const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot);
 
 function getCanvasPosition(evt, canvas) {
-       const e = evt.originalEvent || evt;
-       const touches = e.touches;
-       const source = touches && touches.length ? touches[0] : e;
-       const {offsetX, offsetY} = source;
-       let box = false;
-       let x, y;
-       if (useOffsetPos(offsetX, offsetY, e.target)) {
-               x = offsetX;
-               y = offsetY;
-       } else {
-               const rect = canvas.getBoundingClientRect();
-               x = source.clientX - rect.left;
-               y = source.clientY - rect.top;
-               box = true;
-       }
-       return {x, y, box};
+  const e = evt.originalEvent || evt;
+  const touches = e.touches;
+  const source = touches && touches.length ? touches[0] : e;
+  const {offsetX, offsetY} = source;
+  let box = false;
+  let x, y;
+  if (useOffsetPos(offsetX, offsetY, e.target)) {
+    x = offsetX;
+    y = offsetY;
+  } else {
+    const rect = canvas.getBoundingClientRect();
+    x = source.clientX - rect.left;
+    y = source.clientY - rect.top;
+    box = true;
+  }
+  return {x, y, box};
 }
 
 export function getRelativePosition(evt, chart) {
-       const {canvas, currentDevicePixelRatio} = chart;
-       const style = getComputedStyle(canvas);
-       const borderBox = style.boxSizing === 'border-box';
-       const paddings = getPositionedStyle(style, 'padding');
-       const borders = getPositionedStyle(style, 'border', 'width');
-       const {x, y, box} = getCanvasPosition(evt, canvas);
-       const xOffset = paddings.left + (box && borders.left);
-       const yOffset = paddings.top + (box && borders.top);
-
-       let {width, height} = chart;
-       if (borderBox) {
-               width -= paddings.width + borders.width;
-               height -= paddings.height + borders.height;
-       }
-       return {
-               x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
-               y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
-       };
+  const {canvas, currentDevicePixelRatio} = chart;
+  const style = getComputedStyle(canvas);
+  const borderBox = style.boxSizing === 'border-box';
+  const paddings = getPositionedStyle(style, 'padding');
+  const borders = getPositionedStyle(style, 'border', 'width');
+  const {x, y, box} = getCanvasPosition(evt, canvas);
+  const xOffset = paddings.left + (box && borders.left);
+  const yOffset = paddings.top + (box && borders.top);
+
+  let {width, height} = chart;
+  if (borderBox) {
+    width -= paddings.width + borders.width;
+    height -= paddings.height + borders.height;
+  }
+  return {
+    x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
+    y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
+  };
 }
 
 function getContainerSize(canvas, width, height) {
-       let maxWidth, maxHeight;
-
-       if (width === undefined || height === undefined) {
-               const container = _getParentNode(canvas);
-               if (!container) {
-                       width = canvas.clientWidth;
-                       height = canvas.clientHeight;
-               } else {
-                       const rect = container.getBoundingClientRect(); // this is the border box of the container
-                       const containerStyle = getComputedStyle(container);
-                       const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
-                       const containerPadding = getPositionedStyle(containerStyle, 'padding');
-                       width = rect.width - containerPadding.width - containerBorder.width;
-                       height = rect.height - containerPadding.height - containerBorder.height;
-                       maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
-                       maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
-               }
-       }
-       return {
-               width,
-               height,
-               maxWidth: maxWidth || INFINITY,
-               maxHeight: maxHeight || INFINITY
-       };
+  let maxWidth, maxHeight;
+
+  if (width === undefined || height === undefined) {
+    const container = _getParentNode(canvas);
+    if (!container) {
+      width = canvas.clientWidth;
+      height = canvas.clientHeight;
+    } else {
+      const rect = container.getBoundingClientRect(); // this is the border box of the container
+      const containerStyle = getComputedStyle(container);
+      const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
+      const containerPadding = getPositionedStyle(containerStyle, 'padding');
+      width = rect.width - containerPadding.width - containerBorder.width;
+      height = rect.height - containerPadding.height - containerBorder.height;
+      maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
+      maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
+    }
+  }
+  return {
+    width,
+    height,
+    maxWidth: maxWidth || INFINITY,
+    maxHeight: maxHeight || INFINITY
+  };
 }
 
 export function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
-       const style = getComputedStyle(canvas);
-       const margins = getPositionedStyle(style, 'margin');
-       const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
-       const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
-       const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
-       let {width, height} = containerSize;
-
-       if (style.boxSizing === 'content-box') {
-               const borders = getPositionedStyle(style, 'border', 'width');
-               const paddings = getPositionedStyle(style, 'padding');
-               width -= paddings.width + borders.width;
-               height -= paddings.height + borders.height;
-       }
-       width = Math.max(0, width - margins.width);
-       height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height);
-       return {
-               width: Math.min(width, maxWidth, containerSize.maxWidth),
-               height: Math.min(height, maxHeight, containerSize.maxHeight)
-       };
+  const style = getComputedStyle(canvas);
+  const margins = getPositionedStyle(style, 'margin');
+  const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
+  const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
+  const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
+  let {width, height} = containerSize;
+
+  if (style.boxSizing === 'content-box') {
+    const borders = getPositionedStyle(style, 'border', 'width');
+    const paddings = getPositionedStyle(style, 'padding');
+    width -= paddings.width + borders.width;
+    height -= paddings.height + borders.height;
+  }
+  width = Math.max(0, width - margins.width);
+  height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height);
+  return {
+    width: Math.min(width, maxWidth, containerSize.maxWidth),
+    height: Math.min(height, maxHeight, containerSize.maxHeight)
+  };
 }
 
 export function retinaScale(chart, forceRatio) {
-       const pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
-       const {canvas, width, height} = chart;
-
-       canvas.height = height * pixelRatio;
-       canvas.width = width * pixelRatio;
-       chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
-
-       // If no style has been set on the canvas, the render size is used as display size,
-       // making the chart visually bigger, so let's enforce it to the "correct" values.
-       // See https://github.com/chartjs/Chart.js/issues/3575
-       if (canvas.style && !canvas.style.height && !canvas.style.width) {
-               canvas.style.height = height + 'px';
-               canvas.style.width = width + 'px';
-       }
+  const pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
+  const {canvas, width, height} = chart;
+
+  canvas.height = height * pixelRatio;
+  canvas.width = width * pixelRatio;
+  chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
+
+  // If no style has been set on the canvas, the render size is used as display size,
+  // making the chart visually bigger, so let's enforce it to the "correct" values.
+  // See https://github.com/chartjs/Chart.js/issues/3575
+  if (canvas.style && !canvas.style.height && !canvas.style.width) {
+    canvas.style.height = height + 'px';
+    canvas.style.width = width + 'px';
+  }
 }
 
 /**
@@ -164,22 +164,22 @@ export function retinaScale(chart, forceRatio) {
  * @private
  */
 export const supportsEventListenerOptions = (function() {
-       let passiveSupported = false;
-       try {
-               const options = {
-                       get passive() { // This function will be called when the browser attempts to access the passive property.
-                               passiveSupported = true;
-                               return false;
-                       }
-               };
-               // @ts-ignore
-               window.addEventListener('test', null, options);
-               // @ts-ignore
-               window.removeEventListener('test', null, options);
-       } catch (e) {
-               // continue regardless of error
-       }
-       return passiveSupported;
+  let passiveSupported = false;
+  try {
+    const options = {
+      get passive() { // This function will be called when the browser attempts to access the passive property.
+        passiveSupported = true;
+        return false;
+      }
+    };
+    // @ts-ignore
+    window.addEventListener('test', null, options);
+    // @ts-ignore
+    window.removeEventListener('test', null, options);
+  } catch (e) {
+    // continue regardless of error
+  }
+  return passiveSupported;
 }());
 
 /**
@@ -192,7 +192,7 @@ export const supportsEventListenerOptions = (function() {
  * @returns {number=} Size in pixels or undefined if unknown.
  */
 export function readUsedSize(element, property) {
-       const value = getStyle(element, property);
-       const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
-       return matches ? +matches[1] : undefined;
+  const value = getStyle(element, property);
+  const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+  return matches ? +matches[1] : undefined;
 }
index f88f222ba341f1c690756937816b6b82c1611193..0fbf717a78cad6bf9a5e9e67c1f24c222ec21e47 100644 (file)
@@ -6,230 +6,230 @@ import {PI, TAU, HALF_PI} from './helpers.math';
  * @see http://www.robertpenner.com/easing/
  */
 const effects = {
-       linear(t) {
-               return t;
-       },
-
-       easeInQuad(t) {
-               return t * t;
-       },
-
-       easeOutQuad(t) {
-               return -t * (t - 2);
-       },
-
-       easeInOutQuad(t) {
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * t * t;
-               }
-               return -0.5 * ((--t) * (t - 2) - 1);
-       },
-
-       easeInCubic(t) {
-               return t * t * t;
-       },
-
-       easeOutCubic(t) {
-               return (t -= 1) * t * t + 1;
-       },
-
-       easeInOutCubic(t) {
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * t * t * t;
-               }
-               return 0.5 * ((t -= 2) * t * t + 2);
-       },
-
-       easeInQuart(t) {
-               return t * t * t * t;
-       },
-
-       easeOutQuart(t) {
-               return -((t -= 1) * t * t * t - 1);
-       },
-
-       easeInOutQuart(t) {
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * t * t * t * t;
-               }
-               return -0.5 * ((t -= 2) * t * t * t - 2);
-       },
-
-       easeInQuint(t) {
-               return t * t * t * t * t;
-       },
-
-       easeOutQuint(t) {
-               return (t -= 1) * t * t * t * t + 1;
-       },
-
-       easeInOutQuint(t) {
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * t * t * t * t * t;
-               }
-               return 0.5 * ((t -= 2) * t * t * t * t + 2);
-       },
-
-       easeInSine(t) {
-               return -Math.cos(t * HALF_PI) + 1;
-       },
-
-       easeOutSine(t) {
-               return Math.sin(t * HALF_PI);
-       },
-
-       easeInOutSine(t) {
-               return -0.5 * (Math.cos(PI * t) - 1);
-       },
-
-       easeInExpo(t) {
-               return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
-       },
-
-       easeOutExpo(t) {
-               return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
-       },
-
-       easeInOutExpo(t) {
-               if (t === 0) {
-                       return 0;
-               }
-               if (t === 1) {
-                       return 1;
-               }
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * Math.pow(2, 10 * (t - 1));
-               }
-               return 0.5 * (-Math.pow(2, -10 * --t) + 2);
-       },
-
-       easeInCirc(t) {
-               if (t >= 1) {
-                       return t;
-               }
-               return -(Math.sqrt(1 - t * t) - 1);
-       },
-
-       easeOutCirc(t) {
-               return Math.sqrt(1 - (t -= 1) * t);
-       },
-
-       easeInOutCirc(t) {
-               if ((t /= 0.5) < 1) {
-                       return -0.5 * (Math.sqrt(1 - t * t) - 1);
-               }
-               return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
-       },
-
-       easeInElastic(t) {
-               let s = 1.70158;
-               let p = 0;
-               let a = 1;
-               if (t === 0) {
-                       return 0;
-               }
-               if (t === 1) {
-                       return 1;
-               }
-               if (!p) {
-                       p = 0.3;
-               }
-               if (a < 1) {
-                       a = 1;
-                       s = p / 4;
-               } else {
-                       s = p / TAU * Math.asin(1 / a);
-               }
-               return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
-       },
-
-       easeOutElastic(t) {
-               let s = 1.70158;
-               let p = 0;
-               let a = 1;
-               if (t === 0) {
-                       return 0;
-               }
-               if (t === 1) {
-                       return 1;
-               }
-               if (!p) {
-                       p = 0.3;
-               }
-               if (a < 1) {
-                       a = 1;
-                       s = p / 4;
-               } else {
-                       s = p / TAU * Math.asin(1 / a);
-               }
-               return a * Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
-       },
-
-       easeInOutElastic(t) {
-               let s = 1.70158;
-               let p = 0;
-               let a = 1;
-               if (t === 0) {
-                       return 0;
-               }
-               if ((t /= 0.5) === 2) {
-                       return 1;
-               }
-               if (!p) {
-                       p = 0.45;
-               }
-               if (a < 1) {
-                       a = 1;
-                       s = p / 4;
-               } else {
-                       s = p / TAU * Math.asin(1 / a);
-               }
-               if (t < 1) {
-                       return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
-               }
-               return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * TAU / p) * 0.5 + 1;
-       },
-       easeInBack(t) {
-               const s = 1.70158;
-               return t * t * ((s + 1) * t - s);
-       },
-
-       easeOutBack(t) {
-               const s = 1.70158;
-               return (t -= 1) * t * ((s + 1) * t + s) + 1;
-       },
-
-       easeInOutBack(t) {
-               let s = 1.70158;
-               if ((t /= 0.5) < 1) {
-                       return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
-               }
-               return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
-       },
-
-       easeInBounce(t) {
-               return 1 - effects.easeOutBounce(1 - t);
-       },
-
-       easeOutBounce(t) {
-               if (t < (1 / 2.75)) {
-                       return 7.5625 * t * t;
-               }
-               if (t < (2 / 2.75)) {
-                       return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
-               }
-               if (t < (2.5 / 2.75)) {
-                       return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
-               }
-               return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
-       },
-
-       easeInOutBounce(t) {
-               if (t < 0.5) {
-                       return effects.easeInBounce(t * 2) * 0.5;
-               }
-               return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
-       }
+  linear(t) {
+    return t;
+  },
+
+  easeInQuad(t) {
+    return t * t;
+  },
+
+  easeOutQuad(t) {
+    return -t * (t - 2);
+  },
+
+  easeInOutQuad(t) {
+    if ((t /= 0.5) < 1) {
+      return 0.5 * t * t;
+    }
+    return -0.5 * ((--t) * (t - 2) - 1);
+  },
+
+  easeInCubic(t) {
+    return t * t * t;
+  },
+
+  easeOutCubic(t) {
+    return (t -= 1) * t * t + 1;
+  },
+
+  easeInOutCubic(t) {
+    if ((t /= 0.5) < 1) {
+      return 0.5 * t * t * t;
+    }
+    return 0.5 * ((t -= 2) * t * t + 2);
+  },
+
+  easeInQuart(t) {
+    return t * t * t * t;
+  },
+
+  easeOutQuart(t) {
+    return -((t -= 1) * t * t * t - 1);
+  },
+
+  easeInOutQuart(t) {
+    if ((t /= 0.5) < 1) {
+      return 0.5 * t * t * t * t;
+    }
+    return -0.5 * ((t -= 2) * t * t * t - 2);
+  },
+
+  easeInQuint(t) {
+    return t * t * t * t * t;
+  },
+
+  easeOutQuint(t) {
+    return (t -= 1) * t * t * t * t + 1;
+  },
+
+  easeInOutQuint(t) {
+    if ((t /= 0.5) < 1) {
+      return 0.5 * t * t * t * t * t;
+    }
+    return 0.5 * ((t -= 2) * t * t * t * t + 2);
+  },
+
+  easeInSine(t) {
+    return -Math.cos(t * HALF_PI) + 1;
+  },
+
+  easeOutSine(t) {
+    return Math.sin(t * HALF_PI);
+  },
+
+  easeInOutSine(t) {
+    return -0.5 * (Math.cos(PI * t) - 1);
+  },
+
+  easeInExpo(t) {
+    return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
+  },
+
+  easeOutExpo(t) {
+    return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
+  },
+
+  easeInOutExpo(t) {
+    if (t === 0) {
+      return 0;
+    }
+    if (t === 1) {
+      return 1;
+    }
+    if ((t /= 0.5) < 1) {
+      return 0.5 * Math.pow(2, 10 * (t - 1));
+    }
+    return 0.5 * (-Math.pow(2, -10 * --t) + 2);
+  },
+
+  easeInCirc(t) {
+    if (t >= 1) {
+      return t;
+    }
+    return -(Math.sqrt(1 - t * t) - 1);
+  },
+
+  easeOutCirc(t) {
+    return Math.sqrt(1 - (t -= 1) * t);
+  },
+
+  easeInOutCirc(t) {
+    if ((t /= 0.5) < 1) {
+      return -0.5 * (Math.sqrt(1 - t * t) - 1);
+    }
+    return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+  },
+
+  easeInElastic(t) {
+    let s = 1.70158;
+    let p = 0;
+    let a = 1;
+    if (t === 0) {
+      return 0;
+    }
+    if (t === 1) {
+      return 1;
+    }
+    if (!p) {
+      p = 0.3;
+    }
+    if (a < 1) {
+      a = 1;
+      s = p / 4;
+    } else {
+      s = p / TAU * Math.asin(1 / a);
+    }
+    return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
+  },
+
+  easeOutElastic(t) {
+    let s = 1.70158;
+    let p = 0;
+    let a = 1;
+    if (t === 0) {
+      return 0;
+    }
+    if (t === 1) {
+      return 1;
+    }
+    if (!p) {
+      p = 0.3;
+    }
+    if (a < 1) {
+      a = 1;
+      s = p / 4;
+    } else {
+      s = p / TAU * Math.asin(1 / a);
+    }
+    return a * Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
+  },
+
+  easeInOutElastic(t) {
+    let s = 1.70158;
+    let p = 0;
+    let a = 1;
+    if (t === 0) {
+      return 0;
+    }
+    if ((t /= 0.5) === 2) {
+      return 1;
+    }
+    if (!p) {
+      p = 0.45;
+    }
+    if (a < 1) {
+      a = 1;
+      s = p / 4;
+    } else {
+      s = p / TAU * Math.asin(1 / a);
+    }
+    if (t < 1) {
+      return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
+    }
+    return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * TAU / p) * 0.5 + 1;
+  },
+  easeInBack(t) {
+    const s = 1.70158;
+    return t * t * ((s + 1) * t - s);
+  },
+
+  easeOutBack(t) {
+    const s = 1.70158;
+    return (t -= 1) * t * ((s + 1) * t + s) + 1;
+  },
+
+  easeInOutBack(t) {
+    let s = 1.70158;
+    if ((t /= 0.5) < 1) {
+      return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
+    }
+    return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+  },
+
+  easeInBounce(t) {
+    return 1 - effects.easeOutBounce(1 - t);
+  },
+
+  easeOutBounce(t) {
+    if (t < (1 / 2.75)) {
+      return 7.5625 * t * t;
+    }
+    if (t < (2 / 2.75)) {
+      return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
+    }
+    if (t < (2.5 / 2.75)) {
+      return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
+    }
+    return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
+  },
+
+  easeInOutBounce(t) {
+    if (t < 0.5) {
+      return effects.easeInBounce(t * 2) * 0.5;
+    }
+    return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
+  }
 };
 
 export default effects;
index 280ad832bc77b8b6b45cd506de11d940831d072d..21857a6e993ba09867d0957dab1e53bd250fc7e0 100644 (file)
@@ -1,18 +1,18 @@
 
 export function fontString(pixelSize, fontStyle, fontFamily) {
-       return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+  return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
 }
 
 /**
 * Request animation polyfill
 */
 export const requestAnimFrame = (function() {
-       if (typeof window === 'undefined') {
-               return function(callback) {
-                       return callback();
-               };
-       }
-       return window.requestAnimationFrame;
+  if (typeof window === 'undefined') {
+    return function(callback) {
+      return callback();
+    };
+  }
+  return window.requestAnimationFrame;
 }());
 
 /**
@@ -23,21 +23,21 @@ export const requestAnimFrame = (function() {
  * @param {function} [updateFn]
  */
 export function throttled(fn, thisArg, updateFn) {
-       const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args));
-       let ticking = false;
-       let args = [];
-
-       return function(...rest) {
-               args = updateArgs(rest);
-
-               if (!ticking) {
-                       ticking = true;
-                       requestAnimFrame.call(window, () => {
-                               ticking = false;
-                               fn.apply(thisArg, args);
-                       });
-               }
-       };
+  const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args));
+  let ticking = false;
+  let args = [];
+
+  return function(...rest) {
+    args = updateArgs(rest);
+
+    if (!ticking) {
+      ticking = true;
+      requestAnimFrame.call(window, () => {
+        ticking = false;
+        fn.apply(thisArg, args);
+      });
+    }
+  };
 }
 
 
index bf1ac4a8fb23db9635c8f8745399b5f7b4ba8171..6441efaad3fbf6ef9098c211b8517e78d5e6756a 100644 (file)
@@ -2,34 +2,34 @@
  * @private
  */
 export function _pointInLine(p1, p2, t, mode) { // eslint-disable-line no-unused-vars
-       return {
-               x: p1.x + t * (p2.x - p1.x),
-               y: p1.y + t * (p2.y - p1.y)
-       };
+  return {
+    x: p1.x + t * (p2.x - p1.x),
+    y: p1.y + t * (p2.y - p1.y)
+  };
 }
 
 /**
  * @private
  */
 export function _steppedInterpolation(p1, p2, t, mode) {
-       return {
-               x: p1.x + t * (p2.x - p1.x),
-               y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y
-               : mode === 'after' ? t < 1 ? p1.y : p2.y
-               : t > 0 ? p2.y : p1.y
-       };
+  return {
+    x: p1.x + t * (p2.x - p1.x),
+    y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y
+    : mode === 'after' ? t < 1 ? p1.y : p2.y
+    : t > 0 ? p2.y : p1.y
+  };
 }
 
 /**
  * @private
  */
 export function _bezierInterpolation(p1, p2, t, mode) { // eslint-disable-line no-unused-vars
-       const cp1 = {x: p1.controlPointNextX, y: p1.controlPointNextY};
-       const cp2 = {x: p2.controlPointPreviousX, y: p2.controlPointPreviousY};
-       const a = _pointInLine(p1, cp1, t);
-       const b = _pointInLine(cp1, cp2, t);
-       const c = _pointInLine(cp2, p2, t);
-       const d = _pointInLine(a, b, t);
-       const e = _pointInLine(b, c, t);
-       return _pointInLine(d, e, t);
+  const cp1 = {x: p1.controlPointNextX, y: p1.controlPointNextY};
+  const cp2 = {x: p2.controlPointPreviousX, y: p2.controlPointPreviousY};
+  const a = _pointInLine(p1, cp1, t);
+  const b = _pointInLine(cp1, cp2, t);
+  const c = _pointInLine(cp2, p2, t);
+  const d = _pointInLine(a, b, t);
+  const e = _pointInLine(b, c, t);
+  return _pointInLine(d, e, t);
 }
index 26e522013eed8ad3c46f306e161ebd9323fc3c13..41c8a6db254e6a640714e079f83381964148599b 100644 (file)
@@ -19,80 +19,80 @@ export const TWO_THIRDS_PI = PI * 2 / 3;
  * @private
  */
 export function _factorize(value) {
-       const result = [];
-       const sqrt = Math.sqrt(value);
-       let i;
-
-       for (i = 1; i < sqrt; i++) {
-               if (value % i === 0) {
-                       result.push(i);
-                       result.push(value / i);
-               }
-       }
-       if (sqrt === (sqrt | 0)) { // if value is a square number
-               result.push(sqrt);
-       }
-
-       result.sort((a, b) => a - b).pop();
-       return result;
+  const result = [];
+  const sqrt = Math.sqrt(value);
+  let i;
+
+  for (i = 1; i < sqrt; i++) {
+    if (value % i === 0) {
+      result.push(i);
+      result.push(value / i);
+    }
+  }
+  if (sqrt === (sqrt | 0)) { // if value is a square number
+    result.push(sqrt);
+  }
+
+  result.sort((a, b) => a - b).pop();
+  return result;
 }
 
 export const log10 = Math.log10 || function(x) {
-       const exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
-       // Check for whole powers of 10,
-       // which due to floating point rounding error should be corrected.
-       const powerOf10 = Math.round(exponent);
-       const isPowerOf10 = x === Math.pow(10, powerOf10);
+  const exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
+  // Check for whole powers of 10,
+  // which due to floating point rounding error should be corrected.
+  const powerOf10 = Math.round(exponent);
+  const isPowerOf10 = x === Math.pow(10, powerOf10);
 
-       return isPowerOf10 ? powerOf10 : exponent;
+  return isPowerOf10 ? powerOf10 : exponent;
 };
 
 export function isNumber(n) {
-       return !isNaN(parseFloat(n)) && isFinite(n);
+  return !isNaN(parseFloat(n)) && isFinite(n);
 }
 
 export function almostEquals(x, y, epsilon) {
-       return Math.abs(x - y) < epsilon;
+  return Math.abs(x - y) < epsilon;
 }
 
 export function almostWhole(x, epsilon) {
-       const rounded = Math.round(x);
-       return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
+  const rounded = Math.round(x);
+  return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
 }
 
 /**
  * @private
  */
 export function _setMinAndMaxByKey(array, target, property) {
-       let i, ilen, value;
-
-       for (i = 0, ilen = array.length; i < ilen; i++) {
-               value = array[i][property];
-               if (!isNaN(value)) {
-                       target.min = Math.min(target.min, value);
-                       target.max = Math.max(target.max, value);
-               }
-       }
+  let i, ilen, value;
+
+  for (i = 0, ilen = array.length; i < ilen; i++) {
+    value = array[i][property];
+    if (!isNaN(value)) {
+      target.min = Math.min(target.min, value);
+      target.max = Math.max(target.max, value);
+    }
+  }
 }
 
 export const sign = Math.sign ?
-       function(x) {
-               return Math.sign(x);
-       } :
-       function(x) {
-               x = +x; // convert to a number
-               if (x === 0 || isNaN(x)) {
-                       return x;
-               }
-               return x > 0 ? 1 : -1;
-       };
+  function(x) {
+    return Math.sign(x);
+  } :
+  function(x) {
+    x = +x; // convert to a number
+    if (x === 0 || isNaN(x)) {
+      return x;
+    }
+    return x > 0 ? 1 : -1;
+  };
 
 export function toRadians(degrees) {
-       return degrees * (PI / 180);
+  return degrees * (PI / 180);
 }
 
 export function toDegrees(radians) {
-       return radians * (180 / PI);
+  return radians * (180 / PI);
 }
 
 /**
@@ -103,38 +103,38 @@ export function toDegrees(radians) {
  * @private
  */
 export function _decimalPlaces(x) {
-       if (!isFiniteNumber(x)) {
-               return;
-       }
-       let e = 1;
-       let p = 0;
-       while (Math.round(x * e) / e !== x) {
-               e *= 10;
-               p++;
-       }
-       return p;
+  if (!isFiniteNumber(x)) {
+    return;
+  }
+  let e = 1;
+  let p = 0;
+  while (Math.round(x * e) / e !== x) {
+    e *= 10;
+    p++;
+  }
+  return p;
 }
 
 // Gets the angle from vertical upright to the point about a centre.
 export function getAngleFromPoint(centrePoint, anglePoint) {
-       const distanceFromXCenter = anglePoint.x - centrePoint.x;
-       const distanceFromYCenter = anglePoint.y - centrePoint.y;
-       const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
+  const distanceFromXCenter = anglePoint.x - centrePoint.x;
+  const distanceFromYCenter = anglePoint.y - centrePoint.y;
+  const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
 
-       let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
+  let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
 
-       if (angle < (-0.5 * PI)) {
-               angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
-       }
+  if (angle < (-0.5 * PI)) {
+    angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
+  }
 
-       return {
-               angle,
-               distance: radialDistanceFromCenter
-       };
+  return {
+    angle,
+    distance: radialDistanceFromCenter
+  };
 }
 
 export function distanceBetweenPoints(pt1, pt2) {
-       return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
+  return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
 }
 
 /**
@@ -142,7 +142,7 @@ export function distanceBetweenPoints(pt1, pt2) {
  * @private
  */
 export function _angleDiff(a, b) {
-       return (a - b + PITAU) % TAU - PI;
+  return (a - b + PITAU) % TAU - PI;
 }
 
 /**
@@ -150,21 +150,21 @@ export function _angleDiff(a, b) {
  * @private
  */
 export function _normalizeAngle(a) {
-       return (a % TAU + TAU) % TAU;
+  return (a % TAU + TAU) % TAU;
 }
 
 /**
  * @private
  */
 export function _angleBetween(angle, start, end) {
-       const a = _normalizeAngle(angle);
-       const s = _normalizeAngle(start);
-       const e = _normalizeAngle(end);
-       const angleToStart = _normalizeAngle(s - a);
-       const angleToEnd = _normalizeAngle(e - a);
-       const startToAngle = _normalizeAngle(a - s);
-       const endToAngle = _normalizeAngle(a - e);
-       return a === s || a === e || (angleToStart > angleToEnd && startToAngle < endToAngle);
+  const a = _normalizeAngle(angle);
+  const s = _normalizeAngle(start);
+  const e = _normalizeAngle(end);
+  const angleToStart = _normalizeAngle(s - a);
+  const angleToEnd = _normalizeAngle(e - a);
+  const startToAngle = _normalizeAngle(a - s);
+  const endToAngle = _normalizeAngle(a - e);
+  return a === s || a === e || (angleToStart > angleToEnd && startToAngle < endToAngle);
 }
 
 /**
@@ -175,9 +175,9 @@ export function _angleBetween(angle, start, end) {
  * @private
  */
 export function _limitValue(value, min, max) {
-       return Math.max(min, Math.min(max, value));
+  return Math.max(min, Math.min(max, value));
 }
 
 export function _int16Range(value) {
-       return _limitValue(value, -32768, 32767);
+  return _limitValue(value, -32768, 32767);
 }
index 2b01d518e98ba62bc66e4749769c37981733ea12..604c09603ab7601c2707b0d91833d771b1b920dd 100644 (file)
@@ -17,24 +17,24 @@ const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
  * @since 2.7.0
  */
 export function toLineHeight(value, size) {
-       const matches = ('' + value).match(LINE_HEIGHT);
-       if (!matches || matches[1] === 'normal') {
-               return size * 1.2;
-       }
-
-       value = +matches[2];
-
-       switch (matches[3]) {
-       case 'px':
-               return value;
-       case '%':
-               value /= 100;
-               break;
-       default:
-               break;
-       }
-
-       return size * value;
+  const matches = ('' + value).match(LINE_HEIGHT);
+  if (!matches || matches[1] === 'normal') {
+    return size * 1.2;
+  }
+
+  value = +matches[2];
+
+  switch (matches[3]) {
+  case 'px':
+    return value;
+  case '%':
+    value /= 100;
+    break;
+  default:
+    break;
+  }
+
+  return size * value;
 }
 
 const numberOrZero = v => +v || 0;
@@ -47,23 +47,23 @@ const numberOrZero = v => +v || 0;
  * @since 3.0.0
  */
 export function toTRBL(value) {
-       let t, r, b, l;
-
-       if (isObject(value)) {
-               t = numberOrZero(value.top);
-               r = numberOrZero(value.right);
-               b = numberOrZero(value.bottom);
-               l = numberOrZero(value.left);
-       } else {
-               t = r = b = l = numberOrZero(value);
-       }
-
-       return {
-               top: t,
-               right: r,
-               bottom: b,
-               left: l
-       };
+  let t, r, b, l;
+
+  if (isObject(value)) {
+    t = numberOrZero(value.top);
+    r = numberOrZero(value.right);
+    b = numberOrZero(value.bottom);
+    l = numberOrZero(value.left);
+  } else {
+    t = r = b = l = numberOrZero(value);
+  }
+
+  return {
+    top: t,
+    right: r,
+    bottom: b,
+    left: l
+  };
 }
 
 /**
@@ -74,23 +74,23 @@ export function toTRBL(value) {
  * @since 3.0.0
  */
 export function toTRBLCorners(value) {
-       let tl, tr, bl, br;
-
-       if (isObject(value)) {
-               tl = numberOrZero(value.topLeft);
-               tr = numberOrZero(value.topRight);
-               bl = numberOrZero(value.bottomLeft);
-               br = numberOrZero(value.bottomRight);
-       } else {
-               tl = tr = bl = br = numberOrZero(value);
-       }
-
-       return {
-               topLeft: tl,
-               topRight: tr,
-               bottomLeft: bl,
-               bottomRight: br
-       };
+  let tl, tr, bl, br;
+
+  if (isObject(value)) {
+    tl = numberOrZero(value.topLeft);
+    tr = numberOrZero(value.topRight);
+    bl = numberOrZero(value.bottomLeft);
+    br = numberOrZero(value.bottomRight);
+  } else {
+    tl = tr = bl = br = numberOrZero(value);
+  }
+
+  return {
+    topLeft: tl,
+    topRight: tr,
+    bottomLeft: bl,
+    bottomRight: br
+  };
 }
 
 /**
@@ -101,12 +101,12 @@ export function toTRBLCorners(value) {
  * @since 2.7.0
  */
 export function toPadding(value) {
-       const obj = toTRBL(value);
+  const obj = toTRBL(value);
 
-       obj.width = obj.left + obj.right;
-       obj.height = obj.top + obj.bottom;
+  obj.width = obj.left + obj.right;
+  obj.height = obj.top + obj.bottom;
 
-       return obj;
+  return obj;
 }
 
 /**
@@ -117,26 +117,26 @@ export function toPadding(value) {
  * @private
  */
 export function toFont(options, fallback) {
-       options = options || {};
-       fallback = fallback || defaults.font;
-
-       let size = valueOrDefault(options.size, fallback.size);
-
-       if (typeof size === 'string') {
-               size = parseInt(size, 10);
-       }
-
-       const font = {
-               family: valueOrDefault(options.family, fallback.family),
-               lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
-               size,
-               style: valueOrDefault(options.style, fallback.style),
-               weight: valueOrDefault(options.weight, fallback.weight),
-               string: ''
-       };
-
-       font.string = toFontString(font);
-       return font;
+  options = options || {};
+  fallback = fallback || defaults.font;
+
+  let size = valueOrDefault(options.size, fallback.size);
+
+  if (typeof size === 'string') {
+    size = parseInt(size, 10);
+  }
+
+  const font = {
+    family: valueOrDefault(options.family, fallback.family),
+    lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
+    size,
+    style: valueOrDefault(options.style, fallback.style),
+    weight: valueOrDefault(options.weight, fallback.weight),
+    string: ''
+  };
+
+  font.string = toFontString(font);
+  return font;
 }
 
 /**
@@ -151,27 +151,27 @@ export function toFont(options, fallback) {
  * @since 2.7.0
  */
 export function resolve(inputs, context, index, info) {
-       let cacheable = true;
-       let i, ilen, value;
-
-       for (i = 0, ilen = inputs.length; i < ilen; ++i) {
-               value = inputs[i];
-               if (value === undefined) {
-                       continue;
-               }
-               if (context !== undefined && typeof value === 'function') {
-                       value = value(context);
-                       cacheable = false;
-               }
-               if (index !== undefined && isArray(value)) {
-                       value = value[index % value.length];
-                       cacheable = false;
-               }
-               if (value !== undefined) {
-                       if (info && !cacheable) {
-                               info.cacheable = false;
-                       }
-                       return value;
-               }
-       }
+  let cacheable = true;
+  let i, ilen, value;
+
+  for (i = 0, ilen = inputs.length; i < ilen; ++i) {
+    value = inputs[i];
+    if (value === undefined) {
+      continue;
+    }
+    if (context !== undefined && typeof value === 'function') {
+      value = value(context);
+      cacheable = false;
+    }
+    if (index !== undefined && isArray(value)) {
+      value = value[index % value.length];
+      cacheable = false;
+    }
+    if (value !== undefined) {
+      if (info && !cacheable) {
+        info.cacheable = false;
+      }
+      return value;
+    }
+  }
 }
index 5b0d2cda61ed17476019d2812b64798b27aad053..eb11224f8cb3bc83af8c5378adb8f74361e0188b 100644 (file)
@@ -1,66 +1,66 @@
 const getRightToLeftAdapter = function(rectX, width) {
-       return {
-               x(x) {
-                       return rectX + rectX + width - x;
-               },
-               setWidth(w) {
-                       width = w;
-               },
-               textAlign(align) {
-                       if (align === 'center') {
-                               return align;
-                       }
-                       return align === 'right' ? 'left' : 'right';
-               },
-               xPlus(x, value) {
-                       return x - value;
-               },
-               leftForLtr(x, itemWidth) {
-                       return x - itemWidth;
-               },
-       };
+  return {
+    x(x) {
+      return rectX + rectX + width - x;
+    },
+    setWidth(w) {
+      width = w;
+    },
+    textAlign(align) {
+      if (align === 'center') {
+        return align;
+      }
+      return align === 'right' ? 'left' : 'right';
+    },
+    xPlus(x, value) {
+      return x - value;
+    },
+    leftForLtr(x, itemWidth) {
+      return x - itemWidth;
+    },
+  };
 };
 
 const getLeftToRightAdapter = function() {
-       return {
-               x(x) {
-                       return x;
-               },
-               setWidth(w) { // eslint-disable-line no-unused-vars
-               },
-               textAlign(align) {
-                       return align;
-               },
-               xPlus(x, value) {
-                       return x + value;
-               },
-               leftForLtr(x, _itemWidth) { // eslint-disable-line no-unused-vars
-                       return x;
-               },
-       };
+  return {
+    x(x) {
+      return x;
+    },
+    setWidth(w) { // eslint-disable-line no-unused-vars
+    },
+    textAlign(align) {
+      return align;
+    },
+    xPlus(x, value) {
+      return x + value;
+    },
+    leftForLtr(x, _itemWidth) { // eslint-disable-line no-unused-vars
+      return x;
+    },
+  };
 };
 
 export function getRtlAdapter(rtl, rectX, width) {
-       return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
+  return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
 }
 
 export function overrideTextDirection(ctx, direction) {
-       let style, original;
-       if (direction === 'ltr' || direction === 'rtl') {
-               style = ctx.canvas.style;
-               original = [
-                       style.getPropertyValue('direction'),
-                       style.getPropertyPriority('direction'),
-               ];
+  let style, original;
+  if (direction === 'ltr' || direction === 'rtl') {
+    style = ctx.canvas.style;
+    original = [
+      style.getPropertyValue('direction'),
+      style.getPropertyPriority('direction'),
+    ];
 
-               style.setProperty('direction', direction, 'important');
-               ctx.prevTextDirection = original;
-       }
+    style.setProperty('direction', direction, 'important');
+    ctx.prevTextDirection = original;
+  }
 }
 
 export function restoreTextDirection(ctx, original) {
-       if (original !== undefined) {
-               delete ctx.prevTextDirection;
-               ctx.canvas.style.setProperty('direction', original[0], original[1]);
-       }
+  if (original !== undefined) {
+    delete ctx.prevTextDirection;
+    ctx.canvas.style.setProperty('direction', original[0], original[1]);
+  }
 }
index 632c1e9d73991d995fa5588e764fc24db9bb1dc0..9a3ce5ec84b988fd6b860d1a4454f04505443a0b 100644 (file)
@@ -6,54 +6,54 @@ import {_angleBetween, _angleDiff, _normalizeAngle} from './helpers.math';
  */
 
 function propertyFn(property) {
-       if (property === 'angle') {
-               return {
-                       between: _angleBetween,
-                       compare: _angleDiff,
-                       normalize: _normalizeAngle,
-               };
-       }
-       return {
-               between: (n, s, e) => n >= s && n <= e,
-               compare: (a, b) => a - b,
-               normalize: x => x
-       };
+  if (property === 'angle') {
+    return {
+      between: _angleBetween,
+      compare: _angleDiff,
+      normalize: _normalizeAngle,
+    };
+  }
+  return {
+    between: (n, s, e) => n >= s && n <= e,
+    compare: (a, b) => a - b,
+    normalize: x => x
+  };
 }
 
 function makeSubSegment(start, end, loop, count) {
-       return {
-               start: start % count,
-               end: end % count,
-               loop: loop && (end - start + 1) % count === 0
-       };
+  return {
+    start: start % count,
+    end: end % count,
+    loop: loop && (end - start + 1) % count === 0
+  };
 }
 
 function getSegment(segment, points, bounds) {
-       const {property, start: startBound, end: endBound} = bounds;
-       const {between, normalize} = propertyFn(property);
-       const count = points.length;
-       // eslint-disable-next-line prefer-const
-       let {start, end, loop} = segment;
-       let i, ilen;
-
-       if (loop) {
-               start += count;
-               end += count;
-               for (i = 0, ilen = count; i < ilen; ++i) {
-                       if (!between(normalize(points[start % count][property]), startBound, endBound)) {
-                               break;
-                       }
-                       start--;
-                       end--;
-               }
-               start %= count;
-               end %= count;
-       }
-
-       if (end < start) {
-               end += count;
-       }
-       return {start, end, loop};
+  const {property, start: startBound, end: endBound} = bounds;
+  const {between, normalize} = propertyFn(property);
+  const count = points.length;
+  // eslint-disable-next-line prefer-const
+  let {start, end, loop} = segment;
+  let i, ilen;
+
+  if (loop) {
+    start += count;
+    end += count;
+    for (i = 0, ilen = count; i < ilen; ++i) {
+      if (!between(normalize(points[start % count][property]), startBound, endBound)) {
+        break;
+      }
+      start--;
+      end--;
+    }
+    start %= count;
+    end %= count;
+  }
+
+  if (end < start) {
+    end += count;
+  }
+  return {start, end, loop};
 }
 
 /**
@@ -70,52 +70,52 @@ function getSegment(segment, points, bounds) {
  * @private
  **/
 export function _boundSegment(segment, points, bounds) {
-       if (!bounds) {
-               return [segment];
-       }
-
-       const {property, start: startBound, end: endBound} = bounds;
-       const count = points.length;
-       const {compare, between, normalize} = propertyFn(property);
-       const {start, end, loop} = getSegment(segment, points, bounds);
-
-       const result = [];
-       let inside = false;
-       let subStart = null;
-       let value, point, prevValue;
-
-       const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
-       const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value);
-       const shouldStart = () => inside || startIsBefore();
-       const shouldStop = () => !inside || endIsBefore();
-
-       for (let i = start, prev = start; i <= end; ++i) {
-               point = points[i % count];
-
-               if (point.skip) {
-                       continue;
-               }
-
-               value = normalize(point[property]);
-               inside = between(value, startBound, endBound);
-
-               if (subStart === null && shouldStart()) {
-                       subStart = compare(value, startBound) === 0 ? i : prev;
-               }
-
-               if (subStart !== null && shouldStop()) {
-                       result.push(makeSubSegment(subStart, i, loop, count));
-                       subStart = null;
-               }
-               prev = i;
-               prevValue = value;
-       }
-
-       if (subStart !== null) {
-               result.push(makeSubSegment(subStart, end, loop, count));
-       }
-
-       return result;
+  if (!bounds) {
+    return [segment];
+  }
+
+  const {property, start: startBound, end: endBound} = bounds;
+  const count = points.length;
+  const {compare, between, normalize} = propertyFn(property);
+  const {start, end, loop} = getSegment(segment, points, bounds);
+
+  const result = [];
+  let inside = false;
+  let subStart = null;
+  let value, point, prevValue;
+
+  const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
+  const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value);
+  const shouldStart = () => inside || startIsBefore();
+  const shouldStop = () => !inside || endIsBefore();
+
+  for (let i = start, prev = start; i <= end; ++i) {
+    point = points[i % count];
+
+    if (point.skip) {
+      continue;
+    }
+
+    value = normalize(point[property]);
+    inside = between(value, startBound, endBound);
+
+    if (subStart === null && shouldStart()) {
+      subStart = compare(value, startBound) === 0 ? i : prev;
+    }
+
+    if (subStart !== null && shouldStop()) {
+      result.push(makeSubSegment(subStart, i, loop, count));
+      subStart = null;
+    }
+    prev = i;
+    prevValue = value;
+  }
+
+  if (subStart !== null) {
+    result.push(makeSubSegment(subStart, end, loop, count));
+  }
+
+  return result;
 }
 
 
@@ -129,53 +129,53 @@ export function _boundSegment(segment, points, bounds) {
  * @private
  */
 export function _boundSegments(line, bounds) {
-       const result = [];
-       const segments = line.segments;
-
-       for (let i = 0; i < segments.length; i++) {
-               const sub = _boundSegment(segments[i], line.points, bounds);
-               if (sub.length) {
-                       result.push(...sub);
-               }
-       }
-       return result;
+  const result = [];
+  const segments = line.segments;
+
+  for (let i = 0; i < segments.length; i++) {
+    const sub = _boundSegment(segments[i], line.points, bounds);
+    if (sub.length) {
+      result.push(...sub);
+    }
+  }
+  return result;
 }
 
 /**
  * Find start and end index of a line.
  */
 function findStartAndEnd(points, count, loop, spanGaps) {
-       let start = 0;
-       let end = count - 1;
+  let start = 0;
+  let end = count - 1;
 
-       if (loop && !spanGaps) {
-               // loop and not spaning gaps, first find a gap to start from
-               while (start < count && !points[start].skip) {
-                       start++;
-               }
-       }
+  if (loop && !spanGaps) {
+    // loop and not spaning gaps, first find a gap to start from
+    while (start < count && !points[start].skip) {
+      start++;
+    }
+  }
 
-       // find first non skipped point (after the first gap possibly)
-       while (start < count && points[start].skip) {
-               start++;
-       }
+  // find first non skipped point (after the first gap possibly)
+  while (start < count && points[start].skip) {
+    start++;
+  }
 
-       // if we looped to count, start needs to be 0
-       start %= count;
+  // if we looped to count, start needs to be 0
+  start %= count;
 
-       if (loop) {
-               // loop will go past count, if start > 0
-               end += start;
-       }
+  if (loop) {
+    // loop will go past count, if start > 0
+    end += start;
+  }
 
-       while (end > start && points[end % count].skip) {
-               end--;
-       }
+  while (end > start && points[end % count].skip) {
+    end--;
+  }
 
-       // end could be more than count, normalize
-       end %= count;
+  // end could be more than count, normalize
+  end %= count;
 
-       return {start, end};
+  return {start, end};
 }
 
 /**
@@ -186,35 +186,35 @@ function findStartAndEnd(points, count, loop, spanGaps) {
  * @param {boolean} loop - boolean indicating that this would be a loop if no gaps are found
  */
 function solidSegments(points, start, max, loop) {
-       const count = points.length;
-       const result = [];
-       let last = start;
-       let prev = points[start];
-       let end;
-
-       for (end = start + 1; end <= max; ++end) {
-               const cur = points[end % count];
-               if (cur.skip || cur.stop) {
-                       if (!prev.skip) {
-                               loop = false;
-                               result.push({start: start % count, end: (end - 1) % count, loop});
-                               // @ts-ignore
-                               start = last = cur.stop ? end : null;
-                       }
-               } else {
-                       last = end;
-                       if (prev.skip) {
-                               start = end;
-                       }
-               }
-               prev = cur;
-       }
-
-       if (last !== null) {
-               result.push({start: start % count, end: last % count, loop});
-       }
-
-       return result;
+  const count = points.length;
+  const result = [];
+  let last = start;
+  let prev = points[start];
+  let end;
+
+  for (end = start + 1; end <= max; ++end) {
+    const cur = points[end % count];
+    if (cur.skip || cur.stop) {
+      if (!prev.skip) {
+        loop = false;
+        result.push({start: start % count, end: (end - 1) % count, loop});
+        // @ts-ignore
+        start = last = cur.stop ? end : null;
+      }
+    } else {
+      last = end;
+      if (prev.skip) {
+        start = end;
+      }
+    }
+    prev = cur;
+  }
+
+  if (last !== null) {
+    result.push({start: start % count, end: last % count, loop});
+  }
+
+  return result;
 }
 
 /**
@@ -224,22 +224,22 @@ function solidSegments(points, start, max, loop) {
  * @private
  */
 export function _computeSegments(line) {
-       const points = line.points;
-       const spanGaps = line.options.spanGaps;
-       const count = points.length;
+  const points = line.points;
+  const spanGaps = line.options.spanGaps;
+  const count = points.length;
 
-       if (!count) {
-               return [];
-       }
+  if (!count) {
+    return [];
+  }
 
-       const loop = !!line._loop;
-       const {start, end} = findStartAndEnd(points, count, loop, spanGaps);
+  const loop = !!line._loop;
+  const {start, end} = findStartAndEnd(points, count, loop, spanGaps);
 
-       if (spanGaps === true) {
-               return [{start, end, loop}];
-       }
+  if (spanGaps === true) {
+    return [{start, end, loop}];
+  }
 
-       const max = end < start ? end + count : end;
-       const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
-       return solidSegments(points, start, max, completeLoop);
+  const max = end < start ? end + count : end;
+  const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
+  return solidSegments(points, start, max, completeLoop);
 }
index 6bc2f2f93d0bfddc94b2dfeb0a113fb57b1c968a..d3539015bf2ae5621a3163e5a3521adc5fb80293 100644 (file)
@@ -46,7 +46,7 @@ Object.assign(Chart, controllers, scales, elements, plugins, platforms);
 Chart.Chart = Chart;
 
 if (typeof window !== 'undefined') {
-       window.Chart = Chart;
+  window.Chart = Chart;
 }
 
 export default Chart;
index d17731a78e6556086627015babd3e7ca890b0d2a..5b5851ebab70a1ff97991dfde8c685f9ff71b4c4 100644 (file)
@@ -7,71 +7,71 @@
  * Abstract class that allows abstracting platform dependencies away from the chart.
  */
 export default class BasePlatform {
-       /**
+  /**
         * Called at chart construction time, returns a context2d instance implementing
         * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
         * @param {HTMLCanvasElement} canvas - The canvas from which to acquire context (platform specific)
         * @param {object} options - The chart options
         */
-       acquireContext(canvas, options) {} // eslint-disable-line no-unused-vars
+  acquireContext(canvas, options) {} // eslint-disable-line no-unused-vars
 
-       /**
+  /**
         * Called at chart destruction time, releases any resources associated to the context
         * previously returned by the acquireContext() method.
         * @param {CanvasRenderingContext2D} context - The context2d instance
         * @returns {boolean} true if the method succeeded, else false
         */
-       releaseContext(context) { // eslint-disable-line no-unused-vars
-               return false;
-       }
+  releaseContext(context) { // eslint-disable-line no-unused-vars
+    return false;
+  }
 
-       /**
+  /**
         * Registers the specified listener on the given chart.
         * @param {Chart} chart - Chart from which to listen for event
         * @param {string} type - The ({@link ChartEvent}) type to listen for
         * @param {function} listener - Receives a notification (an object that implements
         * the {@link ChartEvent} interface) when an event of the specified type occurs.
         */
-       addEventListener(chart, type, listener) {} // eslint-disable-line no-unused-vars
+  addEventListener(chart, type, listener) {} // eslint-disable-line no-unused-vars
 
-       /**
+  /**
         * Removes the specified listener previously registered with addEventListener.
         * @param {Chart} chart - Chart from which to remove the listener
         * @param {string} type - The ({@link ChartEvent}) type to remove
         * @param {function} listener - The listener function to remove from the event target.
         */
-       removeEventListener(chart, type, listener) {} // eslint-disable-line no-unused-vars
+  removeEventListener(chart, type, listener) {} // eslint-disable-line no-unused-vars
 
-       /**
+  /**
         * @returns {number} the current devicePixelRatio of the device this platform is connected to.
         */
-       getDevicePixelRatio() {
-               return 1;
-       }
+  getDevicePixelRatio() {
+    return 1;
+  }
 
-       /**
+  /**
         * Returns the maximum size in pixels of given canvas element.
         * @param {HTMLCanvasElement} element
         * @param {number} [width] - content width of parent element
         * @param {number} [height] - content height of parent element
         * @param {number} [aspectRatio] - aspect ratio to maintain
         */
-       getMaximumSize(element, width, height, aspectRatio) {
-               width = Math.max(0, width || element.width);
-               height = height || element.height;
-               return {
-                       width,
-                       height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
-               };
-       }
+  getMaximumSize(element, width, height, aspectRatio) {
+    width = Math.max(0, width || element.width);
+    height = height || element.height;
+    return {
+      width,
+      height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
+    };
+  }
 
-       /**
+  /**
         * @param {HTMLCanvasElement} canvas
         * @returns {boolean} true if the canvas is attached to the platform, false if not.
         */
-       isAttached(canvas) { // eslint-disable-line no-unused-vars
-               return true;
-       }
+  isAttached(canvas) { // eslint-disable-line no-unused-vars
+    return true;
+  }
 }
 
 /**
index 681dc7a5157ab72aaeaef3a9638f52dac2f187cb..7b38caf4a190a862258d463d66add449e7d588c3 100644 (file)
@@ -11,10 +11,10 @@ import BasePlatform from './platform.base';
  * @extends BasePlatform
  */
 export default class BasicPlatform extends BasePlatform {
-       acquireContext(item) {
-               // To prevent canvas fingerprinting, some add-ons undefine the getContext
-               // method, for example: https://github.com/kkapsner/CanvasBlocker
-               // https://github.com/chartjs/Chart.js/issues/2807
-               return item && item.getContext && item.getContext('2d') || null;
-       }
+  acquireContext(item) {
+    // To prevent canvas fingerprinting, some add-ons undefine the getContext
+    // method, for example: https://github.com/kkapsner/CanvasBlocker
+    // https://github.com/chartjs/Chart.js/issues/2807
+    return item && item.getContext && item.getContext('2d') || null;
+  }
 }
index 24068924fefa259baf91315c0ae6bea088090692..1b6fb13f7e35fba9016f41b78d6913a984358e01 100644 (file)
@@ -19,15 +19,15 @@ const EXPANDO_KEY = '$chartjs';
  * @see https://developer.mozilla.org/en-US/docs/Web/Events
  */
 const EVENT_TYPES = {
-       touchstart: 'mousedown',
-       touchmove: 'mousemove',
-       touchend: 'mouseup',
-       pointerenter: 'mouseenter',
-       pointerdown: 'mousedown',
-       pointermove: 'mousemove',
-       pointerup: 'mouseup',
-       pointerleave: 'mouseout',
-       pointerout: 'mouseout'
+  touchstart: 'mousedown',
+  touchmove: 'mousemove',
+  touchend: 'mouseup',
+  pointerenter: 'mouseenter',
+  pointerdown: 'mousedown',
+  pointermove: 'mousemove',
+  pointerup: 'mouseup',
+  pointerleave: 'mouseout',
+  pointerout: 'mouseout'
 };
 
 const isNullOrEmpty = value => value === null || value === '';
@@ -39,55 +39,55 @@ const isNullOrEmpty = value => value === null || value === '';
  * @param {{ options: any; }} config
  */
 function initCanvas(canvas, config) {
-       const style = canvas.style;
-
-       // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
-       // returns null or '' if no explicit value has been set to the canvas attribute.
-       const renderHeight = canvas.getAttribute('height');
-       const renderWidth = canvas.getAttribute('width');
-
-       // Chart.js modifies some canvas values that we want to restore on destroy
-       canvas[EXPANDO_KEY] = {
-               initial: {
-                       height: renderHeight,
-                       width: renderWidth,
-                       style: {
-                               display: style.display,
-                               height: style.height,
-                               width: style.width
-                       }
-               }
-       };
-
-       // Force canvas to display as block to avoid extra space caused by inline
-       // elements, which would interfere with the responsive resize process.
-       // https://github.com/chartjs/Chart.js/issues/2538
-       style.display = style.display || 'block';
-       // Include possible borders in the size
-       style.boxSizing = style.boxSizing || 'border-box';
-
-       if (isNullOrEmpty(renderWidth)) {
-               const displayWidth = readUsedSize(canvas, 'width');
-               if (displayWidth !== undefined) {
-                       canvas.width = displayWidth;
-               }
-       }
-
-       if (isNullOrEmpty(renderHeight)) {
-               if (canvas.style.height === '') {
-                       // If no explicit render height and style height, let's apply the aspect ratio,
-                       // which one can be specified by the user but also by charts as default option
-                       // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
-                       canvas.height = canvas.width / (config.options.aspectRatio || 2);
-               } else {
-                       const displayHeight = readUsedSize(canvas, 'height');
-                       if (displayHeight !== undefined) {
-                               canvas.height = displayHeight;
-                       }
-               }
-       }
-
-       return canvas;
+  const style = canvas.style;
+
+  // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
+  // returns null or '' if no explicit value has been set to the canvas attribute.
+  const renderHeight = canvas.getAttribute('height');
+  const renderWidth = canvas.getAttribute('width');
+
+  // Chart.js modifies some canvas values that we want to restore on destroy
+  canvas[EXPANDO_KEY] = {
+    initial: {
+      height: renderHeight,
+      width: renderWidth,
+      style: {
+        display: style.display,
+        height: style.height,
+        width: style.width
+      }
+    }
+  };
+
+  // Force canvas to display as block to avoid extra space caused by inline
+  // elements, which would interfere with the responsive resize process.
+  // https://github.com/chartjs/Chart.js/issues/2538
+  style.display = style.display || 'block';
+  // Include possible borders in the size
+  style.boxSizing = style.boxSizing || 'border-box';
+
+  if (isNullOrEmpty(renderWidth)) {
+    const displayWidth = readUsedSize(canvas, 'width');
+    if (displayWidth !== undefined) {
+      canvas.width = displayWidth;
+    }
+  }
+
+  if (isNullOrEmpty(renderHeight)) {
+    if (canvas.style.height === '') {
+      // If no explicit render height and style height, let's apply the aspect ratio,
+      // which one can be specified by the user but also by charts as default option
+      // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
+      canvas.height = canvas.width / (config.options.aspectRatio || 2);
+    } else {
+      const displayHeight = readUsedSize(canvas, 'height');
+      if (displayHeight !== undefined) {
+        canvas.height = displayHeight;
+      }
+    }
+  }
+
+  return canvas;
 }
 
 // Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
@@ -95,160 +95,160 @@ function initCanvas(canvas, config) {
 const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
 
 function addListener(node, type, listener) {
-       node.addEventListener(type, listener, eventListenerOptions);
+  node.addEventListener(type, listener, eventListenerOptions);
 }
 
 function removeListener(chart, type, listener) {
-       chart.canvas.removeEventListener(type, listener, eventListenerOptions);
+  chart.canvas.removeEventListener(type, listener, eventListenerOptions);
 }
 
 function fromNativeEvent(event, chart) {
-       const type = EVENT_TYPES[event.type] || event.type;
-       const {x, y} = getRelativePosition(event, chart);
-       return {
-               type,
-               chart,
-               native: event,
-               x: x !== undefined ? x : null,
-               y: y !== undefined ? y : null,
-       };
+  const type = EVENT_TYPES[event.type] || event.type;
+  const {x, y} = getRelativePosition(event, chart);
+  return {
+    type,
+    chart,
+    native: event,
+    x: x !== undefined ? x : null,
+    y: y !== undefined ? y : null,
+  };
 }
 
 function createAttachObserver(chart, type, listener) {
-       const canvas = chart.canvas;
-       const container = canvas && _getParentNode(canvas);
-       const element = container || canvas;
-       const observer = new MutationObserver(entries => {
-               const parent = _getParentNode(element);
-               entries.forEach(entry => {
-                       for (let i = 0; i < entry.addedNodes.length; i++) {
-                               const added = entry.addedNodes[i];
-                               if (added === element || added === parent) {
-                                       listener(entry.target);
-                               }
-                       }
-               });
-       });
-       observer.observe(document, {childList: true, subtree: true});
-       return observer;
+  const canvas = chart.canvas;
+  const container = canvas && _getParentNode(canvas);
+  const element = container || canvas;
+  const observer = new MutationObserver(entries => {
+    const parent = _getParentNode(element);
+    entries.forEach(entry => {
+      for (let i = 0; i < entry.addedNodes.length; i++) {
+        const added = entry.addedNodes[i];
+        if (added === element || added === parent) {
+          listener(entry.target);
+        }
+      }
+    });
+  });
+  observer.observe(document, {childList: true, subtree: true});
+  return observer;
 }
 
 function createDetachObserver(chart, type, listener) {
-       const canvas = chart.canvas;
-       const container = canvas && _getParentNode(canvas);
-       if (!container) {
-               return;
-       }
-       const observer = new MutationObserver(entries => {
-               entries.forEach(entry => {
-                       for (let i = 0; i < entry.removedNodes.length; i++) {
-                               if (entry.removedNodes[i] === canvas) {
-                                       listener();
-                                       break;
-                               }
-                       }
-               });
-       });
-       observer.observe(container, {childList: true});
-       return observer;
+  const canvas = chart.canvas;
+  const container = canvas && _getParentNode(canvas);
+  if (!container) {
+    return;
+  }
+  const observer = new MutationObserver(entries => {
+    entries.forEach(entry => {
+      for (let i = 0; i < entry.removedNodes.length; i++) {
+        if (entry.removedNodes[i] === canvas) {
+          listener();
+          break;
+        }
+      }
+    });
+  });
+  observer.observe(container, {childList: true});
+  return observer;
 }
 
 const drpListeningCharts = new Map();
 let oldDevicePixelRatio = 0;
 
 function onWindowResize() {
-       const dpr = window.devicePixelRatio;
-       if (dpr === oldDevicePixelRatio) {
-               return;
-       }
-       oldDevicePixelRatio = dpr;
-       drpListeningCharts.forEach((resize, chart) => {
-               if (chart.currentDevicePixelRatio !== dpr) {
-                       resize();
-               }
-       });
+  const dpr = window.devicePixelRatio;
+  if (dpr === oldDevicePixelRatio) {
+    return;
+  }
+  oldDevicePixelRatio = dpr;
+  drpListeningCharts.forEach((resize, chart) => {
+    if (chart.currentDevicePixelRatio !== dpr) {
+      resize();
+    }
+  });
 }
 
 function listenDevicePixelRatioChanges(chart, resize) {
-       if (!drpListeningCharts.size) {
-               window.addEventListener('resize', onWindowResize);
-       }
-       drpListeningCharts.set(chart, resize);
+  if (!drpListeningCharts.size) {
+    window.addEventListener('resize', onWindowResize);
+  }
+  drpListeningCharts.set(chart, resize);
 }
 
 function unlistenDevicePixelRatioChanges(chart) {
-       drpListeningCharts.delete(chart);
-       if (!drpListeningCharts.size) {
-               window.removeEventListener('resize', onWindowResize);
-       }
+  drpListeningCharts.delete(chart);
+  if (!drpListeningCharts.size) {
+    window.removeEventListener('resize', onWindowResize);
+  }
 }
 
 function createResizeObserver(chart, type, listener) {
-       const canvas = chart.canvas;
-       const container = canvas && _getParentNode(canvas);
-       if (!container) {
-               return;
-       }
-       const resize = throttled((width, height) => {
-               const w = container.clientWidth;
-               listener(width, height);
-               if (w < container.clientWidth) {
-                       // If the container size shrank during chart resize, let's assume
-                       // scrollbar appeared. So we resize again with the scrollbar visible -
-                       // effectively making chart smaller and the scrollbar hidden again.
-                       // Because we are inside `throttled`, and currently `ticking`, scroll
-                       // events are ignored during this whole 2 resize process.
-                       // If we assumed wrong and something else happened, we are resizing
-                       // twice in a frame (potential performance issue)
-                       listener();
-               }
-       }, window);
-
-       // @ts-ignore until https://github.com/microsoft/TypeScript/issues/37861 implemented
-       const observer = new ResizeObserver(entries => {
-               const entry = entries[0];
-               const width = entry.contentRect.width;
-               const height = entry.contentRect.height;
-               // When its container's display is set to 'none' the callback will be called with a
-               // size of (0, 0), which will cause the chart to lost its original height, so skip
-               // resizing in such case.
-               if (width === 0 && height === 0) {
-                       return;
-               }
-               resize(width, height);
-       });
-       observer.observe(container);
-       listenDevicePixelRatioChanges(chart, resize);
-
-       return observer;
+  const canvas = chart.canvas;
+  const container = canvas && _getParentNode(canvas);
+  if (!container) {
+    return;
+  }
+  const resize = throttled((width, height) => {
+    const w = container.clientWidth;
+    listener(width, height);
+    if (w < container.clientWidth) {
+      // If the container size shrank during chart resize, let's assume
+      // scrollbar appeared. So we resize again with the scrollbar visible -
+      // effectively making chart smaller and the scrollbar hidden again.
+      // Because we are inside `throttled`, and currently `ticking`, scroll
+      // events are ignored during this whole 2 resize process.
+      // If we assumed wrong and something else happened, we are resizing
+      // twice in a frame (potential performance issue)
+      listener();
+    }
+  }, window);
+
+  // @ts-ignore until https://github.com/microsoft/TypeScript/issues/37861 implemented
+  const observer = new ResizeObserver(entries => {
+    const entry = entries[0];
+    const width = entry.contentRect.width;
+    const height = entry.contentRect.height;
+    // When its container's display is set to 'none' the callback will be called with a
+    // size of (0, 0), which will cause the chart to lost its original height, so skip
+    // resizing in such case.
+    if (width === 0 && height === 0) {
+      return;
+    }
+    resize(width, height);
+  });
+  observer.observe(container);
+  listenDevicePixelRatioChanges(chart, resize);
+
+  return observer;
 }
 
 function releaseObserver(chart, type, observer) {
-       if (observer) {
-               observer.disconnect();
-       }
-       if (type === 'resize') {
-               unlistenDevicePixelRatioChanges(chart);
-       }
+  if (observer) {
+    observer.disconnect();
+  }
+  if (type === 'resize') {
+    unlistenDevicePixelRatioChanges(chart);
+  }
 }
 
 function createProxyAndListen(chart, type, listener) {
-       const canvas = chart.canvas;
-       const proxy = throttled((event) => {
-               // This case can occur if the chart is destroyed while waiting
-               // for the throttled function to occur. We prevent crashes by checking
-               // for a destroyed chart
-               if (chart.ctx !== null) {
-                       listener(fromNativeEvent(event, chart));
-               }
-       }, chart, (args) => {
-               const event = args[0];
-               return [event, event.offsetX, event.offsetY];
-       });
-
-       addListener(canvas, type, proxy);
-
-       return proxy;
+  const canvas = chart.canvas;
+  const proxy = throttled((event) => {
+    // This case can occur if the chart is destroyed while waiting
+    // for the throttled function to occur. We prevent crashes by checking
+    // for a destroyed chart
+    if (chart.ctx !== null) {
+      listener(fromNativeEvent(event, chart));
+    }
+  }, chart, (args) => {
+    const event = args[0];
+    return [event, event.offsetX, event.offsetY];
+  });
+
+  addListener(canvas, type, proxy);
+
+  return proxy;
 }
 
 /**
@@ -257,131 +257,131 @@ function createProxyAndListen(chart, type, listener) {
  */
 export default class DomPlatform extends BasePlatform {
 
-       /**
+  /**
         * @param {HTMLCanvasElement} canvas
         * @param {{ options: { aspectRatio?: number; }; }} config
         * @return {CanvasRenderingContext2D|null}
         */
-       acquireContext(canvas, config) {
-               // To prevent canvas fingerprinting, some add-ons undefine the getContext
-               // method, for example: https://github.com/kkapsner/CanvasBlocker
-               // https://github.com/chartjs/Chart.js/issues/2807
-               const context = canvas && canvas.getContext && canvas.getContext('2d');
-
-               // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the canvas is
-               // inside an iframe or when running in a protected environment. We could guess the
-               // types from their toString() value but let's keep things flexible and assume it's
-               // a sufficient condition if the canvas has a context2D which has canvas as `canvas`.
-               // https://github.com/chartjs/Chart.js/issues/3887
-               // https://github.com/chartjs/Chart.js/issues/4102
-               // https://github.com/chartjs/Chart.js/issues/4152
-               if (context && context.canvas === canvas) {
-                       // Load platform resources on first chart creation, to make it possible to
-                       // import the library before setting platform options.
-                       initCanvas(canvas, config);
-                       return context;
-               }
-
-               return null;
-       }
-
-       /**
+  acquireContext(canvas, config) {
+    // To prevent canvas fingerprinting, some add-ons undefine the getContext
+    // method, for example: https://github.com/kkapsner/CanvasBlocker
+    // https://github.com/chartjs/Chart.js/issues/2807
+    const context = canvas && canvas.getContext && canvas.getContext('2d');
+
+    // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the canvas is
+    // inside an iframe or when running in a protected environment. We could guess the
+    // types from their toString() value but let's keep things flexible and assume it's
+    // a sufficient condition if the canvas has a context2D which has canvas as `canvas`.
+    // https://github.com/chartjs/Chart.js/issues/3887
+    // https://github.com/chartjs/Chart.js/issues/4102
+    // https://github.com/chartjs/Chart.js/issues/4152
+    if (context && context.canvas === canvas) {
+      // Load platform resources on first chart creation, to make it possible to
+      // import the library before setting platform options.
+      initCanvas(canvas, config);
+      return context;
+    }
+
+    return null;
+  }
+
+  /**
         * @param {CanvasRenderingContext2D} context
         */
-       releaseContext(context) {
-               const canvas = context.canvas;
-               if (!canvas[EXPANDO_KEY]) {
-                       return false;
-               }
-
-               const initial = canvas[EXPANDO_KEY].initial;
-               ['height', 'width'].forEach((prop) => {
-                       const value = initial[prop];
-                       if (isNullOrUndef(value)) {
-                               canvas.removeAttribute(prop);
-                       } else {
-                               canvas.setAttribute(prop, value);
-                       }
-               });
-
-               const style = initial.style || {};
-               Object.keys(style).forEach((key) => {
-                       canvas.style[key] = style[key];
-               });
-
-               // The canvas render size might have been changed (and thus the state stack discarded),
-               // we can't use save() and restore() to restore the initial state. So make sure that at
-               // least the canvas context is reset to the default state by setting the canvas width.
-               // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
-               // eslint-disable-next-line no-self-assign
-               canvas.width = canvas.width;
-
-               delete canvas[EXPANDO_KEY];
-               return true;
-       }
-
-       /**
+  releaseContext(context) {
+    const canvas = context.canvas;
+    if (!canvas[EXPANDO_KEY]) {
+      return false;
+    }
+
+    const initial = canvas[EXPANDO_KEY].initial;
+    ['height', 'width'].forEach((prop) => {
+      const value = initial[prop];
+      if (isNullOrUndef(value)) {
+        canvas.removeAttribute(prop);
+      } else {
+        canvas.setAttribute(prop, value);
+      }
+    });
+
+    const style = initial.style || {};
+    Object.keys(style).forEach((key) => {
+      canvas.style[key] = style[key];
+    });
+
+    // The canvas render size might have been changed (and thus the state stack discarded),
+    // we can't use save() and restore() to restore the initial state. So make sure that at
+    // least the canvas context is reset to the default state by setting the canvas width.
+    // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
+    // eslint-disable-next-line no-self-assign
+    canvas.width = canvas.width;
+
+    delete canvas[EXPANDO_KEY];
+    return true;
+  }
+
+  /**
         *
         * @param {Chart} chart
         * @param {string} type
         * @param {function} listener
         */
-       addEventListener(chart, type, listener) {
-               // Can have only one listener per type, so make sure previous is removed
-               this.removeEventListener(chart, type);
-
-               const proxies = chart.$proxies || (chart.$proxies = {});
-               const handlers = {
-                       attach: createAttachObserver,
-                       detach: createDetachObserver,
-                       resize: createResizeObserver
-               };
-               const handler = handlers[type] || createProxyAndListen;
-               proxies[type] = handler(chart, type, listener);
-       }
-
-
-       /**
+  addEventListener(chart, type, listener) {
+    // Can have only one listener per type, so make sure previous is removed
+    this.removeEventListener(chart, type);
+
+    const proxies = chart.$proxies || (chart.$proxies = {});
+    const handlers = {
+      attach: createAttachObserver,
+      detach: createDetachObserver,
+      resize: createResizeObserver
+    };
+    const handler = handlers[type] || createProxyAndListen;
+    proxies[type] = handler(chart, type, listener);
+  }
+
+
+  /**
         * @param {Chart} chart
         * @param {string} type
         */
-       removeEventListener(chart, type) {
-               const proxies = chart.$proxies || (chart.$proxies = {});
-               const proxy = proxies[type];
-
-               if (!proxy) {
-                       return;
-               }
-
-               const handlers = {
-                       attach: releaseObserver,
-                       detach: releaseObserver,
-                       resize: releaseObserver
-               };
-               const handler = handlers[type] || removeListener;
-               handler(chart, type, proxy);
-               proxies[type] = undefined;
-       }
-
-       getDevicePixelRatio() {
-               return window.devicePixelRatio;
-       }
-
-       /**
+  removeEventListener(chart, type) {
+    const proxies = chart.$proxies || (chart.$proxies = {});
+    const proxy = proxies[type];
+
+    if (!proxy) {
+      return;
+    }
+
+    const handlers = {
+      attach: releaseObserver,
+      detach: releaseObserver,
+      resize: releaseObserver
+    };
+    const handler = handlers[type] || removeListener;
+    handler(chart, type, proxy);
+    proxies[type] = undefined;
+  }
+
+  getDevicePixelRatio() {
+    return window.devicePixelRatio;
+  }
+
+  /**
         * @param {HTMLCanvasElement} canvas
         * @param {number} [width] - content width of parent element
         * @param {number} [height] - content height of parent element
         * @param {number} [aspectRatio] - aspect ratio to maintain
         */
-       getMaximumSize(canvas, width, height, aspectRatio) {
-               return getMaximumSize(canvas, width, height, aspectRatio);
-       }
+  getMaximumSize(canvas, width, height, aspectRatio) {
+    return getMaximumSize(canvas, width, height, aspectRatio);
+  }
 
-       /**
+  /**
         * @param {HTMLCanvasElement} canvas
         */
-       isAttached(canvas) {
-               const container = _getParentNode(canvas);
-               return !!(container && _getParentNode(container));
-       }
+  isAttached(canvas) {
+    const container = _getParentNode(canvas);
+    return !!(container && _getParentNode(container));
+  }
 }
index 4093e36567972f51196f3ced8e911e996b6086e0..c320d2f82f5b0bfaf4792887818196640bb5fd15 100644 (file)
 import {isNullOrUndef, resolve} from '../helpers';
 
 function minMaxDecimation(data, availableWidth) {
-       let i, point, x, y, prevX, minIndex, maxIndex, minY, maxY;
-       const decimated = [];
-
-       const xMin = data[0].x;
-       const xMax = data[data.length - 1].x;
-       const dx = xMax - xMin;
-
-       for (i = 0; i < data.length; ++i) {
-               point = data[i];
-               x = (point.x - xMin) / dx * availableWidth;
-               y = point.y;
-               const truncX = x | 0;
-
-               if (truncX === prevX) {
-                       // Determine `minY` / `maxY` and `avgX` while we stay within same x-position
-                       if (y < minY) {
-                               minY = y;
-                               minIndex = i;
-                       } else if (y > maxY) {
-                               maxY = y;
-                               maxIndex = i;
-                       }
-               } else {
-                       // Push up to 4 points, 3 for the last interval and the first point for this interval
-                       if (minIndex && maxIndex) {
-                               decimated.push(data[minIndex], data[maxIndex]);
-                       }
-                       if (i > 0) {
-                               // Last point in the previous interval
-                               decimated.push(data[i - 1]);
-                       }
-                       decimated.push(point);
-                       prevX = truncX;
-                       minY = maxY = y;
-                       minIndex = maxIndex = i;
-               }
-       }
-
-       return decimated;
+  let i, point, x, y, prevX, minIndex, maxIndex, minY, maxY;
+  const decimated = [];
+
+  const xMin = data[0].x;
+  const xMax = data[data.length - 1].x;
+  const dx = xMax - xMin;
+
+  for (i = 0; i < data.length; ++i) {
+    point = data[i];
+    x = (point.x - xMin) / dx * availableWidth;
+    y = point.y;
+    const truncX = x | 0;
+
+    if (truncX === prevX) {
+      // Determine `minY` / `maxY` and `avgX` while we stay within same x-position
+      if (y < minY) {
+        minY = y;
+        minIndex = i;
+      } else if (y > maxY) {
+        maxY = y;
+        maxIndex = i;
+      }
+    } else {
+      // Push up to 4 points, 3 for the last interval and the first point for this interval
+      if (minIndex && maxIndex) {
+        decimated.push(data[minIndex], data[maxIndex]);
+      }
+      if (i > 0) {
+        // Last point in the previous interval
+        decimated.push(data[i - 1]);
+      }
+      decimated.push(point);
+      prevX = truncX;
+      minY = maxY = y;
+      minIndex = maxIndex = i;
+    }
+  }
+
+  return decimated;
 }
 
 export default {
-       id: 'decimation',
-
-       defaults: {
-               algorithm: 'min-max',
-               enabled: false,
-       },
-
-       beforeElementsUpdate: (chart, args, options) => {
-               if (!options.enabled) {
-                       return;
-               }
-
-               // Assume the entire chart is available to show a few more points than needed
-               const availableWidth = chart.width;
-
-               chart.data.datasets.forEach((dataset, datasetIndex) => {
-                       const {_data, indexAxis} = dataset;
-                       const meta = chart.getDatasetMeta(datasetIndex);
-                       const data = _data || dataset.data;
-
-                       if (resolve([indexAxis, chart.options.indexAxis]) === 'y') {
-                               // Decimation is only supported for lines that have an X indexAxis
-                               return;
-                       }
-
-                       if (meta.type !== 'line') {
-                               // Only line datasets are supported
-                               return;
-                       }
-
-                       const xAxis = chart.scales[meta.xAxisID];
-                       if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
-                               // Only linear interpolation is supported
-                               return;
-                       }
-
-                       if (chart.options.parsing) {
-                               // Plugin only supports data that does not need parsing
-                               return;
-                       }
-
-                       if (data.length <= 4 * availableWidth) {
-                               // No decimation is required until we are above this threshold
-                               return;
-                       }
-
-                       if (isNullOrUndef(_data)) {
-                               // First time we are seeing this dataset
-                               // We override the 'data' property with a setter that stores the
-                               // raw data in _data, but reads the decimated data from _decimated
-                               // TODO: Undo this on chart destruction
-                               dataset._data = data;
-                               delete dataset.data;
-                               Object.defineProperty(dataset, 'data', {
-                                       configurable: true,
-                                       enumerable: true,
-                                       get: function() {
-                                               return this._decimated;
-                                       },
-                                       set: function(d) {
-                                               this._data = d;
-                                       }
-                               });
-                       }
-
-                       // Point the chart to the decimated data
-                       let decimated;
-                       switch (options.algorithm) {
-                       case 'min-max':
-                               decimated = minMaxDecimation(data, availableWidth);
-                               break;
-                       default:
-                               throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
-                       }
-
-                       dataset._decimated = decimated;
-               });
-       },
-
-       destroy(chart) {
-               chart.data.datasets.forEach((dataset) => {
-                       if (dataset._decimated) {
-                               const data = dataset._data;
-                               delete dataset._decimated;
-                               delete dataset._data;
-                               Object.defineProperty(dataset, 'data', {value: data});
-                       }
-               });
-       }
+  id: 'decimation',
+
+  defaults: {
+    algorithm: 'min-max',
+    enabled: false,
+  },
+
+  beforeElementsUpdate: (chart, args, options) => {
+    if (!options.enabled) {
+      return;
+    }
+
+    // Assume the entire chart is available to show a few more points than needed
+    const availableWidth = chart.width;
+
+    chart.data.datasets.forEach((dataset, datasetIndex) => {
+      const {_data, indexAxis} = dataset;
+      const meta = chart.getDatasetMeta(datasetIndex);
+      const data = _data || dataset.data;
+
+      if (resolve([indexAxis, chart.options.indexAxis]) === 'y') {
+        // Decimation is only supported for lines that have an X indexAxis
+        return;
+      }
+
+      if (meta.type !== 'line') {
+        // Only line datasets are supported
+        return;
+      }
+
+      const xAxis = chart.scales[meta.xAxisID];
+      if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
+        // Only linear interpolation is supported
+        return;
+      }
+
+      if (chart.options.parsing) {
+        // Plugin only supports data that does not need parsing
+        return;
+      }
+
+      if (data.length <= 4 * availableWidth) {
+        // No decimation is required until we are above this threshold
+        return;
+      }
+
+      if (isNullOrUndef(_data)) {
+        // First time we are seeing this dataset
+        // We override the 'data' property with a setter that stores the
+        // raw data in _data, but reads the decimated data from _decimated
+        // TODO: Undo this on chart destruction
+        dataset._data = data;
+        delete dataset.data;
+        Object.defineProperty(dataset, 'data', {
+          configurable: true,
+          enumerable: true,
+          get: function() {
+            return this._decimated;
+          },
+          set: function(d) {
+            this._data = d;
+          }
+        });
+      }
+
+      // Point the chart to the decimated data
+      let decimated;
+      switch (options.algorithm) {
+      case 'min-max':
+        decimated = minMaxDecimation(data, availableWidth);
+        break;
+      default:
+        throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
+      }
+
+      dataset._decimated = decimated;
+    });
+  },
+
+  destroy(chart) {
+    chart.data.datasets.forEach((dataset) => {
+      if (dataset._decimated) {
+        const data = dataset._data;
+        delete dataset._decimated;
+        delete dataset._data;
+        Object.defineProperty(dataset, 'data', {value: data});
+      }
+    });
+  }
 };
index 572d74acdab589a74984c9be5b4fc71a4698e90e..9b725b3f2519a8408b52f08d6086e70b60924605 100644 (file)
@@ -21,31 +21,31 @@ import {TAU, _normalizeAngle} from '../helpers/helpers.math';
  * @param {number} index
  */
 function getLineByIndex(chart, index) {
-       const meta = chart.getDatasetMeta(index);
-       const visible = meta && chart.isDatasetVisible(index);
-       return visible ? meta.dataset : null;
+  const meta = chart.getDatasetMeta(index);
+  const visible = meta && chart.isDatasetVisible(index);
+  return visible ? meta.dataset : null;
 }
 
 /**
  * @param {LineElement} line
  */
 function parseFillOption(line) {
-       const options = line.options;
-       const fillOption = options.fill;
-       let fill = valueOrDefault(fillOption && fillOption.target, fillOption);
-
-       if (fill === undefined) {
-               fill = !!options.backgroundColor;
-       }
-
-       if (fill === false || fill === null) {
-               return false;
-       }
-
-       if (fill === true) {
-               return 'origin';
-       }
-       return fill;
+  const options = line.options;
+  const fillOption = options.fill;
+  let fill = valueOrDefault(fillOption && fillOption.target, fillOption);
+
+  if (fill === undefined) {
+    fill = !!options.backgroundColor;
+  }
+
+  if (fill === false || fill === null) {
+    return false;
+  }
+
+  if (fill === true) {
+    return 'origin';
+  }
+  return fill;
 }
 
 /**
@@ -54,146 +54,146 @@ function parseFillOption(line) {
  * @param {number} count
  */
 function decodeFill(line, index, count) {
-       const fill = parseFillOption(line);
+  const fill = parseFillOption(line);
 
-       if (isObject(fill)) {
-               return isNaN(fill.value) ? false : fill;
-       }
+  if (isObject(fill)) {
+    return isNaN(fill.value) ? false : fill;
+  }
 
-       let target = parseFloat(fill);
+  let target = parseFloat(fill);
 
-       if (isFinite(target) && Math.floor(target) === target) {
-               if (fill[0] === '-' || fill[0] === '+') {
-                       target = index + target;
-               }
+  if (isFinite(target) && Math.floor(target) === target) {
+    if (fill[0] === '-' || fill[0] === '+') {
+      target = index + target;
+    }
 
-               if (target === index || target < 0 || target >= count) {
-                       return false;
-               }
+    if (target === index || target < 0 || target >= count) {
+      return false;
+    }
 
-               return target;
-       }
+    return target;
+  }
 
-       return ['origin', 'start', 'end', 'stack'].indexOf(fill) >= 0 && fill;
+  return ['origin', 'start', 'end', 'stack'].indexOf(fill) >= 0 && fill;
 }
 
 function computeLinearBoundary(source) {
-       const {scale = {}, fill} = source;
-       let target = null;
-       let horizontal;
-
-       if (fill === 'start') {
-               target = scale.bottom;
-       } else if (fill === 'end') {
-               target = scale.top;
-       } else if (isObject(fill)) {
-               target = scale.getPixelForValue(fill.value);
-       } else if (scale.getBasePixel) {
-               target = scale.getBasePixel();
-       }
-
-       if (isFinite(target)) {
-               horizontal = scale.isHorizontal();
-               return {
-                       x: horizontal ? target : null,
-                       y: horizontal ? null : target
-               };
-       }
-
-       return null;
+  const {scale = {}, fill} = source;
+  let target = null;
+  let horizontal;
+
+  if (fill === 'start') {
+    target = scale.bottom;
+  } else if (fill === 'end') {
+    target = scale.top;
+  } else if (isObject(fill)) {
+    target = scale.getPixelForValue(fill.value);
+  } else if (scale.getBasePixel) {
+    target = scale.getBasePixel();
+  }
+
+  if (isFinite(target)) {
+    horizontal = scale.isHorizontal();
+    return {
+      x: horizontal ? target : null,
+      y: horizontal ? null : target
+    };
+  }
+
+  return null;
 }
 
 // TODO: use elements.ArcElement instead
 class simpleArc {
-       constructor(opts) {
-               this.x = opts.x;
-               this.y = opts.y;
-               this.radius = opts.radius;
-       }
-
-       pathSegment(ctx, bounds, opts) {
-               const {x, y, radius} = this;
-               bounds = bounds || {start: 0, end: TAU};
-               if (opts.reverse) {
-                       ctx.arc(x, y, radius, bounds.end, bounds.start, true);
-               } else {
-                       ctx.arc(x, y, radius, bounds.start, bounds.end);
-               }
-               return !opts.bounds;
-       }
-
-       interpolate(point, property) {
-               const {x, y, radius} = this;
-               const angle = point.angle;
-               if (property === 'angle') {
-                       return {
-                               x: x + Math.cos(angle) * radius,
-                               y: y + Math.sin(angle) * radius,
-                               angle
-                       };
-               }
-       }
+  constructor(opts) {
+    this.x = opts.x;
+    this.y = opts.y;
+    this.radius = opts.radius;
+  }
+
+  pathSegment(ctx, bounds, opts) {
+    const {x, y, radius} = this;
+    bounds = bounds || {start: 0, end: TAU};
+    if (opts.reverse) {
+      ctx.arc(x, y, radius, bounds.end, bounds.start, true);
+    } else {
+      ctx.arc(x, y, radius, bounds.start, bounds.end);
+    }
+    return !opts.bounds;
+  }
+
+  interpolate(point, property) {
+    const {x, y, radius} = this;
+    const angle = point.angle;
+    if (property === 'angle') {
+      return {
+        x: x + Math.cos(angle) * radius,
+        y: y + Math.sin(angle) * radius,
+        angle
+      };
+    }
+  }
 }
 
 function computeCircularBoundary(source) {
-       const {scale, fill} = source;
-       const options = scale.options;
-       const length = scale.getLabels().length;
-       const target = [];
-       const start = options.reverse ? scale.max : scale.min;
-       const end = options.reverse ? scale.min : scale.max;
-       let i, center, value;
-
-       if (fill === 'start') {
-               value = start;
-       } else if (fill === 'end') {
-               value = end;
-       } else if (isObject(fill)) {
-               value = fill.value;
-       } else {
-               value = scale.getBaseValue();
-       }
-
-       if (options.gridLines.circular) {
-               center = scale.getPointPositionForValue(0, start);
-               return new simpleArc({
-                       x: center.x,
-                       y: center.y,
-                       radius: scale.getDistanceFromCenterForValue(value)
-               });
-       }
-
-       for (i = 0; i < length; ++i) {
-               target.push(scale.getPointPositionForValue(i, value));
-       }
-       return target;
+  const {scale, fill} = source;
+  const options = scale.options;
+  const length = scale.getLabels().length;
+  const target = [];
+  const start = options.reverse ? scale.max : scale.min;
+  const end = options.reverse ? scale.min : scale.max;
+  let i, center, value;
+
+  if (fill === 'start') {
+    value = start;
+  } else if (fill === 'end') {
+    value = end;
+  } else if (isObject(fill)) {
+    value = fill.value;
+  } else {
+    value = scale.getBaseValue();
+  }
+
+  if (options.gridLines.circular) {
+    center = scale.getPointPositionForValue(0, start);
+    return new simpleArc({
+      x: center.x,
+      y: center.y,
+      radius: scale.getDistanceFromCenterForValue(value)
+    });
+  }
+
+  for (i = 0; i < length; ++i) {
+    target.push(scale.getPointPositionForValue(i, value));
+  }
+  return target;
 }
 
 function computeBoundary(source) {
-       const scale = source.scale || {};
+  const scale = source.scale || {};
 
-       if (scale.getPointPositionForValue) {
-               return computeCircularBoundary(source);
-       }
-       return computeLinearBoundary(source);
+  if (scale.getPointPositionForValue) {
+    return computeCircularBoundary(source);
+  }
+  return computeLinearBoundary(source);
 }
 
 function pointsFromSegments(boundary, line) {
-       const {x = null, y = null} = boundary || {};
-       const linePoints = line.points;
-       const points = [];
-       line.segments.forEach((segment) => {
-               const first = linePoints[segment.start];
-               const last = linePoints[segment.end];
-               if (y !== null) {
-                       points.push({x: first.x, y});
-                       points.push({x: last.x, y});
-               } else if (x !== null) {
-                       points.push({x, y: first.y});
-                       points.push({x, y: last.y});
-               }
-       });
-       return points;
+  const {x = null, y = null} = boundary || {};
+  const linePoints = line.points;
+  const points = [];
+  line.segments.forEach((segment) => {
+    const first = linePoints[segment.start];
+    const last = linePoints[segment.end];
+    if (y !== null) {
+      points.push({x: first.x, y});
+      points.push({x: last.x, y});
+    } else if (x !== null) {
+      points.push({x, y: first.y});
+      points.push({x, y: last.y});
+    }
+  });
+  return points;
 }
 
 /**
@@ -201,20 +201,20 @@ function pointsFromSegments(boundary, line) {
  * @return {LineElement}
  */
 function buildStackLine(source) {
-       const {chart, scale, index, line} = source;
-       const points = [];
-       const segments = line.segments;
-       const sourcePoints = line.points;
-       const linesBelow = getLinesBelow(chart, index);
-       linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line));
-
-       for (let i = 0; i < segments.length; i++) {
-               const segment = segments[i];
-               for (let j = segment.start; j <= segment.end; j++) {
-                       addPointsBelow(points, sourcePoints[j], linesBelow);
-               }
-       }
-       return new LineElement({points, options: {}});
+  const {chart, scale, index, line} = source;
+  const points = [];
+  const segments = line.segments;
+  const sourcePoints = line.points;
+  const linesBelow = getLinesBelow(chart, index);
+  linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line));
+
+  for (let i = 0; i < segments.length; i++) {
+    const segment = segments[i];
+    for (let j = segment.start; j <= segment.end; j++) {
+      addPointsBelow(points, sourcePoints[j], linesBelow);
+    }
+  }
+  return new LineElement({points, options: {}});
 }
 
 const isLineAndNotInHideAnimation = (meta) => meta.type === 'line' && !meta.hidden;
@@ -225,19 +225,19 @@ const isLineAndNotInHideAnimation = (meta) => meta.type === 'line' && !meta.hidd
  * @return {LineElement[]}
  */
 function getLinesBelow(chart, index) {
-       const below = [];
-       const metas = chart.getSortedVisibleDatasetMetas();
-
-       for (let i = 0; i < metas.length; i++) {
-               const meta = metas[i];
-               if (meta.index === index) {
-                       break;
-               }
-               if (isLineAndNotInHideAnimation(meta)) {
-                       below.unshift(meta.dataset);
-               }
-       }
-       return below;
+  const below = [];
+  const metas = chart.getSortedVisibleDatasetMetas();
+
+  for (let i = 0; i < metas.length; i++) {
+    const meta = metas[i];
+    if (meta.index === index) {
+      break;
+    }
+    if (isLineAndNotInHideAnimation(meta)) {
+      below.unshift(meta.dataset);
+    }
+  }
+  return below;
 }
 
 /**
@@ -246,27 +246,27 @@ function getLinesBelow(chart, index) {
  * @param {LineElement[]} linesBelow
  */
 function addPointsBelow(points, sourcePoint, linesBelow) {
-       const postponed = [];
-       for (let j = 0; j < linesBelow.length; j++) {
-               const line = linesBelow[j];
-               const {first, last, point} = findPoint(line, sourcePoint, 'x');
-
-               if (!point || (first && last)) {
-                       continue;
-               }
-               if (first) {
-                       // First point of an segment -> need to add another point before this,
-                       // from next line below.
-                       postponed.unshift(point);
-               } else {
-                       points.push(point);
-                       if (!last) {
-                               // In the middle of an segment, no need to add more points.
-                               break;
-                       }
-               }
-       }
-       points.push(...postponed);
+  const postponed = [];
+  for (let j = 0; j < linesBelow.length; j++) {
+    const line = linesBelow[j];
+    const {first, last, point} = findPoint(line, sourcePoint, 'x');
+
+    if (!point || (first && last)) {
+      continue;
+    }
+    if (first) {
+      // First point of an segment -> need to add another point before this,
+      // from next line below.
+      postponed.unshift(point);
+    } else {
+      points.push(point);
+      if (!last) {
+        // In the middle of an segment, no need to add more points.
+        break;
+      }
+    }
+  }
+  points.push(...postponed);
 }
 
 /**
@@ -276,47 +276,47 @@ function addPointsBelow(points, sourcePoint, linesBelow) {
  * @returns {{point?: PointElement, first?: boolean, last?: boolean}}
  */
 function findPoint(line, sourcePoint, property) {
-       const point = line.interpolate(sourcePoint, property);
-       if (!point) {
-               return {};
-       }
-
-       const pointValue = point[property];
-       const segments = line.segments;
-       const linePoints = line.points;
-       let first = false;
-       let last = false;
-       for (let i = 0; i < segments.length; i++) {
-               const segment = segments[i];
-               const firstValue = linePoints[segment.start][property];
-               const lastValue = linePoints[segment.end][property];
-               if (pointValue >= firstValue && pointValue <= lastValue) {
-                       first = pointValue === firstValue;
-                       last = pointValue === lastValue;
-                       break;
-               }
-       }
-       return {first, last, point};
+  const point = line.interpolate(sourcePoint, property);
+  if (!point) {
+    return {};
+  }
+
+  const pointValue = point[property];
+  const segments = line.segments;
+  const linePoints = line.points;
+  let first = false;
+  let last = false;
+  for (let i = 0; i < segments.length; i++) {
+    const segment = segments[i];
+    const firstValue = linePoints[segment.start][property];
+    const lastValue = linePoints[segment.end][property];
+    if (pointValue >= firstValue && pointValue <= lastValue) {
+      first = pointValue === firstValue;
+      last = pointValue === lastValue;
+      break;
+    }
+  }
+  return {first, last, point};
 }
 
 function getTarget(source) {
-       const {chart, fill, line} = source;
+  const {chart, fill, line} = source;
 
-       if (isFinite(fill)) {
-               return getLineByIndex(chart, fill);
-       }
+  if (isFinite(fill)) {
+    return getLineByIndex(chart, fill);
+  }
 
-       if (fill === 'stack') {
-               return buildStackLine(source);
-       }
+  if (fill === 'stack') {
+    return buildStackLine(source);
+  }
 
-       const boundary = computeBoundary(source);
+  const boundary = computeBoundary(source);
 
-       if (boundary instanceof simpleArc) {
-               return boundary;
-       }
+  if (boundary instanceof simpleArc) {
+    return boundary;
+  }
 
-       return createBoundaryLine(boundary, line);
+  return createBoundaryLine(boundary, line);
 }
 
 /**
@@ -325,279 +325,279 @@ function getTarget(source) {
  * @return {LineElement?}
  */
 function createBoundaryLine(boundary, line) {
-       let points = [];
-       let _loop = false;
-
-       if (isArray(boundary)) {
-               _loop = true;
-               // @ts-ignore
-               points = boundary;
-       } else {
-               points = pointsFromSegments(boundary, line);
-       }
-
-       return points.length ? new LineElement({
-               points,
-               options: {tension: 0},
-               _loop,
-               _fullLoop: _loop
-       }) : null;
+  let points = [];
+  let _loop = false;
+
+  if (isArray(boundary)) {
+    _loop = true;
+    // @ts-ignore
+    points = boundary;
+  } else {
+    points = pointsFromSegments(boundary, line);
+  }
+
+  return points.length ? new LineElement({
+    points,
+    options: {tension: 0},
+    _loop,
+    _fullLoop: _loop
+  }) : null;
 }
 
 function resolveTarget(sources, index, propagate) {
-       const source = sources[index];
-       let fill = source.fill;
-       const visited = [index];
-       let target;
-
-       if (!propagate) {
-               return fill;
-       }
-
-       while (fill !== false && visited.indexOf(fill) === -1) {
-               if (!isFinite(fill)) {
-                       return fill;
-               }
-
-               target = sources[fill];
-               if (!target) {
-                       return false;
-               }
-
-               if (target.visible) {
-                       return fill;
-               }
-
-               visited.push(fill);
-               fill = target.fill;
-       }
-
-       return false;
+  const source = sources[index];
+  let fill = source.fill;
+  const visited = [index];
+  let target;
+
+  if (!propagate) {
+    return fill;
+  }
+
+  while (fill !== false && visited.indexOf(fill) === -1) {
+    if (!isFinite(fill)) {
+      return fill;
+    }
+
+    target = sources[fill];
+    if (!target) {
+      return false;
+    }
+
+    if (target.visible) {
+      return fill;
+    }
+
+    visited.push(fill);
+    fill = target.fill;
+  }
+
+  return false;
 }
 
 function _clip(ctx, target, clipY) {
-       ctx.beginPath();
-       target.path(ctx);
-       ctx.lineTo(target.last().x, clipY);
-       ctx.lineTo(target.first().x, clipY);
-       ctx.closePath();
-       ctx.clip();
+  ctx.beginPath();
+  target.path(ctx);
+  ctx.lineTo(target.last().x, clipY);
+  ctx.lineTo(target.first().x, clipY);
+  ctx.closePath();
+  ctx.clip();
 }
 
 function getBounds(property, first, last, loop) {
-       if (loop) {
-               return;
-       }
-       let start = first[property];
-       let end = last[property];
-
-       if (property === 'angle') {
-               start = _normalizeAngle(start);
-               end = _normalizeAngle(end);
-       }
-       return {property, start, end};
+  if (loop) {
+    return;
+  }
+  let start = first[property];
+  let end = last[property];
+
+  if (property === 'angle') {
+    start = _normalizeAngle(start);
+    end = _normalizeAngle(end);
+  }
+  return {property, start, end};
 }
 
 function _getEdge(a, b, prop, fn) {
-       if (a && b) {
-               return fn(a[prop], b[prop]);
-       }
-       return a ? a[prop] : b ? b[prop] : 0;
+  if (a && b) {
+    return fn(a[prop], b[prop]);
+  }
+  return a ? a[prop] : b ? b[prop] : 0;
 }
 
 function _segments(line, target, property) {
-       const segments = line.segments;
-       const points = line.points;
-       const tpoints = target.points;
-       const parts = [];
-
-       for (let i = 0; i < segments.length; i++) {
-               const segment = segments[i];
-               const bounds = getBounds(property, points[segment.start], points[segment.end], segment.loop);
-
-               if (!target.segments) {
-                       // Special case for boundary not supporting `segments` (simpleArc)
-                       // Bounds are provided as `target` for partial circle, or undefined for full circle
-                       parts.push({
-                               source: segment,
-                               target: bounds,
-                               start: points[segment.start],
-                               end: points[segment.end]
-                       });
-                       continue;
-               }
-
-               // Get all segments from `target` that intersect the bounds of current segment of `line`
-               const subs = _boundSegments(target, bounds);
-
-               for (let j = 0; j < subs.length; ++j) {
-                       const sub = subs[j];
-                       const subBounds = getBounds(property, tpoints[sub.start], tpoints[sub.end], sub.loop);
-                       const fillSources = _boundSegment(segment, points, subBounds);
-
-                       for (let k = 0; k < fillSources.length; k++) {
-                               parts.push({
-                                       source: fillSources[k],
-                                       target: sub,
-                                       start: {
-                                               [property]: _getEdge(bounds, subBounds, 'start', Math.max)
-                                       },
-                                       end: {
-                                               [property]: _getEdge(bounds, subBounds, 'end', Math.min)
-                                       }
-
-                               });
-                       }
-               }
-       }
-       return parts;
+  const segments = line.segments;
+  const points = line.points;
+  const tpoints = target.points;
+  const parts = [];
+
+  for (let i = 0; i < segments.length; i++) {
+    const segment = segments[i];
+    const bounds = getBounds(property, points[segment.start], points[segment.end], segment.loop);
+
+    if (!target.segments) {
+      // Special case for boundary not supporting `segments` (simpleArc)
+      // Bounds are provided as `target` for partial circle, or undefined for full circle
+      parts.push({
+        source: segment,
+        target: bounds,
+        start: points[segment.start],
+        end: points[segment.end]
+      });
+      continue;
+    }
+
+    // Get all segments from `target` that intersect the bounds of current segment of `line`
+    const subs = _boundSegments(target, bounds);
+
+    for (let j = 0; j < subs.length; ++j) {
+      const sub = subs[j];
+      const subBounds = getBounds(property, tpoints[sub.start], tpoints[sub.end], sub.loop);
+      const fillSources = _boundSegment(segment, points, subBounds);
+
+      for (let k = 0; k < fillSources.length; k++) {
+        parts.push({
+          source: fillSources[k],
+          target: sub,
+          start: {
+            [property]: _getEdge(bounds, subBounds, 'start', Math.max)
+          },
+          end: {
+            [property]: _getEdge(bounds, subBounds, 'end', Math.min)
+          }
+
+        });
+      }
+    }
+  }
+  return parts;
 }
 
 function clipBounds(ctx, scale, bounds) {
-       const {top, bottom} = scale.chart.chartArea;
-       const {property, start, end} = bounds || {};
-       if (property === 'x') {
-               ctx.beginPath();
-               ctx.rect(start, top, end - start, bottom - top);
-               ctx.clip();
-       }
+  const {top, bottom} = scale.chart.chartArea;
+  const {property, start, end} = bounds || {};
+  if (property === 'x') {
+    ctx.beginPath();
+    ctx.rect(start, top, end - start, bottom - top);
+    ctx.clip();
+  }
 }
 
 function interpolatedLineTo(ctx, target, point, property) {
-       const interpolatedPoint = target.interpolate(point, property);
-       if (interpolatedPoint) {
-               ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
-       }
+  const interpolatedPoint = target.interpolate(point, property);
+  if (interpolatedPoint) {
+    ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
+  }
 }
 
 function _fill(ctx, cfg) {
-       const {line, target, property, color, scale} = cfg;
-       const segments = _segments(line, target, property);
+  const {line, target, property, color, scale} = cfg;
+  const segments = _segments(line, target, property);
 
-       ctx.fillStyle = color;
-       for (let i = 0, ilen = segments.length; i < ilen; ++i) {
-               const {source: src, target: tgt, start, end} = segments[i];
+  ctx.fillStyle = color;
+  for (let i = 0, ilen = segments.length; i < ilen; ++i) {
+    const {source: src, target: tgt, start, end} = segments[i];
 
-               ctx.save();
+    ctx.save();
 
-               clipBounds(ctx, scale, getBounds(property, start, end));
+    clipBounds(ctx, scale, getBounds(property, start, end));
 
-               ctx.beginPath();
+    ctx.beginPath();
 
-               const lineLoop = !!line.pathSegment(ctx, src);
-               if (lineLoop) {
-                       ctx.closePath();
-               } else {
-                       interpolatedLineTo(ctx, target, end, property);
-               }
+    const lineLoop = !!line.pathSegment(ctx, src);
+    if (lineLoop) {
+      ctx.closePath();
+    } else {
+      interpolatedLineTo(ctx, target, end, property);
+    }
 
-               const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true});
-               const loop = lineLoop && targetLoop;
-               if (!loop) {
-                       interpolatedLineTo(ctx, target, start, property);
-               }
+    const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true});
+    const loop = lineLoop && targetLoop;
+    if (!loop) {
+      interpolatedLineTo(ctx, target, start, property);
+    }
 
-               ctx.closePath();
-               ctx.fill(loop ? 'evenodd' : 'nonzero');
+    ctx.closePath();
+    ctx.fill(loop ? 'evenodd' : 'nonzero');
 
-               ctx.restore();
-       }
+    ctx.restore();
+  }
 }
 
 function doFill(ctx, cfg) {
-       const {line, target, above, below, area, scale} = cfg;
-       const property = line._loop ? 'angle' : 'x';
+  const {line, target, above, below, area, scale} = cfg;
+  const property = line._loop ? 'angle' : 'x';
 
-       ctx.save();
+  ctx.save();
 
-       if (property === 'x' && below !== above) {
-               _clip(ctx, target, area.top);
-               _fill(ctx, {line, target, color: above, scale, property});
-               ctx.restore();
-               ctx.save();
-               _clip(ctx, target, area.bottom);
-       }
-       _fill(ctx, {line, target, color: below, scale, property});
+  if (property === 'x' && below !== above) {
+    _clip(ctx, target, area.top);
+    _fill(ctx, {line, target, color: above, scale, property});
+    ctx.restore();
+    ctx.save();
+    _clip(ctx, target, area.bottom);
+  }
+  _fill(ctx, {line, target, color: below, scale, property});
 
-       ctx.restore();
+  ctx.restore();
 }
 
 export default {
-       id: 'filler',
-
-       afterDatasetsUpdate(chart, _args, options) {
-               const count = (chart.data.datasets || []).length;
-               const propagate = options.propagate;
-               const sources = [];
-               let meta, i, line, source;
-
-               for (i = 0; i < count; ++i) {
-                       meta = chart.getDatasetMeta(i);
-                       line = meta.dataset;
-                       source = null;
-
-                       if (line && line.options && line instanceof LineElement) {
-                               source = {
-                                       visible: chart.isDatasetVisible(i),
-                                       index: i,
-                                       fill: decodeFill(line, i, count),
-                                       chart,
-                                       scale: meta.vScale,
-                                       line
-                               };
-                       }
-
-                       meta.$filler = source;
-                       sources.push(source);
-               }
-
-               for (i = 0; i < count; ++i) {
-                       source = sources[i];
-                       if (!source || source.fill === false) {
-                               continue;
-                       }
-
-                       source.fill = resolveTarget(sources, i, propagate);
-               }
-       },
-
-       beforeDatasetsDraw(chart) {
-               const metasets = chart.getSortedVisibleDatasetMetas();
-               const area = chart.chartArea;
-               let i, meta;
-
-               for (i = metasets.length - 1; i >= 0; --i) {
-                       meta = metasets[i].$filler;
-
-                       if (meta) {
-                               meta.line.updateControlPoints(area);
-                       }
-               }
-       },
-
-       beforeDatasetDraw(chart, args) {
-               const area = chart.chartArea;
-               const ctx = chart.ctx;
-               const source = args.meta.$filler;
-
-               if (!source || source.fill === false) {
-                       return;
-               }
-
-               const target = getTarget(source);
-               const {line, scale} = source;
-               const lineOpts = line.options;
-               const fillOption = lineOpts.fill;
-               const color = lineOpts.backgroundColor;
-               const {above = color, below = color} = fillOption || {};
-               if (target && line.points.length) {
-                       clipArea(ctx, area);
-                       doFill(ctx, {line, target, above, below, area, scale});
-                       unclipArea(ctx);
-               }
-       },
-
-       defaults: {
-               propagate: true
-       }
+  id: 'filler',
+
+  afterDatasetsUpdate(chart, _args, options) {
+    const count = (chart.data.datasets || []).length;
+    const propagate = options.propagate;
+    const sources = [];
+    let meta, i, line, source;
+
+    for (i = 0; i < count; ++i) {
+      meta = chart.getDatasetMeta(i);
+      line = meta.dataset;
+      source = null;
+
+      if (line && line.options && line instanceof LineElement) {
+        source = {
+          visible: chart.isDatasetVisible(i),
+          index: i,
+          fill: decodeFill(line, i, count),
+          chart,
+          scale: meta.vScale,
+          line
+        };
+      }
+
+      meta.$filler = source;
+      sources.push(source);
+    }
+
+    for (i = 0; i < count; ++i) {
+      source = sources[i];
+      if (!source || source.fill === false) {
+        continue;
+      }
+
+      source.fill = resolveTarget(sources, i, propagate);
+    }
+  },
+
+  beforeDatasetsDraw(chart) {
+    const metasets = chart.getSortedVisibleDatasetMetas();
+    const area = chart.chartArea;
+    let i, meta;
+
+    for (i = metasets.length - 1; i >= 0; --i) {
+      meta = metasets[i].$filler;
+
+      if (meta) {
+        meta.line.updateControlPoints(area);
+      }
+    }
+  },
+
+  beforeDatasetDraw(chart, args) {
+    const area = chart.chartArea;
+    const ctx = chart.ctx;
+    const source = args.meta.$filler;
+
+    if (!source || source.fill === false) {
+      return;
+    }
+
+    const target = getTarget(source);
+    const {line, scale} = source;
+    const lineOpts = line.options;
+    const fillOption = lineOpts.fill;
+    const color = lineOpts.backgroundColor;
+    const {above = color, below = color} = fillOption || {};
+    if (target && line.points.length) {
+      clipArea(ctx, area);
+      doFill(ctx, {line, target, above, below, area, scale});
+      unclipArea(ctx);
+    }
+  },
+
+  defaults: {
+    propagate: true
+  }
 };
index bf32e359a6b9cdf091e035c5ede940de58f524cd..af3eaef5b32ebb4ac69c1e0350bc2d93f6c24ac8 100644 (file)
@@ -3,9 +3,9 @@ import Element from '../core/core.element';
 import layouts from '../core/core.layouts';
 import {drawPoint, renderText} from '../helpers/helpers.canvas';
 import {
-       callback as call, valueOrDefault, toFont, isObject,
-       toPadding, getRtlAdapter, overrideTextDirection, restoreTextDirection,
-       clipArea, unclipArea
+  callback as call, valueOrDefault, toFont, isObject,
+  toPadding, getRtlAdapter, overrideTextDirection, restoreTextDirection,
+  clipArea, unclipArea
 } from '../helpers/index';
 import {_toLeftRightCenter, _alignStartEnd} from '../helpers/helpers.extras';
 /**
@@ -13,606 +13,606 @@ import {_toLeftRightCenter, _alignStartEnd} from '../helpers/helpers.extras';
  */
 
 const getBoxSize = (labelOpts, fontSize) => {
-       let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts;
-
-       if (labelOpts.usePointStyle) {
-               boxHeight = Math.min(boxHeight, fontSize);
-               boxWidth = Math.min(boxWidth, fontSize);
-       }
-
-       return {
-               boxWidth,
-               boxHeight,
-               itemHeight: Math.max(fontSize, boxHeight)
-       };
+  let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts;
+
+  if (labelOpts.usePointStyle) {
+    boxHeight = Math.min(boxHeight, fontSize);
+    boxWidth = Math.min(boxWidth, fontSize);
+  }
+
+  return {
+    boxWidth,
+    boxHeight,
+    itemHeight: Math.max(fontSize, boxHeight)
+  };
 };
 
 export class Legend extends Element {
 
-       /**
+  /**
         * @param {{ ctx: any; options: any; chart: any; }} config
         */
-       constructor(config) {
-               super();
+  constructor(config) {
+    super();
 
-               this._added = false;
+    this._added = false;
 
-               // Contains hit boxes for each dataset (in dataset order)
-               this.legendHitBoxes = [];
+    // Contains hit boxes for each dataset (in dataset order)
+    this.legendHitBoxes = [];
 
-               /**
+    /**
                 * @private
                 */
-               this._hoveredItem = null;
-
-               // Are we in doughnut mode which has a different data type
-               this.doughnutMode = false;
-
-               this.chart = config.chart;
-               this.options = config.options;
-               this.ctx = config.ctx;
-               this.legendItems = undefined;
-               this.columnSizes = undefined;
-               this.lineWidths = undefined;
-               this.maxHeight = undefined;
-               this.maxWidth = undefined;
-               this.top = undefined;
-               this.bottom = undefined;
-               this.left = undefined;
-               this.right = undefined;
-               this.height = undefined;
-               this.width = undefined;
-               this._margins = undefined;
-               this.position = undefined;
-               this.weight = undefined;
-               this.fullSize = undefined;
-       }
-
-       update(maxWidth, maxHeight, margins) {
-               const me = this;
-
-               me.maxWidth = maxWidth;
-               me.maxHeight = maxHeight;
-               me._margins = margins;
-
-               me.setDimensions();
-               me.buildLabels();
-               me.fit();
-       }
-
-       setDimensions() {
-               const me = this;
-
-               if (me.isHorizontal()) {
-                       me.width = me.maxWidth;
-                       me.left = 0;
-                       me.right = me.width;
-               } else {
-                       me.height = me.maxHeight;
-                       me.top = 0;
-                       me.bottom = me.height;
-               }
-       }
-
-       buildLabels() {
-               const me = this;
-               const labelOpts = me.options.labels || {};
-               let legendItems = call(labelOpts.generateLabels, [me.chart], me) || [];
-
-               if (labelOpts.filter) {
-                       legendItems = legendItems.filter((item) => labelOpts.filter(item, me.chart.data));
-               }
-
-               if (labelOpts.sort) {
-                       legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, me.chart.data));
-               }
-
-               if (me.options.reverse) {
-                       legendItems.reverse();
-               }
-
-               me.legendItems = legendItems;
-       }
-
-       fit() {
-               const me = this;
-               const {options, ctx} = me;
-
-               // The legend may not be displayed for a variety of reasons including
-               // the fact that the defaults got set to `false`.
-               // When the legend is not displayed, there are no guarantees that the options
-               // are correctly formatted so we need to bail out as early as possible.
-               if (!options.display) {
-                       me.width = me.height = 0;
-                       return;
-               }
-
-               const labelOpts = options.labels;
-               const labelFont = toFont(labelOpts.font, me.chart.options.font);
-               const fontSize = labelFont.size;
-               const titleHeight = me._computeTitleHeight();
-               const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);
-
-               let width, height;
-
-               ctx.font = labelFont.string;
-
-               if (me.isHorizontal()) {
-                       width = me.maxWidth; // fill all the width
-                       height = me._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
-               } else {
-                       height = me.maxHeight; // fill all the height
-                       width = me._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
-               }
-
-               me.width = Math.min(width, options.maxWidth || me.maxWidth);
-               me.height = Math.min(height, options.maxHeight || me.maxHeight);
-       }
-
-       /**
+    this._hoveredItem = null;
+
+    // Are we in doughnut mode which has a different data type
+    this.doughnutMode = false;
+
+    this.chart = config.chart;
+    this.options = config.options;
+    this.ctx = config.ctx;
+    this.legendItems = undefined;
+    this.columnSizes = undefined;
+    this.lineWidths = undefined;
+    this.maxHeight = undefined;
+    this.maxWidth = undefined;
+    this.top = undefined;
+    this.bottom = undefined;
+    this.left = undefined;
+    this.right = undefined;
+    this.height = undefined;
+    this.width = undefined;
+    this._margins = undefined;
+    this.position = undefined;
+    this.weight = undefined;
+    this.fullSize = undefined;
+  }
+
+  update(maxWidth, maxHeight, margins) {
+    const me = this;
+
+    me.maxWidth = maxWidth;
+    me.maxHeight = maxHeight;
+    me._margins = margins;
+
+    me.setDimensions();
+    me.buildLabels();
+    me.fit();
+  }
+
+  setDimensions() {
+    const me = this;
+
+    if (me.isHorizontal()) {
+      me.width = me.maxWidth;
+      me.left = 0;
+      me.right = me.width;
+    } else {
+      me.height = me.maxHeight;
+      me.top = 0;
+      me.bottom = me.height;
+    }
+  }
+
+  buildLabels() {
+    const me = this;
+    const labelOpts = me.options.labels || {};
+    let legendItems = call(labelOpts.generateLabels, [me.chart], me) || [];
+
+    if (labelOpts.filter) {
+      legendItems = legendItems.filter((item) => labelOpts.filter(item, me.chart.data));
+    }
+
+    if (labelOpts.sort) {
+      legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, me.chart.data));
+    }
+
+    if (me.options.reverse) {
+      legendItems.reverse();
+    }
+
+    me.legendItems = legendItems;
+  }
+
+  fit() {
+    const me = this;
+    const {options, ctx} = me;
+
+    // The legend may not be displayed for a variety of reasons including
+    // the fact that the defaults got set to `false`.
+    // When the legend is not displayed, there are no guarantees that the options
+    // are correctly formatted so we need to bail out as early as possible.
+    if (!options.display) {
+      me.width = me.height = 0;
+      return;
+    }
+
+    const labelOpts = options.labels;
+    const labelFont = toFont(labelOpts.font, me.chart.options.font);
+    const fontSize = labelFont.size;
+    const titleHeight = me._computeTitleHeight();
+    const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);
+
+    let width, height;
+
+    ctx.font = labelFont.string;
+
+    if (me.isHorizontal()) {
+      width = me.maxWidth; // fill all the width
+      height = me._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
+    } else {
+      height = me.maxHeight; // fill all the height
+      width = me._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
+    }
+
+    me.width = Math.min(width, options.maxWidth || me.maxWidth);
+    me.height = Math.min(height, options.maxHeight || me.maxHeight);
+  }
+
+  /**
         * @private
         */
-       _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
-               const me = this;
-               const {ctx, maxWidth} = me;
-               const padding = me.options.labels.padding;
-               const hitboxes = me.legendHitBoxes = [];
-               // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
-               const lineWidths = me.lineWidths = [0];
-               let totalHeight = titleHeight;
-
-               ctx.textAlign = 'left';
-               ctx.textBaseline = 'middle';
-
-               me.legendItems.forEach((legendItem, i) => {
-                       const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
-
-                       if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
-                               totalHeight += itemHeight + padding;
-                               lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
-                       }
-
-                       // Store the hitbox width and height here. Final position will be updated in `draw`
-                       hitboxes[i] = {left: 0, top: 0, width: itemWidth, height: itemHeight};
-
-                       lineWidths[lineWidths.length - 1] += itemWidth + padding;
-
-               });
-               return totalHeight;
-       }
-
-       _fitCols(titleHeight, fontSize, boxWidth, itemHeight) {
-               const me = this;
-               const {ctx, maxHeight} = me;
-               const padding = me.options.labels.padding;
-               const hitboxes = me.legendHitBoxes = [];
-               const columnSizes = me.columnSizes = [];
-               let totalWidth = padding;
-               let currentColWidth = 0;
-               let currentColHeight = 0;
-
-               const heightLimit = maxHeight - titleHeight;
-               me.legendItems.forEach((legendItem, i) => {
-                       const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
-
-                       // If too tall, go to new column
-                       if (i > 0 && currentColHeight + fontSize + 2 * padding > heightLimit) {
-                               totalWidth += currentColWidth + padding;
-                               columnSizes.push({width: currentColWidth, height: currentColHeight}); // previous column size
-                               currentColWidth = currentColHeight = 0;
-                       }
-
-                       // Get max width
-                       currentColWidth = Math.max(currentColWidth, itemWidth);
-                       currentColHeight += fontSize + padding;
-
-                       // Store the hitbox width and height here. Final position will be updated in `draw`
-                       hitboxes[i] = {left: 0, top: 0, width: itemWidth, height: itemHeight};
-               });
-
-               totalWidth += currentColWidth;
-               columnSizes.push({width: currentColWidth, height: currentColHeight}); // previous column size
-
-               return totalWidth;
-       }
-
-       isHorizontal() {
-               return this.options.position === 'top' || this.options.position === 'bottom';
-       }
-
-       draw() {
-               const me = this;
-               if (me.options.display) {
-                       const ctx = me.ctx;
-                       clipArea(ctx, me);
-
-                       me._draw();
-
-                       unclipArea(ctx);
-               }
-       }
-
-       /**
+  _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
+    const me = this;
+    const {ctx, maxWidth} = me;
+    const padding = me.options.labels.padding;
+    const hitboxes = me.legendHitBoxes = [];
+    // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
+    const lineWidths = me.lineWidths = [0];
+    let totalHeight = titleHeight;
+
+    ctx.textAlign = 'left';
+    ctx.textBaseline = 'middle';
+
+    me.legendItems.forEach((legendItem, i) => {
+      const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+      if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
+        totalHeight += itemHeight + padding;
+        lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
+      }
+
+      // Store the hitbox width and height here. Final position will be updated in `draw`
+      hitboxes[i] = {left: 0,  top: 0, width: itemWidth, height: itemHeight};
+
+      lineWidths[lineWidths.length - 1] += itemWidth + padding;
+
+    });
+    return totalHeight;
+  }
+
+  _fitCols(titleHeight, fontSize, boxWidth, itemHeight) {
+    const me = this;
+    const {ctx, maxHeight} = me;
+    const padding = me.options.labels.padding;
+    const hitboxes = me.legendHitBoxes = [];
+    const columnSizes = me.columnSizes = [];
+    let totalWidth = padding;
+    let currentColWidth = 0;
+    let currentColHeight = 0;
+
+    const heightLimit = maxHeight - titleHeight;
+    me.legendItems.forEach((legendItem, i) => {
+      const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+
+      // If too tall, go to new column
+      if (i > 0 && currentColHeight + fontSize + 2 * padding > heightLimit) {
+        totalWidth += currentColWidth + padding;
+        columnSizes.push({width: currentColWidth, height: currentColHeight}); // previous column size
+        currentColWidth = currentColHeight = 0;
+      }
+
+      // Get max width
+      currentColWidth = Math.max(currentColWidth, itemWidth);
+      currentColHeight += fontSize + padding;
+
+      // Store the hitbox width and height here. Final position will be updated in `draw`
+      hitboxes[i] = {left: 0,  top: 0, width: itemWidth, height: itemHeight};
+    });
+
+    totalWidth += currentColWidth;
+    columnSizes.push({width: currentColWidth, height: currentColHeight}); // previous column size
+
+    return totalWidth;
+  }
+
+  isHorizontal() {
+    return this.options.position === 'top' || this.options.position === 'bottom';
+  }
+
+  draw() {
+    const me = this;
+    if (me.options.display) {
+      const ctx = me.ctx;
+      clipArea(ctx, me);
+
+      me._draw();
+
+      unclipArea(ctx);
+    }
+  }
+
+  /**
         * @private
         */
-       _draw() {
-               const me = this;
-               const {options: opts, columnSizes, lineWidths, ctx, legendHitBoxes} = me;
-               const {align, labels: labelOpts} = opts;
-               const defaultColor = defaults.color;
-               const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
-               const labelFont = toFont(labelOpts.font, me.chart.options.font);
-               const {color: fontColor, padding} = labelOpts;
-               const fontSize = labelFont.size;
-               let cursor;
-
-               me.drawTitle();
-
-               // Canvas setup
-               ctx.textAlign = rtlHelper.textAlign('left');
-               ctx.textBaseline = 'middle';
-               ctx.lineWidth = 0.5;
-               ctx.strokeStyle = fontColor; // for strikethrough effect
-               ctx.fillStyle = fontColor; // render in correct colour
-               ctx.font = labelFont.string;
-
-               const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize);
-
-               // current position
-               const drawLegendBox = function(x, y, legendItem) {
-                       if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
-                               return;
-                       }
-
-                       // Set the ctx for the box
-                       ctx.save();
-
-                       const lineWidth = valueOrDefault(legendItem.lineWidth, 1);
-                       ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
-                       ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt');
-                       ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);
-                       ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter');
-                       ctx.lineWidth = lineWidth;
-                       ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
-
-                       ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));
-
-                       if (labelOpts.usePointStyle) {
-                               // Recalculate x and y for drawPoint() because its expecting
-                               // x and y to be center of figure (instead of top left)
-                               const drawOptions = {
-                                       radius: boxWidth * Math.SQRT2 / 2,
-                                       pointStyle: legendItem.pointStyle,
-                                       rotation: legendItem.rotation,
-                                       borderWidth: lineWidth
-                               };
-                               const centerX = rtlHelper.xPlus(x, boxWidth / 2);
-                               const centerY = y + fontSize / 2;
-
-                               // Draw pointStyle as legend symbol
-                               drawPoint(ctx, drawOptions, centerX, centerY);
-                       } else {
-                               // Draw box as legend symbol
-                               // Adjust position when boxHeight < fontSize (want it centered)
-                               const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
-
-                               ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight);
-                               if (lineWidth !== 0) {
-                                       ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight);
-                               }
-                       }
-
-                       ctx.restore();
-               };
-
-               const fillText = function(x, y, legendItem) {
-                       const halfFontSize = fontSize / 2;
-                       const xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
-                       renderText(ctx, legendItem.text, xLeft, y + (itemHeight / 2), labelFont, {strikethrough: legendItem.hidden});
-               };
-
-               // Horizontal
-               const isHorizontal = me.isHorizontal();
-               const titleHeight = this._computeTitleHeight();
-               if (isHorizontal) {
-                       cursor = {
-                               x: _alignStartEnd(align, me.left + padding, me.right - lineWidths[0]),
-                               y: me.top + padding + titleHeight,
-                               line: 0
-                       };
-               } else {
-                       cursor = {
-                               x: me.left + padding,
-                               y: _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[0].height),
-                               line: 0
-                       };
-               }
-
-               overrideTextDirection(me.ctx, opts.textDirection);
-
-               const lineHeight = itemHeight + padding;
-               me.legendItems.forEach((legendItem, i) => {
-                       const textWidth = ctx.measureText(legendItem.text).width;
-                       const width = boxWidth + (fontSize / 2) + textWidth;
-                       let x = cursor.x;
-                       let y = cursor.y;
-
-                       rtlHelper.setWidth(me.width);
-
-                       if (isHorizontal) {
-                               if (i > 0 && x + width + padding > me.right) {
-                                       y = cursor.y += lineHeight;
-                                       cursor.line++;
-                                       x = cursor.x = _alignStartEnd(align, me.left + padding, me.right - lineWidths[cursor.line]);
-                               }
-                       } else if (i > 0 && y + lineHeight > me.bottom) {
-                               x = cursor.x = x + columnSizes[cursor.line].width + padding;
-                               cursor.line++;
-                               y = cursor.y = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[cursor.line].height);
-                       }
-
-                       const realX = rtlHelper.x(x);
-
-                       drawLegendBox(realX, y, legendItem);
-
-                       legendHitBoxes[i].left = rtlHelper.leftForLtr(realX, legendHitBoxes[i].width);
-                       legendHitBoxes[i].top = y;
-
-                       // Fill the actual label
-                       fillText(realX, y, legendItem);
-
-                       if (isHorizontal) {
-                               cursor.x += width + padding;
-                       } else {
-                               cursor.y += lineHeight;
-                       }
-               });
-
-               restoreTextDirection(me.ctx, opts.textDirection);
-       }
-
-       /**
+  _draw() {
+    const me = this;
+    const {options: opts, columnSizes, lineWidths, ctx, legendHitBoxes} = me;
+    const {align, labels: labelOpts} = opts;
+    const defaultColor = defaults.color;
+    const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
+    const labelFont = toFont(labelOpts.font, me.chart.options.font);
+    const {color: fontColor, padding} = labelOpts;
+    const fontSize = labelFont.size;
+    let cursor;
+
+    me.drawTitle();
+
+    // Canvas setup
+    ctx.textAlign = rtlHelper.textAlign('left');
+    ctx.textBaseline = 'middle';
+    ctx.lineWidth = 0.5;
+    ctx.strokeStyle = fontColor; // for strikethrough effect
+    ctx.fillStyle = fontColor; // render in correct colour
+    ctx.font = labelFont.string;
+
+    const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize);
+
+    // current position
+    const drawLegendBox = function(x, y, legendItem) {
+      if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
+        return;
+      }
+
+      // Set the ctx for the box
+      ctx.save();
+
+      const lineWidth = valueOrDefault(legendItem.lineWidth, 1);
+      ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
+      ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt');
+      ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);
+      ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter');
+      ctx.lineWidth = lineWidth;
+      ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
+
+      ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));
+
+      if (labelOpts.usePointStyle) {
+        // Recalculate x and y for drawPoint() because its expecting
+        // x and y to be center of figure (instead of top left)
+        const drawOptions = {
+          radius: boxWidth * Math.SQRT2 / 2,
+          pointStyle: legendItem.pointStyle,
+          rotation: legendItem.rotation,
+          borderWidth: lineWidth
+        };
+        const centerX = rtlHelper.xPlus(x, boxWidth / 2);
+        const centerY = y + fontSize / 2;
+
+        // Draw pointStyle as legend symbol
+        drawPoint(ctx, drawOptions, centerX, centerY);
+      } else {
+        // Draw box as legend symbol
+        // Adjust position when boxHeight < fontSize (want it centered)
+        const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
+
+        ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight);
+        if (lineWidth !== 0) {
+          ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight);
+        }
+      }
+
+      ctx.restore();
+    };
+
+    const fillText = function(x, y, legendItem) {
+      const halfFontSize = fontSize / 2;
+      const xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);
+      renderText(ctx, legendItem.text, xLeft, y + (itemHeight / 2), labelFont, {strikethrough: legendItem.hidden});
+    };
+
+    // Horizontal
+    const isHorizontal = me.isHorizontal();
+    const titleHeight = this._computeTitleHeight();
+    if (isHorizontal) {
+      cursor = {
+        x: _alignStartEnd(align, me.left + padding, me.right - lineWidths[0]),
+        y: me.top + padding + titleHeight,
+        line: 0
+      };
+    } else {
+      cursor = {
+        x: me.left + padding,
+        y: _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[0].height),
+        line: 0
+      };
+    }
+
+    overrideTextDirection(me.ctx, opts.textDirection);
+
+    const lineHeight = itemHeight + padding;
+    me.legendItems.forEach((legendItem, i) => {
+      const textWidth = ctx.measureText(legendItem.text).width;
+      const width = boxWidth + (fontSize / 2) + textWidth;
+      let x = cursor.x;
+      let y = cursor.y;
+
+      rtlHelper.setWidth(me.width);
+
+      if (isHorizontal) {
+        if (i > 0 && x + width + padding > me.right) {
+          y = cursor.y += lineHeight;
+          cursor.line++;
+          x = cursor.x = _alignStartEnd(align, me.left + padding, me.right - lineWidths[cursor.line]);
+        }
+      } else if (i > 0 && y + lineHeight > me.bottom) {
+        x = cursor.x = x + columnSizes[cursor.line].width + padding;
+        cursor.line++;
+        y = cursor.y = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[cursor.line].height);
+      }
+
+      const realX = rtlHelper.x(x);
+
+      drawLegendBox(realX, y, legendItem);
+
+      legendHitBoxes[i].left = rtlHelper.leftForLtr(realX, legendHitBoxes[i].width);
+      legendHitBoxes[i].top = y;
+
+      // Fill the actual label
+      fillText(realX, y, legendItem);
+
+      if (isHorizontal) {
+        cursor.x += width + padding;
+      } else {
+        cursor.y += lineHeight;
+      }
+    });
+
+    restoreTextDirection(me.ctx, opts.textDirection);
+  }
+
+  /**
         * @protected
         */
-       drawTitle() {
-               const me = this;
-               const opts = me.options;
-               const titleOpts = opts.title;
-               const titleFont = toFont(titleOpts.font, me.chart.options.font);
-               const titlePadding = toPadding(titleOpts.padding);
-
-               if (!titleOpts.display) {
-                       return;
-               }
-
-               const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
-               const ctx = me.ctx;
-               const position = titleOpts.position;
-               const halfFontSize = titleFont.size / 2;
-               const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
-               let y;
-
-               // These defaults are used when the legend is vertical.
-               // When horizontal, they are computed below.
-               let left = me.left;
-               let maxWidth = me.width;
-
-               if (this.isHorizontal()) {
-                       // Move left / right so that the title is above the legend lines
-                       maxWidth = Math.max(...me.lineWidths);
-                       y = me.top + topPaddingPlusHalfFontSize;
-                       left = _alignStartEnd(opts.align, left, me.right - maxWidth);
-               } else {
-                       // Move down so that the title is above the legend stack in every alignment
-                       const maxHeight = me.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
-                       y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, me.top, me.bottom - maxHeight - opts.labels.padding - me._computeTitleHeight());
-               }
-
-               // Now that we know the left edge of the inner legend box, compute the correct
-               // X coordinate from the title alignment
-               const x = _alignStartEnd(position, left, left + maxWidth);
-
-               // Canvas setup
-               ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));
-               ctx.textBaseline = 'middle';
-               ctx.strokeStyle = titleOpts.color;
-               ctx.fillStyle = titleOpts.color;
-               ctx.font = titleFont.string;
-
-               renderText(ctx, titleOpts.text, x, y, titleFont);
-       }
-
-       /**
+  drawTitle() {
+    const me = this;
+    const opts = me.options;
+    const titleOpts = opts.title;
+    const titleFont = toFont(titleOpts.font, me.chart.options.font);
+    const titlePadding = toPadding(titleOpts.padding);
+
+    if (!titleOpts.display) {
+      return;
+    }
+
+    const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
+    const ctx = me.ctx;
+    const position = titleOpts.position;
+    const halfFontSize = titleFont.size / 2;
+    const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
+    let y;
+
+    // These defaults are used when the legend is vertical.
+    // When horizontal, they are computed below.
+    let left = me.left;
+    let maxWidth = me.width;
+
+    if (this.isHorizontal()) {
+      // Move left / right so that the title is above the legend lines
+      maxWidth = Math.max(...me.lineWidths);
+      y = me.top + topPaddingPlusHalfFontSize;
+      left = _alignStartEnd(opts.align, left, me.right - maxWidth);
+    } else {
+      // Move down so that the title is above the legend stack in every alignment
+      const maxHeight = me.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
+      y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, me.top, me.bottom - maxHeight - opts.labels.padding - me._computeTitleHeight());
+    }
+
+    // Now that we know the left edge of the inner legend box, compute the correct
+    // X coordinate from the title alignment
+    const x = _alignStartEnd(position, left, left + maxWidth);
+
+    // Canvas setup
+    ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));
+    ctx.textBaseline = 'middle';
+    ctx.strokeStyle = titleOpts.color;
+    ctx.fillStyle = titleOpts.color;
+    ctx.font = titleFont.string;
+
+    renderText(ctx, titleOpts.text, x, y, titleFont);
+  }
+
+  /**
         * @private
         */
-       _computeTitleHeight() {
-               const titleOpts = this.options.title;
-               const titleFont = toFont(titleOpts.font, this.chart.options.font);
-               const titlePadding = toPadding(titleOpts.padding);
-               return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
-       }
-
-       /**
+  _computeTitleHeight() {
+    const titleOpts = this.options.title;
+    const titleFont = toFont(titleOpts.font, this.chart.options.font);
+    const titlePadding = toPadding(titleOpts.padding);
+    return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
+  }
+
+  /**
         * @private
         */
-       _getLegendItemAt(x, y) {
-               const me = this;
-               let i, hitBox, lh;
-
-               if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
-                       // See if we are touching one of the dataset boxes
-                       lh = me.legendHitBoxes;
-                       for (i = 0; i < lh.length; ++i) {
-                               hitBox = lh[i];
-
-                               if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
-                                       // Touching an element
-                                       return me.legendItems[i];
-                               }
-                       }
-               }
-
-               return null;
-       }
-
-       /**
+  _getLegendItemAt(x, y) {
+    const me = this;
+    let i, hitBox, lh;
+
+    if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
+      // See if we are touching one of the dataset boxes
+      lh = me.legendHitBoxes;
+      for (i = 0; i < lh.length; ++i) {
+        hitBox = lh[i];
+
+        if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
+          // Touching an element
+          return me.legendItems[i];
+        }
+      }
+    }
+
+    return null;
+  }
+
+  /**
         * Handle an event
         * @param {ChartEvent} e - The event to handle
         */
-       handleEvent(e) {
-               const me = this;
-               const opts = me.options;
-               if (!isListened(e.type, opts)) {
-                       return;
-               }
-
-               // Chart event already has relative position in it
-               const hoveredItem = me._getLegendItemAt(e.x, e.y);
-
-               if (e.type === 'mousemove') {
-                       const previous = me._hoveredItem;
-                       if (previous && previous !== hoveredItem) {
-                               call(opts.onLeave, [e, previous, me], me);
-                       }
-
-                       me._hoveredItem = hoveredItem;
-
-                       if (hoveredItem) {
-                               call(opts.onHover, [e, hoveredItem, me], me);
-                       }
-               } else if (hoveredItem) {
-                       call(opts.onClick, [e, hoveredItem, me], me);
-               }
-       }
+  handleEvent(e) {
+    const me = this;
+    const opts = me.options;
+    if (!isListened(e.type, opts)) {
+      return;
+    }
+
+    // Chart event already has relative position in it
+    const hoveredItem = me._getLegendItemAt(e.x, e.y);
+
+    if (e.type === 'mousemove') {
+      const previous = me._hoveredItem;
+      if (previous && previous !== hoveredItem) {
+        call(opts.onLeave, [e, previous, me], me);
+      }
+
+      me._hoveredItem = hoveredItem;
+
+      if (hoveredItem) {
+        call(opts.onHover, [e, hoveredItem, me], me);
+      }
+    } else if (hoveredItem) {
+      call(opts.onClick, [e, hoveredItem, me], me);
+    }
+  }
 }
 
 function isListened(type, opts) {
-       if (type === 'mousemove' && (opts.onHover || opts.onLeave)) {
-               return true;
-       }
-       if (opts.onClick && (type === 'click' || type === 'mouseup')) {
-               return true;
-       }
-       return false;
+  if (type === 'mousemove' && (opts.onHover || opts.onLeave)) {
+    return true;
+  }
+  if (opts.onClick && (type === 'click' || type === 'mouseup')) {
+    return true;
+  }
+  return false;
 }
 
 export default {
-       id: 'legend',
+  id: 'legend',
 
-       /**
+  /**
         * For tests
         * @private
         */
-       _element: Legend,
-
-       start(chart, _args, options) {
-               const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart});
-               layouts.configure(chart, legend, options);
-               layouts.addBox(chart, legend);
-       },
-
-       stop(chart) {
-               layouts.removeBox(chart, chart.legend);
-               delete chart.legend;
-       },
-
-       // During the beforeUpdate step, the layout configuration needs to run
-       // This ensures that if the legend position changes (via an option update)
-       // the layout system respects the change. See https://github.com/chartjs/Chart.js/issues/7527
-       beforeUpdate(chart, _args, options) {
-               const legend = chart.legend;
-               layouts.configure(chart, legend, options);
-               legend.options = options;
-       },
-
-       // The labels need to be built after datasets are updated to ensure that colors
-       // and other styling are correct. See https://github.com/chartjs/Chart.js/issues/6968
-       afterUpdate(chart) {
-               chart.legend.buildLabels();
-       },
-
-
-       afterEvent(chart, args) {
-               chart.legend.handleEvent(args.event);
-       },
-
-       defaults: {
-               display: true,
-               position: 'top',
-               align: 'center',
-               fullSize: true,
-               reverse: false,
-               weight: 1000,
-
-               // a callback that will handle
-               onClick(e, legendItem, legend) {
-                       const index = legendItem.datasetIndex;
-                       const ci = legend.chart;
-                       if (ci.isDatasetVisible(index)) {
-                               ci.hide(index);
-                               legendItem.hidden = true;
-                       } else {
-                               ci.show(index);
-                               legendItem.hidden = false;
-                       }
-               },
-
-               onHover: null,
-               onLeave: null,
-
-               labels: {
-                       boxWidth: 40,
-                       padding: 10,
-                       // Generates labels shown in the legend
-                       // Valid properties to return:
-                       // text : text to display
-                       // fillStyle : fill of coloured box
-                       // strokeStyle: stroke of coloured box
-                       // hidden : if this legend item refers to a hidden item
-                       // lineCap : cap style for line
-                       // lineDash
-                       // lineDashOffset :
-                       // lineJoin :
-                       // lineWidth :
-                       generateLabels(chart) {
-                               const datasets = chart.data.datasets;
-                               const {labels} = chart.legend.options;
-                               const usePointStyle = labels.usePointStyle;
-                               const overrideStyle = labels.pointStyle;
-
-                               return chart._getSortedDatasetMetas().map((meta) => {
-                                       const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
-                                       const borderWidth = isObject(style.borderWidth) ? (valueOrDefault(style.borderWidth.top, 0) + valueOrDefault(style.borderWidth.left, 0) + valueOrDefault(style.borderWidth.bottom, 0) + valueOrDefault(style.borderWidth.right, 0)) / 4 : style.borderWidth;
-
-                                       return {
-                                               text: datasets[meta.index].label,
-                                               fillStyle: style.backgroundColor,
-                                               hidden: !meta.visible,
-                                               lineCap: style.borderCapStyle,
-                                               lineDash: style.borderDash,
-                                               lineDashOffset: style.borderDashOffset,
-                                               lineJoin: style.borderJoinStyle,
-                                               lineWidth: borderWidth,
-                                               strokeStyle: style.borderColor,
-                                               pointStyle: overrideStyle || style.pointStyle,
-                                               rotation: style.rotation,
-
-                                               // Below is extra data used for toggling the datasets
-                                               datasetIndex: meta.index
-                                       };
-                               }, this);
-                       }
-               },
-
-               title: {
-                       display: false,
-                       position: 'center',
-                       text: '',
-               }
-       },
-
-       defaultRoutes: {
-               'labels.color': 'color',
-               'title.color': 'color'
-       }
+  _element: Legend,
+
+  start(chart, _args, options) {
+    const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart});
+    layouts.configure(chart, legend, options);
+    layouts.addBox(chart, legend);
+  },
+
+  stop(chart) {
+    layouts.removeBox(chart, chart.legend);
+    delete chart.legend;
+  },
+
+  // During the beforeUpdate step, the layout configuration needs to run
+  // This ensures that if the legend position changes (via an option update)
+  // the layout system respects the change. See https://github.com/chartjs/Chart.js/issues/7527
+  beforeUpdate(chart, _args, options) {
+    const legend = chart.legend;
+    layouts.configure(chart, legend, options);
+    legend.options = options;
+  },
+
+  // The labels need to be built after datasets are updated to ensure that colors
+  // and other styling are correct. See https://github.com/chartjs/Chart.js/issues/6968
+  afterUpdate(chart) {
+    chart.legend.buildLabels();
+  },
+
+
+  afterEvent(chart, args) {
+    chart.legend.handleEvent(args.event);
+  },
+
+  defaults: {
+    display: true,
+    position: 'top',
+    align: 'center',
+    fullSize: true,
+    reverse: false,
+    weight: 1000,
+
+    // a callback that will handle
+    onClick(e, legendItem, legend) {
+      const index = legendItem.datasetIndex;
+      const ci = legend.chart;
+      if (ci.isDatasetVisible(index)) {
+        ci.hide(index);
+        legendItem.hidden = true;
+      } else {
+        ci.show(index);
+        legendItem.hidden = false;
+      }
+    },
+
+    onHover: null,
+    onLeave: null,
+
+    labels: {
+      boxWidth: 40,
+      padding: 10,
+      // Generates labels shown in the legend
+      // Valid properties to return:
+      // text : text to display
+      // fillStyle : fill of coloured box
+      // strokeStyle: stroke of coloured box
+      // hidden : if this legend item refers to a hidden item
+      // lineCap : cap style for line
+      // lineDash
+      // lineDashOffset :
+      // lineJoin :
+      // lineWidth :
+      generateLabels(chart) {
+        const datasets = chart.data.datasets;
+        const {labels} = chart.legend.options;
+        const usePointStyle = labels.usePointStyle;
+        const overrideStyle = labels.pointStyle;
+
+        return chart._getSortedDatasetMetas().map((meta) => {
+          const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
+          const borderWidth = isObject(style.borderWidth) ? (valueOrDefault(style.borderWidth.top, 0) + valueOrDefault(style.borderWidth.left, 0) + valueOrDefault(style.borderWidth.bottom, 0) + valueOrDefault(style.borderWidth.right, 0)) / 4 : style.borderWidth;
+
+          return {
+            text: datasets[meta.index].label,
+            fillStyle: style.backgroundColor,
+            hidden: !meta.visible,
+            lineCap: style.borderCapStyle,
+            lineDash: style.borderDash,
+            lineDashOffset: style.borderDashOffset,
+            lineJoin: style.borderJoinStyle,
+            lineWidth: borderWidth,
+            strokeStyle: style.borderColor,
+            pointStyle: overrideStyle || style.pointStyle,
+            rotation: style.rotation,
+
+            // Below is extra data used for toggling the datasets
+            datasetIndex: meta.index
+          };
+        }, this);
+      }
+    },
+
+    title: {
+      display: false,
+      position: 'center',
+      text: '',
+    }
+  },
+
+  defaultRoutes: {
+    'labels.color': 'color',
+    'title.color': 'color'
+  }
 };
index 415afc76053cd0c7652a0fa2a8451326b71a45b8..6543f5b29cc20dcc2b7be33607e7969bb2cc5fb5 100644 (file)
@@ -5,179 +5,179 @@ import {_toLeftRightCenter, _alignStartEnd} from '../helpers/helpers.extras';
 import {renderText} from '../helpers/helpers.canvas';
 
 export class Title extends Element {
-       /**
+  /**
         * @param {{ ctx: any; options: any; chart: any; }} config
         */
-       constructor(config) {
-               super();
-
-               this.chart = config.chart;
-               this.options = config.options;
-               this.ctx = config.ctx;
-               this._padding = undefined;
-               this.top = undefined;
-               this.bottom = undefined;
-               this.left = undefined;
-               this.right = undefined;
-               this.width = undefined;
-               this.height = undefined;
-               this.position = undefined;
-               this.weight = undefined;
-               this.fullSize = undefined;
-       }
-
-       update(maxWidth, maxHeight) {
-               const me = this;
-               const opts = me.options;
-
-               me.left = 0;
-               me.top = 0;
-
-               if (!opts.display) {
-                       me.width = me.height = me.right = me.bottom = 0;
-                       return;
-               }
-
-               me.width = me.right = maxWidth;
-               me.height = me.bottom = maxHeight;
-
-               const lineCount = isArray(opts.text) ? opts.text.length : 1;
-               me._padding = toPadding(opts.padding);
-               const textSize = lineCount * toFont(opts.font, me.chart.options.font).lineHeight + me._padding.height;
-
-               if (me.isHorizontal()) {
-                       me.height = textSize;
-               } else {
-                       me.width = textSize;
-               }
-       }
-
-       isHorizontal() {
-               const pos = this.options.position;
-               return pos === 'top' || pos === 'bottom';
-       }
-
-       _drawArgs(offset) {
-               const {top, left, bottom, right, options} = this;
-               const align = options.align;
-               let rotation = 0;
-               let maxWidth, titleX, titleY;
-
-               if (this.isHorizontal()) {
-                       titleX = _alignStartEnd(align, left, right);
-                       titleY = top + offset;
-                       maxWidth = right - left;
-               } else {
-                       if (options.position === 'left') {
-                               titleX = left + offset;
-                               titleY = _alignStartEnd(align, bottom, top);
-                               rotation = PI * -0.5;
-                       } else {
-                               titleX = right - offset;
-                               titleY = _alignStartEnd(align, top, bottom);
-                               rotation = PI * 0.5;
-                       }
-                       maxWidth = bottom - top;
-               }
-               return {titleX, titleY, maxWidth, rotation};
-       }
-
-       draw() {
-               const me = this;
-               const ctx = me.ctx;
-               const opts = me.options;
-
-               if (!opts.display) {
-                       return;
-               }
-
-               const fontOpts = toFont(opts.font, me.chart.options.font);
-               const lineHeight = fontOpts.lineHeight;
-               const offset = lineHeight / 2 + me._padding.top;
-               const {titleX, titleY, maxWidth, rotation} = me._drawArgs(offset);
-
-               renderText(ctx, opts.text, 0, 0, fontOpts, {
-                       color: opts.color,
-                       maxWidth,
-                       rotation,
-                       textAlign: _toLeftRightCenter(opts.align),
-                       textBaseline: 'middle',
-                       translation: [titleX, titleY],
-               });
-       }
+  constructor(config) {
+    super();
+
+    this.chart = config.chart;
+    this.options = config.options;
+    this.ctx = config.ctx;
+    this._padding = undefined;
+    this.top = undefined;
+    this.bottom = undefined;
+    this.left = undefined;
+    this.right = undefined;
+    this.width = undefined;
+    this.height = undefined;
+    this.position = undefined;
+    this.weight = undefined;
+    this.fullSize = undefined;
+  }
+
+  update(maxWidth, maxHeight) {
+    const me = this;
+    const opts = me.options;
+
+    me.left = 0;
+    me.top = 0;
+
+    if (!opts.display) {
+      me.width = me.height = me.right = me.bottom = 0;
+      return;
+    }
+
+    me.width = me.right = maxWidth;
+    me.height = me.bottom = maxHeight;
+
+    const lineCount = isArray(opts.text) ? opts.text.length : 1;
+    me._padding = toPadding(opts.padding);
+    const textSize = lineCount * toFont(opts.font, me.chart.options.font).lineHeight + me._padding.height;
+
+    if (me.isHorizontal()) {
+      me.height = textSize;
+    } else {
+      me.width = textSize;
+    }
+  }
+
+  isHorizontal() {
+    const pos = this.options.position;
+    return pos === 'top' || pos === 'bottom';
+  }
+
+  _drawArgs(offset) {
+    const {top, left, bottom, right, options} = this;
+    const align = options.align;
+    let rotation = 0;
+    let maxWidth, titleX, titleY;
+
+    if (this.isHorizontal()) {
+      titleX = _alignStartEnd(align, left, right);
+      titleY = top + offset;
+      maxWidth = right - left;
+    } else {
+      if (options.position === 'left') {
+        titleX = left + offset;
+        titleY = _alignStartEnd(align, bottom, top);
+        rotation = PI * -0.5;
+      } else {
+        titleX = right - offset;
+        titleY = _alignStartEnd(align, top, bottom);
+        rotation = PI * 0.5;
+      }
+      maxWidth = bottom - top;
+    }
+    return {titleX, titleY, maxWidth, rotation};
+  }
+
+  draw() {
+    const me = this;
+    const ctx = me.ctx;
+    const opts = me.options;
+
+    if (!opts.display) {
+      return;
+    }
+
+    const fontOpts = toFont(opts.font, me.chart.options.font);
+    const lineHeight = fontOpts.lineHeight;
+    const offset = lineHeight / 2 + me._padding.top;
+    const {titleX, titleY, maxWidth, rotation} = me._drawArgs(offset);
+
+    renderText(ctx, opts.text, 0, 0, fontOpts, {
+      color: opts.color,
+      maxWidth,
+      rotation,
+      textAlign: _toLeftRightCenter(opts.align),
+      textBaseline: 'middle',
+      translation: [titleX, titleY],
+    });
+  }
 }
 
 function createTitle(chart, titleOpts) {
-       const title = new Title({
-               ctx: chart.ctx,
-               options: titleOpts,
-               chart
-       });
-
-       layouts.configure(chart, title, titleOpts);
-       layouts.addBox(chart, title);
-       chart.titleBlock = title;
+  const title = new Title({
+    ctx: chart.ctx,
+    options: titleOpts,
+    chart
+  });
+
+  layouts.configure(chart, title, titleOpts);
+  layouts.addBox(chart, title);
+  chart.titleBlock = title;
 }
 
 function removeTitle(chart) {
-       const title = chart.titleBlock;
-       if (title) {
-               layouts.removeBox(chart, title);
-               delete chart.titleBlock;
-       }
+  const title = chart.titleBlock;
+  if (title) {
+    layouts.removeBox(chart, title);
+    delete chart.titleBlock;
+  }
 }
 
 function createOrUpdateTitle(chart, options) {
-       const title = chart.titleBlock;
-       if (title) {
-               layouts.configure(chart, title, options);
-               title.options = options;
-       } else {
-               createTitle(chart, options);
-       }
+  const title = chart.titleBlock;
+  if (title) {
+    layouts.configure(chart, title, options);
+    title.options = options;
+  } else {
+    createTitle(chart, options);
+  }
 }
 
 export default {
-       id: 'title',
+  id: 'title',
 
-       /**
+  /**
         * For tests
         * @private
         */
-       _element: Title,
-
-       start(chart, _args, options) {
-               createTitle(chart, options);
-       },
-
-       stop(chart) {
-               const titleBlock = chart.titleBlock;
-               layouts.removeBox(chart, titleBlock);
-               delete chart.titleBlock;
-       },
-
-       beforeUpdate(chart, _args, options) {
-               if (options === false) {
-                       removeTitle(chart);
-               } else {
-                       createOrUpdateTitle(chart, options);
-               }
-       },
-
-       defaults: {
-               align: 'center',
-               display: false,
-               font: {
-                       style: 'bold',
-               },
-               fullSize: true,
-               padding: 10,
-               position: 'top',
-               text: '',
-               weight: 2000         // by default greater than legend (1000) to be above
-       },
-
-       defaultRoutes: {
-               color: 'color'
-       }
+  _element: Title,
+
+  start(chart, _args, options) {
+    createTitle(chart, options);
+  },
+
+  stop(chart) {
+    const titleBlock = chart.titleBlock;
+    layouts.removeBox(chart, titleBlock);
+    delete chart.titleBlock;
+  },
+
+  beforeUpdate(chart, _args, options) {
+    if (options === false) {
+      removeTitle(chart);
+    } else {
+      createOrUpdateTitle(chart, options);
+    }
+  },
+
+  defaults: {
+    align: 'center',
+    display: false,
+    font: {
+      style: 'bold',
+    },
+    fullSize: true,
+    padding: 10,
+    position: 'top',
+    text: '',
+    weight: 2000         // by default greater than legend (1000) to be above
+  },
+
+  defaultRoutes: {
+    color: 'color'
+  }
 };
index cb230dd5c5ee693577e08d030e4931f072b26705..566481554f404c617a3bd1c13ee3f7e0ff7f2bcf 100644 (file)
@@ -10,89 +10,89 @@ import {drawPoint, toFontString} from '../helpers';
  */
 
 const positioners = {
-       /**
+  /**
         * Average mode places the tooltip at the average position of the elements shown
         * @function Chart.Tooltip.positioners.average
         * @param items {object[]} the items being displayed in the tooltip
         * @returns {object} tooltip position
         */
-       average(items) {
-               if (!items.length) {
-                       return false;
-               }
-
-               let i, len;
-               let x = 0;
-               let y = 0;
-               let count = 0;
-
-               for (i = 0, len = items.length; i < len; ++i) {
-                       const el = items[i].element;
-                       if (el && el.hasValue()) {
-                               const pos = el.tooltipPosition();
-                               x += pos.x;
-                               y += pos.y;
-                               ++count;
-                       }
-               }
-
-               return {
-                       x: x / count,
-                       y: y / count
-               };
-       },
-
-       /**
+  average(items) {
+    if (!items.length) {
+      return false;
+    }
+
+    let i, len;
+    let x = 0;
+    let y = 0;
+    let count = 0;
+
+    for (i = 0, len = items.length; i < len; ++i) {
+      const el = items[i].element;
+      if (el && el.hasValue()) {
+        const pos = el.tooltipPosition();
+        x += pos.x;
+        y += pos.y;
+        ++count;
+      }
+    }
+
+    return {
+      x: x / count,
+      y: y / count
+    };
+  },
+
+  /**
         * Gets the tooltip position nearest of the item nearest to the event position
         * @function Chart.Tooltip.positioners.nearest
         * @param items {object[]} the tooltip items
         * @param eventPosition {object} the position of the event in canvas coordinates
         * @returns {object} the tooltip position
         */
-       nearest(items, eventPosition) {
-               let x = eventPosition.x;
-               let y = eventPosition.y;
-               let minDistance = Number.POSITIVE_INFINITY;
-               let i, len, nearestElement;
-
-               for (i = 0, len = items.length; i < len; ++i) {
-                       const el = items[i].element;
-                       if (el && el.hasValue()) {
-                               const center = el.getCenterPoint();
-                               const d = distanceBetweenPoints(eventPosition, center);
-
-                               if (d < minDistance) {
-                                       minDistance = d;
-                                       nearestElement = el;
-                               }
-                       }
-               }
-
-               if (nearestElement) {
-                       const tp = nearestElement.tooltipPosition();
-                       x = tp.x;
-                       y = tp.y;
-               }
-
-               return {
-                       x,
-                       y
-               };
-       }
+  nearest(items, eventPosition) {
+    let x = eventPosition.x;
+    let y = eventPosition.y;
+    let minDistance = Number.POSITIVE_INFINITY;
+    let i, len, nearestElement;
+
+    for (i = 0, len = items.length; i < len; ++i) {
+      const el = items[i].element;
+      if (el && el.hasValue()) {
+        const center = el.getCenterPoint();
+        const d = distanceBetweenPoints(eventPosition, center);
+
+        if (d < minDistance) {
+          minDistance = d;
+          nearestElement = el;
+        }
+      }
+    }
+
+    if (nearestElement) {
+      const tp = nearestElement.tooltipPosition();
+      x = tp.x;
+      y = tp.y;
+    }
+
+    return {
+      x,
+      y
+    };
+  }
 };
 
 // Helper to push or concat based on if the 2nd parameter is an array or not
 function pushOrConcat(base, toPush) {
-       if (toPush) {
-               if (isArray(toPush)) {
-                       // base = base.concat(toPush);
-                       Array.prototype.push.apply(base, toPush);
-               } else {
-                       base.push(toPush);
-               }
-       }
-
-       return base;
+  if (toPush) {
+    if (isArray(toPush)) {
+      // base = base.concat(toPush);
+      Array.prototype.push.apply(base, toPush);
+    } else {
+      base.push(toPush);
+    }
+  }
+
+  return base;
 }
 
 /**
@@ -102,10 +102,10 @@ function pushOrConcat(base, toPush) {
  * @function
  */
 function splitNewlines(str) {
-       if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
-               return str.split('\n');
-       }
-       return str;
+  if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
+    return str.split('\n');
+  }
+  return str;
 }
 
 
@@ -115,905 +115,905 @@ function splitNewlines(str) {
  * @return new tooltip item
  */
 function createTooltipItem(chart, item) {
-       const {element, datasetIndex, index} = item;
-       const controller = chart.getDatasetMeta(datasetIndex).controller;
-       const {label, value} = controller.getLabelAndValue(index);
-
-       return {
-               chart,
-               label,
-               parsed: controller.getParsed(index),
-               raw: chart.data.datasets[datasetIndex].data[index],
-               formattedValue: value,
-               dataset: controller.getDataset(),
-               dataIndex: index,
-               datasetIndex,
-               element
-       };
+  const {element, datasetIndex, index} = item;
+  const controller = chart.getDatasetMeta(datasetIndex).controller;
+  const {label, value} = controller.getLabelAndValue(index);
+
+  return {
+    chart,
+    label,
+    parsed: controller.getParsed(index),
+    raw: chart.data.datasets[datasetIndex].data[index],
+    formattedValue: value,
+    dataset: controller.getDataset(),
+    dataIndex: index,
+    datasetIndex,
+    element
+  };
 }
 
 /**
  * Get the size of the tooltip
  */
 function getTooltipSize(tooltip) {
-       const ctx = tooltip._chart.ctx;
-       const {body, footer, options, title} = tooltip;
-       const {bodyFont, footerFont, titleFont, boxWidth, boxHeight} = options;
-       const titleLineCount = title.length;
-       const footerLineCount = footer.length;
-       const bodyLineItemCount = body.length;
-
-       let height = options.yPadding * 2; // Tooltip Padding
-       let width = 0;
-
-       // Count of all lines in the body
-       let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
-       combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
-
-       if (titleLineCount) {
-               height += titleLineCount * titleFont.size
+  const ctx = tooltip._chart.ctx;
+  const {body, footer, options, title} = tooltip;
+  const {bodyFont, footerFont, titleFont, boxWidth, boxHeight} = options;
+  const titleLineCount = title.length;
+  const footerLineCount = footer.length;
+  const bodyLineItemCount = body.length;
+
+  let height = options.yPadding * 2; // Tooltip Padding
+  let width = 0;
+
+  // Count of all lines in the body
+  let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
+  combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
+
+  if (titleLineCount) {
+    height += titleLineCount * titleFont.size
                        + (titleLineCount - 1) * options.titleSpacing
                        + options.titleMarginBottom;
-       }
-       if (combinedBodyLength) {
-               // Body lines may include some extra height depending on boxHeight
-               const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.size) : bodyFont.size;
-               height += bodyLineItemCount * bodyLineHeight
+  }
+  if (combinedBodyLength) {
+    // Body lines may include some extra height depending on boxHeight
+    const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.size) : bodyFont.size;
+    height += bodyLineItemCount * bodyLineHeight
                        + (combinedBodyLength - bodyLineItemCount) * bodyFont.size
                        + (combinedBodyLength - 1) * options.bodySpacing;
-       }
-       if (footerLineCount) {
-               height += options.footerMarginTop
+  }
+  if (footerLineCount) {
+    height += options.footerMarginTop
                        + footerLineCount * footerFont.size
                        + (footerLineCount - 1) * options.footerSpacing;
-       }
+  }
 
-       // Title width
-       let widthPadding = 0;
-       const maxLineWidth = function(line) {
-               width = Math.max(width, ctx.measureText(line).width + widthPadding);
-       };
+  // Title width
+  let widthPadding = 0;
+  const maxLineWidth = function(line) {
+    width = Math.max(width, ctx.measureText(line).width + widthPadding);
+  };
 
-       ctx.save();
+  ctx.save();
 
-       ctx.font = toFontString(titleFont);
-       each(tooltip.title, maxLineWidth);
+  ctx.font = toFontString(titleFont);
+  each(tooltip.title, maxLineWidth);
 
-       // Body width
-       ctx.font = toFontString(bodyFont);
-       each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
+  // Body width
+  ctx.font = toFontString(bodyFont);
+  each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
 
-       // Body lines may include some extra width due to the color box
-       widthPadding = options.displayColors ? (boxWidth + 2) : 0;
-       each(body, (bodyItem) => {
-               each(bodyItem.before, maxLineWidth);
-               each(bodyItem.lines, maxLineWidth);
-               each(bodyItem.after, maxLineWidth);
-       });
+  // Body lines may include some extra width due to the color box
+  widthPadding = options.displayColors ? (boxWidth + 2) : 0;
+  each(body, (bodyItem) => {
+    each(bodyItem.before, maxLineWidth);
+    each(bodyItem.lines, maxLineWidth);
+    each(bodyItem.after, maxLineWidth);
+  });
 
-       // Reset back to 0
-       widthPadding = 0;
+  // Reset back to 0
+  widthPadding = 0;
 
-       // Footer width
-       ctx.font = toFontString(footerFont);
-       each(tooltip.footer, maxLineWidth);
+  // Footer width
+  ctx.font = toFontString(footerFont);
+  each(tooltip.footer, maxLineWidth);
 
-       ctx.restore();
+  ctx.restore();
 
-       // Add padding
-       width += 2 * options.xPadding;
+  // Add padding
+  width += 2 * options.xPadding;
 
-       return {width, height};
+  return {width, height};
 }
 
 /**
  * Helper to get the alignment of a tooltip given the size
  */
 function determineAlignment(chart, options, size) {
-       const {x, y, width, height} = size;
-       const chartArea = chart.chartArea;
-       let xAlign = 'center';
-       let yAlign = 'center';
-
-       if (y < height / 2) {
-               yAlign = 'top';
-       } else if (y > (chart.height - height / 2)) {
-               yAlign = 'bottom';
-       }
-
-       let lf, rf; // functions to determine left, right alignment
-       const midX = (chartArea.left + chartArea.right) / 2;
-       const midY = (chartArea.top + chartArea.bottom) / 2;
-
-       if (yAlign === 'center') {
-               lf = (value) => value <= midX;
-               rf = (value) => value > midX;
-       } else {
-               lf = (value) => value <= (width / 2);
-               rf = (value) => value >= (chart.width - (width / 2));
-       }
-
-       // functions to determine if left/right alignment causes tooltip to go outside chart
-       const olf = (value) => value + width + options.caretSize + options.caretPadding > chart.width;
-       const orf = (value) => value - width - options.caretSize - options.caretPadding < 0;
-       // function to get the y alignment if the tooltip goes outside of the left or right edges
-       const yf = (value) => value <= midY ? 'top' : 'bottom';
-
-       if (lf(x)) {
-               xAlign = 'left';
-
-               // Is tooltip too wide and goes over the right side of the chart.?
-               if (olf(x)) {
-                       xAlign = 'center';
-                       yAlign = yf(y);
-               }
-       } else if (rf(x)) {
-               xAlign = 'right';
-
-               // Is tooltip too wide and goes outside left edge of canvas?
-               if (orf(x)) {
-                       xAlign = 'center';
-                       yAlign = yf(y);
-               }
-       }
-
-       return {
-               xAlign: options.xAlign ? options.xAlign : xAlign,
-               yAlign: options.yAlign ? options.yAlign : yAlign
-       };
+  const {x, y, width, height} = size;
+  const chartArea = chart.chartArea;
+  let xAlign = 'center';
+  let yAlign = 'center';
+
+  if (y < height / 2) {
+    yAlign = 'top';
+  } else if (y > (chart.height - height / 2)) {
+    yAlign = 'bottom';
+  }
+
+  let lf, rf; // functions to determine left, right alignment
+  const midX = (chartArea.left + chartArea.right) / 2;
+  const midY = (chartArea.top + chartArea.bottom) / 2;
+
+  if (yAlign === 'center') {
+    lf = (value) => value <= midX;
+    rf = (value) => value > midX;
+  } else {
+    lf = (value) => value <= (width / 2);
+    rf = (value) => value >= (chart.width - (width / 2));
+  }
+
+  // functions to determine if left/right alignment causes tooltip to go outside chart
+  const olf = (value) => value + width + options.caretSize + options.caretPadding > chart.width;
+  const orf = (value) => value - width - options.caretSize - options.caretPadding < 0;
+  // function to get the y alignment if the tooltip goes outside of the left or right edges
+  const yf = (value) => value <= midY ? 'top' : 'bottom';
+
+  if (lf(x)) {
+    xAlign = 'left';
+
+    // Is tooltip too wide and goes over the right side of the chart.?
+    if (olf(x)) {
+      xAlign = 'center';
+      yAlign = yf(y);
+    }
+  } else if (rf(x)) {
+    xAlign = 'right';
+
+    // Is tooltip too wide and goes outside left edge of canvas?
+    if (orf(x)) {
+      xAlign = 'center';
+      yAlign = yf(y);
+    }
+  }
+
+  return {
+    xAlign: options.xAlign ? options.xAlign : xAlign,
+    yAlign: options.yAlign ? options.yAlign : yAlign
+  };
 }
 
 function alignX(size, xAlign, chartWidth) {
-       // eslint-disable-next-line prefer-const
-       let {x, width} = size;
-       if (xAlign === 'right') {
-               x -= width;
-       } else if (xAlign === 'center') {
-               x -= (width / 2);
-               if (x + width > chartWidth) {
-                       x = chartWidth - width;
-               }
-               if (x < 0) {
-                       x = 0;
-               }
-       }
-       return x;
+  // eslint-disable-next-line prefer-const
+  let {x, width} = size;
+  if (xAlign === 'right') {
+    x -= width;
+  } else if (xAlign === 'center') {
+    x -= (width / 2);
+    if (x + width > chartWidth) {
+      x = chartWidth - width;
+    }
+    if (x < 0) {
+      x = 0;
+    }
+  }
+  return x;
 }
 
 function alignY(size, yAlign, paddingAndSize) {
-       // eslint-disable-next-line prefer-const
-       let {y, height} = size;
-       if (yAlign === 'top') {
-               y += paddingAndSize;
-       } else if (yAlign === 'bottom') {
-               y -= height + paddingAndSize;
-       } else {
-               y -= (height / 2);
-       }
-       return y;
+  // eslint-disable-next-line prefer-const
+  let {y, height} = size;
+  if (yAlign === 'top') {
+    y += paddingAndSize;
+  } else if (yAlign === 'bottom') {
+    y -= height + paddingAndSize;
+  } else {
+    y -= (height / 2);
+  }
+  return y;
 }
 
 /**
  * Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
  */
 function getBackgroundPoint(options, size, alignment, chart) {
-       const {caretSize, caretPadding, cornerRadius} = options;
-       const {xAlign, yAlign} = alignment;
-       const paddingAndSize = caretSize + caretPadding;
-       const radiusAndPadding = cornerRadius + caretPadding;
-
-       let x = alignX(size, xAlign, chart.width);
-       const y = alignY(size, yAlign, paddingAndSize);
-
-       if (yAlign === 'center') {
-               if (xAlign === 'left') {
-                       x += paddingAndSize;
-               } else if (xAlign === 'right') {
-                       x -= paddingAndSize;
-               }
-       } else if (xAlign === 'left') {
-               x -= radiusAndPadding;
-       } else if (xAlign === 'right') {
-               x += radiusAndPadding;
-       }
-
-       return {x, y};
+  const {caretSize, caretPadding, cornerRadius} = options;
+  const {xAlign, yAlign} = alignment;
+  const paddingAndSize = caretSize + caretPadding;
+  const radiusAndPadding = cornerRadius + caretPadding;
+
+  let x = alignX(size, xAlign, chart.width);
+  const y = alignY(size, yAlign, paddingAndSize);
+
+  if (yAlign === 'center') {
+    if (xAlign === 'left') {
+      x += paddingAndSize;
+    } else if (xAlign === 'right') {
+      x -= paddingAndSize;
+    }
+  } else if (xAlign === 'left') {
+    x -= radiusAndPadding;
+  } else if (xAlign === 'right') {
+    x += radiusAndPadding;
+  }
+
+  return {x, y};
 }
 
 function getAlignedX(tooltip, align) {
-       const options = tooltip.options;
-       return align === 'center'
-               ? tooltip.x + tooltip.width / 2
-               : align === 'right'
-                       ? tooltip.x + tooltip.width - options.xPadding
-                       : tooltip.x + options.xPadding;
+  const options = tooltip.options;
+  return align === 'center'
+    ? tooltip.x + tooltip.width / 2
+    : align === 'right'
+      ? tooltip.x + tooltip.width - options.xPadding
+      : tooltip.x + options.xPadding;
 }
 
 /**
  * Helper to build before and after body lines
  */
 function getBeforeAfterBodyLines(callback) {
-       return pushOrConcat([], splitNewlines(callback));
+  return pushOrConcat([], splitNewlines(callback));
 }
 
 export class Tooltip extends Element {
-       constructor(config) {
-               super();
-
-               this.opacity = 0;
-               this._active = [];
-               this._chart = config._chart;
-               this._eventPosition = undefined;
-               this._size = undefined;
-               this._cachedAnimations = undefined;
-               this.$animations = undefined;
-               this.options = config.options;
-               this.dataPoints = undefined;
-               this.title = undefined;
-               this.beforeBody = undefined;
-               this.body = undefined;
-               this.afterBody = undefined;
-               this.footer = undefined;
-               this.xAlign = undefined;
-               this.yAlign = undefined;
-               this.x = undefined;
-               this.y = undefined;
-               this.height = undefined;
-               this.width = undefined;
-               this.caretX = undefined;
-               this.caretY = undefined;
-               this.labelColors = undefined;
-               this.labelPointStyles = undefined;
-               this.labelTextColors = undefined;
-       }
-
-       initialize(options) {
-               const defaultSize = options.bodyFont.size;
-               options.boxHeight = valueOrDefault(options.boxHeight, defaultSize);
-               options.boxWidth = valueOrDefault(options.boxWidth, defaultSize);
-               this.options = options;
-               this._cachedAnimations = undefined;
-       }
-
-       /**
+  constructor(config) {
+    super();
+
+    this.opacity = 0;
+    this._active = [];
+    this._chart = config._chart;
+    this._eventPosition = undefined;
+    this._size = undefined;
+    this._cachedAnimations = undefined;
+    this.$animations = undefined;
+    this.options = config.options;
+    this.dataPoints = undefined;
+    this.title = undefined;
+    this.beforeBody = undefined;
+    this.body = undefined;
+    this.afterBody = undefined;
+    this.footer = undefined;
+    this.xAlign = undefined;
+    this.yAlign = undefined;
+    this.x = undefined;
+    this.y = undefined;
+    this.height = undefined;
+    this.width = undefined;
+    this.caretX = undefined;
+    this.caretY = undefined;
+    this.labelColors = undefined;
+    this.labelPointStyles = undefined;
+    this.labelTextColors = undefined;
+  }
+
+  initialize(options) {
+    const defaultSize = options.bodyFont.size;
+    options.boxHeight = valueOrDefault(options.boxHeight, defaultSize);
+    options.boxWidth = valueOrDefault(options.boxWidth, defaultSize);
+    this.options = options;
+    this._cachedAnimations = undefined;
+  }
+
+  /**
         * @private
         */
-       _resolveAnimations() {
-               const me = this;
-               const cached = me._cachedAnimations;
-
-               if (cached) {
-                       return cached;
-               }
-
-               const chart = me._chart;
-               const options = me.options;
-               const opts = options.enabled && chart.options.animation && options.animation;
-               const animations = new Animations(me._chart, opts);
-               me._cachedAnimations = Object.freeze(animations);
-
-               return animations;
-       }
-
-       getTitle(context) {
-               const me = this;
-               const opts = me.options;
-               const callbacks = opts.callbacks;
-
-               const beforeTitle = callbacks.beforeTitle.apply(me, [context]);
-               const title = callbacks.title.apply(me, [context]);
-               const afterTitle = callbacks.afterTitle.apply(me, [context]);
-
-               let lines = [];
-               lines = pushOrConcat(lines, splitNewlines(beforeTitle));
-               lines = pushOrConcat(lines, splitNewlines(title));
-               lines = pushOrConcat(lines, splitNewlines(afterTitle));
-
-               return lines;
-       }
-
-       getBeforeBody(tooltipItems) {
-               return getBeforeAfterBodyLines(this.options.callbacks.beforeBody.apply(this, [tooltipItems]));
-       }
-
-       getBody(tooltipItems) {
-               const me = this;
-               const callbacks = me.options.callbacks;
-               const bodyItems = [];
-
-               each(tooltipItems, (context) => {
-                       const bodyItem = {
-                               before: [],
-                               lines: [],
-                               after: []
-                       };
-                       pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, context)));
-                       pushOrConcat(bodyItem.lines, callbacks.label.call(me, context));
-                       pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, context)));
-
-                       bodyItems.push(bodyItem);
-               });
-
-               return bodyItems;
-       }
-
-       getAfterBody(tooltipItems) {
-               return getBeforeAfterBodyLines(this.options.callbacks.afterBody.apply(this, [tooltipItems]));
-       }
-
-       // Get the footer and beforeFooter and afterFooter lines
-       getFooter(tooltipItems) {
-               const me = this;
-               const callbacks = me.options.callbacks;
-
-               const beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]);
-               const footer = callbacks.footer.apply(me, [tooltipItems]);
-               const afterFooter = callbacks.afterFooter.apply(me, [tooltipItems]);
-
-               let lines = [];
-               lines = pushOrConcat(lines, splitNewlines(beforeFooter));
-               lines = pushOrConcat(lines, splitNewlines(footer));
-               lines = pushOrConcat(lines, splitNewlines(afterFooter));
-
-               return lines;
-       }
-
-       /**
+  _resolveAnimations() {
+    const me = this;
+    const cached = me._cachedAnimations;
+
+    if (cached) {
+      return cached;
+    }
+
+    const chart = me._chart;
+    const options = me.options;
+    const opts = options.enabled && chart.options.animation && options.animation;
+    const animations = new Animations(me._chart, opts);
+    me._cachedAnimations = Object.freeze(animations);
+
+    return animations;
+  }
+
+  getTitle(context) {
+    const me = this;
+    const opts = me.options;
+    const callbacks = opts.callbacks;
+
+    const beforeTitle = callbacks.beforeTitle.apply(me, [context]);
+    const title = callbacks.title.apply(me, [context]);
+    const afterTitle = callbacks.afterTitle.apply(me, [context]);
+
+    let lines = [];
+    lines = pushOrConcat(lines, splitNewlines(beforeTitle));
+    lines = pushOrConcat(lines, splitNewlines(title));
+    lines = pushOrConcat(lines, splitNewlines(afterTitle));
+
+    return lines;
+  }
+
+  getBeforeBody(tooltipItems) {
+    return getBeforeAfterBodyLines(this.options.callbacks.beforeBody.apply(this, [tooltipItems]));
+  }
+
+  getBody(tooltipItems) {
+    const me = this;
+    const callbacks = me.options.callbacks;
+    const bodyItems = [];
+
+    each(tooltipItems, (context) => {
+      const bodyItem = {
+        before: [],
+        lines: [],
+        after: []
+      };
+      pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, context)));
+      pushOrConcat(bodyItem.lines, callbacks.label.call(me, context));
+      pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, context)));
+
+      bodyItems.push(bodyItem);
+    });
+
+    return bodyItems;
+  }
+
+  getAfterBody(tooltipItems) {
+    return getBeforeAfterBodyLines(this.options.callbacks.afterBody.apply(this, [tooltipItems]));
+  }
+
+  // Get the footer and beforeFooter and afterFooter lines
+  getFooter(tooltipItems) {
+    const me = this;
+    const callbacks = me.options.callbacks;
+
+    const beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]);
+    const footer = callbacks.footer.apply(me, [tooltipItems]);
+    const afterFooter = callbacks.afterFooter.apply(me, [tooltipItems]);
+
+    let lines = [];
+    lines = pushOrConcat(lines, splitNewlines(beforeFooter));
+    lines = pushOrConcat(lines, splitNewlines(footer));
+    lines = pushOrConcat(lines, splitNewlines(afterFooter));
+
+    return lines;
+  }
+
+  /**
         * @private
         */
-       _createItems() {
-               const me = this;
-               const active = me._active;
-               const options = me.options;
-               const data = me._chart.data;
-               const labelColors = [];
-               const labelPointStyles = [];
-               const labelTextColors = [];
-               let tooltipItems = [];
-               let i, len;
-
-               for (i = 0, len = active.length; i < len; ++i) {
-                       tooltipItems.push(createTooltipItem(me._chart, active[i]));
-               }
-
-               // If the user provided a filter function, use it to modify the tooltip items
-               if (options.filter) {
-                       tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));
-               }
-
-               // If the user provided a sorting function, use it to modify the tooltip items
-               if (options.itemSort) {
-                       tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data));
-               }
-
-               // Determine colors for boxes
-               each(tooltipItems, (context) => {
-                       labelColors.push(options.callbacks.labelColor.call(me, context));
-                       labelPointStyles.push(options.callbacks.labelPointStyle.call(me, context));
-                       labelTextColors.push(options.callbacks.labelTextColor.call(me, context));
-               });
-
-               me.labelColors = labelColors;
-               me.labelPointStyles = labelPointStyles;
-               me.labelTextColors = labelTextColors;
-               me.dataPoints = tooltipItems;
-               return tooltipItems;
-       }
-
-       update(changed) {
-               const me = this;
-               const options = me.options;
-               const active = me._active;
-               let properties;
-
-               if (!active.length) {
-                       if (me.opacity !== 0) {
-                               properties = {
-                                       opacity: 0
-                               };
-                       }
-               } else {
-                       const position = positioners[options.position].call(me, active, me._eventPosition);
-                       const tooltipItems = me._createItems();
-
-                       me.title = me.getTitle(tooltipItems);
-                       me.beforeBody = me.getBeforeBody(tooltipItems);
-                       me.body = me.getBody(tooltipItems);
-                       me.afterBody = me.getAfterBody(tooltipItems);
-                       me.footer = me.getFooter(tooltipItems);
-
-                       const size = me._size = getTooltipSize(me);
-                       const positionAndSize = Object.assign({}, position, size);
-                       const alignment = determineAlignment(me._chart, options, positionAndSize);
-                       const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart);
-
-                       me.xAlign = alignment.xAlign;
-                       me.yAlign = alignment.yAlign;
-
-                       properties = {
-                               opacity: 1,
-                               x: backgroundPoint.x,
-                               y: backgroundPoint.y,
-                               width: size.width,
-                               height: size.height,
-                               caretX: position.x,
-                               caretY: position.y
-                       };
-               }
-
-               if (properties) {
-                       me._resolveAnimations().update(me, properties);
-               }
-
-               if (changed && options.custom) {
-                       options.custom.call(me, {chart: me._chart, tooltip: me});
-               }
-       }
-
-       drawCaret(tooltipPoint, ctx, size) {
-               const caretPosition = this.getCaretPosition(tooltipPoint, size);
-
-               ctx.lineTo(caretPosition.x1, caretPosition.y1);
-               ctx.lineTo(caretPosition.x2, caretPosition.y2);
-               ctx.lineTo(caretPosition.x3, caretPosition.y3);
-       }
-
-       getCaretPosition(tooltipPoint, size) {
-               const {xAlign, yAlign, options} = this;
-               const {cornerRadius, caretSize} = options;
-               const {x: ptX, y: ptY} = tooltipPoint;
-               const {width, height} = size;
-               let x1, x2, x3, y1, y2, y3;
-
-               if (yAlign === 'center') {
-                       y2 = ptY + (height / 2);
-
-                       if (xAlign === 'left') {
-                               x1 = ptX;
-                               x2 = x1 - caretSize;
-
-                               // Left draws bottom -> top, this y1 is on the bottom
-                               y1 = y2 + caretSize;
-                               y3 = y2 - caretSize;
-                       } else {
-                               x1 = ptX + width;
-                               x2 = x1 + caretSize;
-
-                               // Right draws top -> bottom, thus y1 is on the top
-                               y1 = y2 - caretSize;
-                               y3 = y2 + caretSize;
-                       }
-
-                       x3 = x1;
-               } else {
-                       if (xAlign === 'left') {
-                               x2 = ptX + cornerRadius + (caretSize);
-                       } else if (xAlign === 'right') {
-                               x2 = ptX + width - cornerRadius - caretSize;
-                       } else {
-                               x2 = this.caretX;
-                       }
-
-                       if (yAlign === 'top') {
-                               y1 = ptY;
-                               y2 = y1 - caretSize;
-
-                               // Top draws left -> right, thus x1 is on the left
-                               x1 = x2 - caretSize;
-                               x3 = x2 + caretSize;
-                       } else {
-                               y1 = ptY + height;
-                               y2 = y1 + caretSize;
-
-                               // Bottom draws right -> left, thus x1 is on the right
-                               x1 = x2 + caretSize;
-                               x3 = x2 - caretSize;
-                       }
-                       y3 = y1;
-               }
-               return {x1, x2, x3, y1, y2, y3};
-       }
-
-       drawTitle(pt, ctx) {
-               const me = this;
-               const options = me.options;
-               const title = me.title;
-               const length = title.length;
-               let titleFont, titleSpacing, i;
-
-               if (length) {
-                       const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
-
-                       pt.x = getAlignedX(me, options.titleAlign);
-
-                       ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
-                       ctx.textBaseline = 'middle';
-
-                       titleFont = options.titleFont;
-                       titleSpacing = options.titleSpacing;
-
-                       ctx.fillStyle = options.titleColor;
-                       ctx.font = toFontString(titleFont);
-
-                       for (i = 0; i < length; ++i) {
-                               ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.size / 2);
-                               pt.y += titleFont.size + titleSpacing; // Line Height and spacing
-
-                               if (i + 1 === length) {
-                                       pt.y += options.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
-                               }
-                       }
-               }
-       }
-
-       /**
+  _createItems() {
+    const me = this;
+    const active = me._active;
+    const options = me.options;
+    const data = me._chart.data;
+    const labelColors = [];
+    const labelPointStyles = [];
+    const labelTextColors = [];
+    let tooltipItems = [];
+    let i, len;
+
+    for (i = 0, len = active.length; i < len; ++i) {
+      tooltipItems.push(createTooltipItem(me._chart, active[i]));
+    }
+
+    // If the user provided a filter function, use it to modify the tooltip items
+    if (options.filter) {
+      tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));
+    }
+
+    // If the user provided a sorting function, use it to modify the tooltip items
+    if (options.itemSort) {
+      tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data));
+    }
+
+    // Determine colors for boxes
+    each(tooltipItems, (context) => {
+      labelColors.push(options.callbacks.labelColor.call(me, context));
+      labelPointStyles.push(options.callbacks.labelPointStyle.call(me, context));
+      labelTextColors.push(options.callbacks.labelTextColor.call(me, context));
+    });
+
+    me.labelColors = labelColors;
+    me.labelPointStyles = labelPointStyles;
+    me.labelTextColors = labelTextColors;
+    me.dataPoints = tooltipItems;
+    return tooltipItems;
+  }
+
+  update(changed) {
+    const me = this;
+    const options = me.options;
+    const active = me._active;
+    let properties;
+
+    if (!active.length) {
+      if (me.opacity !== 0) {
+        properties = {
+          opacity: 0
+        };
+      }
+    } else {
+      const position = positioners[options.position].call(me, active, me._eventPosition);
+      const tooltipItems = me._createItems();
+
+      me.title = me.getTitle(tooltipItems);
+      me.beforeBody = me.getBeforeBody(tooltipItems);
+      me.body = me.getBody(tooltipItems);
+      me.afterBody = me.getAfterBody(tooltipItems);
+      me.footer = me.getFooter(tooltipItems);
+
+      const size = me._size = getTooltipSize(me);
+      const positionAndSize = Object.assign({}, position, size);
+      const alignment = determineAlignment(me._chart, options, positionAndSize);
+      const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart);
+
+      me.xAlign = alignment.xAlign;
+      me.yAlign = alignment.yAlign;
+
+      properties = {
+        opacity: 1,
+        x: backgroundPoint.x,
+        y: backgroundPoint.y,
+        width: size.width,
+        height: size.height,
+        caretX: position.x,
+        caretY: position.y
+      };
+    }
+
+    if (properties) {
+      me._resolveAnimations().update(me, properties);
+    }
+
+    if (changed && options.custom) {
+      options.custom.call(me, {chart: me._chart, tooltip: me});
+    }
+  }
+
+  drawCaret(tooltipPoint, ctx, size) {
+    const caretPosition = this.getCaretPosition(tooltipPoint, size);
+
+    ctx.lineTo(caretPosition.x1, caretPosition.y1);
+    ctx.lineTo(caretPosition.x2, caretPosition.y2);
+    ctx.lineTo(caretPosition.x3, caretPosition.y3);
+  }
+
+  getCaretPosition(tooltipPoint, size) {
+    const {xAlign, yAlign, options} = this;
+    const {cornerRadius, caretSize} = options;
+    const {x: ptX, y: ptY} = tooltipPoint;
+    const {width, height} = size;
+    let x1, x2, x3, y1, y2, y3;
+
+    if (yAlign === 'center') {
+      y2 = ptY + (height / 2);
+
+      if (xAlign === 'left') {
+        x1 = ptX;
+        x2 = x1 - caretSize;
+
+        // Left draws bottom -> top, this y1 is on the bottom
+        y1 = y2 + caretSize;
+        y3 = y2 - caretSize;
+      } else {
+        x1 = ptX + width;
+        x2 = x1 + caretSize;
+
+        // Right draws top -> bottom, thus y1 is on the top
+        y1 = y2 - caretSize;
+        y3 = y2 + caretSize;
+      }
+
+      x3 = x1;
+    } else {
+      if (xAlign === 'left') {
+        x2 = ptX + cornerRadius + (caretSize);
+      } else if (xAlign === 'right') {
+        x2 = ptX + width - cornerRadius - caretSize;
+      } else {
+        x2 = this.caretX;
+      }
+
+      if (yAlign === 'top') {
+        y1 = ptY;
+        y2 = y1 - caretSize;
+
+        // Top draws left -> right, thus x1 is on the left
+        x1 = x2 - caretSize;
+        x3 = x2 + caretSize;
+      } else {
+        y1 = ptY + height;
+        y2 = y1 + caretSize;
+
+        // Bottom draws right -> left, thus x1 is on the right
+        x1 = x2 + caretSize;
+        x3 = x2 - caretSize;
+      }
+      y3 = y1;
+    }
+    return {x1, x2, x3, y1, y2, y3};
+  }
+
+  drawTitle(pt, ctx) {
+    const me = this;
+    const options = me.options;
+    const title = me.title;
+    const length = title.length;
+    let titleFont, titleSpacing, i;
+
+    if (length) {
+      const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
+
+      pt.x = getAlignedX(me, options.titleAlign);
+
+      ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
+      ctx.textBaseline = 'middle';
+
+      titleFont = options.titleFont;
+      titleSpacing = options.titleSpacing;
+
+      ctx.fillStyle = options.titleColor;
+      ctx.font = toFontString(titleFont);
+
+      for (i = 0; i < length; ++i) {
+        ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.size / 2);
+        pt.y += titleFont.size + titleSpacing; // Line Height and spacing
+
+        if (i + 1 === length) {
+          pt.y += options.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
+        }
+      }
+    }
+  }
+
+  /**
         * @private
         */
-       _drawColorBox(ctx, pt, i, rtlHelper) {
-               const me = this;
-               const options = me.options;
-               const labelColors = me.labelColors[i];
-               const labelPointStyle = me.labelPointStyles[i];
-               const {boxHeight, boxWidth, bodyFont} = options;
-               const colorX = getAlignedX(me, 'left');
-               const rtlColorX = rtlHelper.x(colorX);
-               const yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0;
-               const colorY = pt.y + yOffSet;
-
-               if (options.usePointStyle) {
-                       const drawOptions = {
-                               radius: Math.min(boxWidth, boxHeight) / 2, // fit the circle in the box
-                               pointStyle: labelPointStyle.pointStyle,
-                               rotation: labelPointStyle.rotation,
-                               borderWidth: 1
-                       };
-                       // Recalculate x and y for drawPoint() because its expecting
-                       // x and y to be center of figure (instead of top left)
-                       const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
-                       const centerY = colorY + boxHeight / 2;
-
-                       // Fill the point with white so that colours merge nicely if the opacity is < 1
-                       ctx.strokeStyle = options.multiKeyBackground;
-                       ctx.fillStyle = options.multiKeyBackground;
-                       drawPoint(ctx, drawOptions, centerX, centerY);
-
-                       // Draw the point
-                       ctx.strokeStyle = labelColors.borderColor;
-                       ctx.fillStyle = labelColors.backgroundColor;
-                       drawPoint(ctx, drawOptions, centerX, centerY);
-               } else {
-                       // Fill a white rect so that colours merge nicely if the opacity is < 1
-                       ctx.fillStyle = options.multiKeyBackground;
-                       ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight);
-
-                       // Border
-                       ctx.lineWidth = 1;
-                       ctx.strokeStyle = labelColors.borderColor;
-                       ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight);
-
-                       // Inner square
-                       ctx.fillStyle = labelColors.backgroundColor;
-                       ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2), colorY + 1, boxWidth - 2, boxHeight - 2);
-               }
-
-               // restore fillStyle
-               ctx.fillStyle = me.labelTextColors[i];
-       }
-
-       drawBody(pt, ctx) {
-               const me = this;
-               const {body, options} = me;
-               const {bodyFont, bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options;
-               let bodyLineHeight = bodyFont.size;
-               let xLinePadding = 0;
-
-               const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
-
-               const fillLineOfText = function(line) {
-                       ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
-                       pt.y += bodyLineHeight + bodySpacing;
-               };
-
-               const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
-               let bodyItem, textColor, lines, i, j, ilen, jlen;
-
-               ctx.textAlign = bodyAlign;
-               ctx.textBaseline = 'middle';
-               ctx.font = toFontString(bodyFont);
-
-               pt.x = getAlignedX(me, bodyAlignForCalculation);
-
-               // Before body lines
-               ctx.fillStyle = options.bodyColor;
-               each(me.beforeBody, fillLineOfText);
-
-               xLinePadding = displayColors && bodyAlignForCalculation !== 'right'
-                       ? bodyAlign === 'center' ? (boxWidth / 2 + 1) : (boxWidth + 2)
-                       : 0;
-
-               // Draw body lines now
-               for (i = 0, ilen = body.length; i < ilen; ++i) {
-                       bodyItem = body[i];
-                       textColor = me.labelTextColors[i];
-
-                       ctx.fillStyle = textColor;
-                       each(bodyItem.before, fillLineOfText);
-
-                       lines = bodyItem.lines;
-                       // Draw Legend-like boxes if needed
-                       if (displayColors && lines.length) {
-                               me._drawColorBox(ctx, pt, i, rtlHelper);
-                               bodyLineHeight = Math.max(bodyFont.size, boxHeight);
-                       }
-
-                       for (j = 0, jlen = lines.length; j < jlen; ++j) {
-                               fillLineOfText(lines[j]);
-                               // Reset for any lines that don't include colorbox
-                               bodyLineHeight = bodyFont.size;
-                       }
-
-                       each(bodyItem.after, fillLineOfText);
-               }
-
-               // Reset back to 0 for after body
-               xLinePadding = 0;
-               bodyLineHeight = bodyFont.size;
-
-               // After body lines
-               each(me.afterBody, fillLineOfText);
-               pt.y -= bodySpacing; // Remove last body spacing
-       }
-
-       drawFooter(pt, ctx) {
-               const me = this;
-               const options = me.options;
-               const footer = me.footer;
-               const length = footer.length;
-               let footerFont, i;
-
-               if (length) {
-                       const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
-
-                       pt.x = getAlignedX(me, options.footerAlign);
-                       pt.y += options.footerMarginTop;
-
-                       ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
-                       ctx.textBaseline = 'middle';
-
-                       footerFont = options.footerFont;
-
-                       ctx.fillStyle = options.footerColor;
-                       ctx.font = toFontString(footerFont);
-
-                       for (i = 0; i < length; ++i) {
-                               ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.size / 2);
-                               pt.y += footerFont.size + options.footerSpacing;
-                       }
-               }
-       }
-
-       drawBackground(pt, ctx, tooltipSize) {
-               const {xAlign, yAlign, options} = this;
-               const {x, y} = pt;
-               const {width, height} = tooltipSize;
-               const radius = options.cornerRadius;
-
-               ctx.fillStyle = options.backgroundColor;
-               ctx.strokeStyle = options.borderColor;
-               ctx.lineWidth = options.borderWidth;
-
-               ctx.beginPath();
-               ctx.moveTo(x + radius, y);
-               if (yAlign === 'top') {
-                       this.drawCaret(pt, ctx, tooltipSize);
-               }
-               ctx.lineTo(x + width - radius, y);
-               ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
-               if (yAlign === 'center' && xAlign === 'right') {
-                       this.drawCaret(pt, ctx, tooltipSize);
-               }
-               ctx.lineTo(x + width, y + height - radius);
-               ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
-               if (yAlign === 'bottom') {
-                       this.drawCaret(pt, ctx, tooltipSize);
-               }
-               ctx.lineTo(x + radius, y + height);
-               ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
-               if (yAlign === 'center' && xAlign === 'left') {
-                       this.drawCaret(pt, ctx, tooltipSize);
-               }
-               ctx.lineTo(x, y + radius);
-               ctx.quadraticCurveTo(x, y, x + radius, y);
-               ctx.closePath();
-
-               ctx.fill();
-
-               if (options.borderWidth > 0) {
-                       ctx.stroke();
-               }
-       }
-
-       /**
+  _drawColorBox(ctx, pt, i, rtlHelper) {
+    const me = this;
+    const options = me.options;
+    const labelColors = me.labelColors[i];
+    const labelPointStyle = me.labelPointStyles[i];
+    const {boxHeight, boxWidth, bodyFont} = options;
+    const colorX = getAlignedX(me, 'left');
+    const rtlColorX = rtlHelper.x(colorX);
+    const yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0;
+    const colorY = pt.y + yOffSet;
+
+    if (options.usePointStyle) {
+      const drawOptions = {
+        radius: Math.min(boxWidth, boxHeight) / 2, // fit the circle in the box
+        pointStyle: labelPointStyle.pointStyle,
+        rotation: labelPointStyle.rotation,
+        borderWidth: 1
+      };
+      // Recalculate x and y for drawPoint() because its expecting
+      // x and y to be center of figure (instead of top left)
+      const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
+      const centerY = colorY + boxHeight / 2;
+
+      // Fill the point with white so that colours merge nicely if the opacity is < 1
+      ctx.strokeStyle = options.multiKeyBackground;
+      ctx.fillStyle = options.multiKeyBackground;
+      drawPoint(ctx, drawOptions, centerX, centerY);
+
+      // Draw the point
+      ctx.strokeStyle = labelColors.borderColor;
+      ctx.fillStyle = labelColors.backgroundColor;
+      drawPoint(ctx, drawOptions, centerX, centerY);
+    } else {
+      // Fill a white rect so that colours merge nicely if the opacity is < 1
+      ctx.fillStyle = options.multiKeyBackground;
+      ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight);
+
+      // Border
+      ctx.lineWidth = 1;
+      ctx.strokeStyle = labelColors.borderColor;
+      ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight);
+
+      // Inner square
+      ctx.fillStyle = labelColors.backgroundColor;
+      ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2), colorY + 1, boxWidth - 2, boxHeight - 2);
+    }
+
+    // restore fillStyle
+    ctx.fillStyle = me.labelTextColors[i];
+  }
+
+  drawBody(pt, ctx) {
+    const me = this;
+    const {body, options} = me;
+    const {bodyFont, bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options;
+    let bodyLineHeight = bodyFont.size;
+    let xLinePadding = 0;
+
+    const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
+
+    const fillLineOfText = function(line) {
+      ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
+      pt.y += bodyLineHeight + bodySpacing;
+    };
+
+    const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
+    let bodyItem, textColor, lines, i, j, ilen, jlen;
+
+    ctx.textAlign = bodyAlign;
+    ctx.textBaseline = 'middle';
+    ctx.font = toFontString(bodyFont);
+
+    pt.x = getAlignedX(me, bodyAlignForCalculation);
+
+    // Before body lines
+    ctx.fillStyle = options.bodyColor;
+    each(me.beforeBody, fillLineOfText);
+
+    xLinePadding = displayColors && bodyAlignForCalculation !== 'right'
+      ? bodyAlign === 'center' ? (boxWidth / 2 + 1) : (boxWidth + 2)
+      : 0;
+
+    // Draw body lines now
+    for (i = 0, ilen = body.length; i < ilen; ++i) {
+      bodyItem = body[i];
+      textColor = me.labelTextColors[i];
+
+      ctx.fillStyle = textColor;
+      each(bodyItem.before, fillLineOfText);
+
+      lines = bodyItem.lines;
+      // Draw Legend-like boxes if needed
+      if (displayColors && lines.length) {
+        me._drawColorBox(ctx, pt, i, rtlHelper);
+        bodyLineHeight = Math.max(bodyFont.size, boxHeight);
+      }
+
+      for (j = 0, jlen = lines.length; j < jlen; ++j) {
+        fillLineOfText(lines[j]);
+        // Reset for any lines that don't include colorbox
+        bodyLineHeight = bodyFont.size;
+      }
+
+      each(bodyItem.after, fillLineOfText);
+    }
+
+    // Reset back to 0 for after body
+    xLinePadding = 0;
+    bodyLineHeight = bodyFont.size;
+
+    // After body lines
+    each(me.afterBody, fillLineOfText);
+    pt.y -= bodySpacing; // Remove last body spacing
+  }
+
+  drawFooter(pt, ctx) {
+    const me = this;
+    const options = me.options;
+    const footer = me.footer;
+    const length = footer.length;
+    let footerFont, i;
+
+    if (length) {
+      const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
+
+      pt.x = getAlignedX(me, options.footerAlign);
+      pt.y += options.footerMarginTop;
+
+      ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
+      ctx.textBaseline = 'middle';
+
+      footerFont = options.footerFont;
+
+      ctx.fillStyle = options.footerColor;
+      ctx.font = toFontString(footerFont);
+
+      for (i = 0; i < length; ++i) {
+        ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.size / 2);
+        pt.y += footerFont.size + options.footerSpacing;
+      }
+    }
+  }
+
+  drawBackground(pt, ctx, tooltipSize) {
+    const {xAlign, yAlign, options} = this;
+    const {x, y} = pt;
+    const {width, height} = tooltipSize;
+    const radius = options.cornerRadius;
+
+    ctx.fillStyle = options.backgroundColor;
+    ctx.strokeStyle = options.borderColor;
+    ctx.lineWidth = options.borderWidth;
+
+    ctx.beginPath();
+    ctx.moveTo(x + radius, y);
+    if (yAlign === 'top') {
+      this.drawCaret(pt, ctx, tooltipSize);
+    }
+    ctx.lineTo(x + width - radius, y);
+    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+    if (yAlign === 'center' && xAlign === 'right') {
+      this.drawCaret(pt, ctx, tooltipSize);
+    }
+    ctx.lineTo(x + width, y + height - radius);
+    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+    if (yAlign === 'bottom') {
+      this.drawCaret(pt, ctx, tooltipSize);
+    }
+    ctx.lineTo(x + radius, y + height);
+    ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+    if (yAlign === 'center' && xAlign === 'left') {
+      this.drawCaret(pt, ctx, tooltipSize);
+    }
+    ctx.lineTo(x, y + radius);
+    ctx.quadraticCurveTo(x, y, x + radius, y);
+    ctx.closePath();
+
+    ctx.fill();
+
+    if (options.borderWidth > 0) {
+      ctx.stroke();
+    }
+  }
+
+  /**
         * Update x/y animation targets when _active elements are animating too
         * @private
         */
-       _updateAnimationTarget() {
-               const me = this;
-               const chart = me._chart;
-               const options = me.options;
-               const anims = me.$animations;
-               const animX = anims && anims.x;
-               const animY = anims && anims.y;
-               if (animX || animY) {
-                       const position = positioners[options.position].call(me, me._active, me._eventPosition);
-                       if (!position) {
-                               return;
-                       }
-                       const size = me._size = getTooltipSize(me);
-                       const positionAndSize = Object.assign({}, position, me._size);
-                       const alignment = determineAlignment(chart, options, positionAndSize);
-                       const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
-                       if (animX._to !== point.x || animY._to !== point.y) {
-                               me.xAlign = alignment.xAlign;
-                               me.yAlign = alignment.yAlign;
-                               me.width = size.width;
-                               me.height = size.height;
-                               me.caretX = position.x;
-                               me.caretY = position.y;
-                               me._resolveAnimations().update(me, point);
-                       }
-               }
-       }
-
-       draw(ctx) {
-               const me = this;
-               const options = me.options;
-               let opacity = me.opacity;
-
-               if (!opacity) {
-                       return;
-               }
-
-               me._updateAnimationTarget();
-
-               const tooltipSize = {
-                       width: me.width,
-                       height: me.height
-               };
-               const pt = {
-                       x: me.x,
-                       y: me.y
-               };
-
-               // IE11/Edge does not like very small opacities, so snap to 0
-               opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
-
-               // Truthy/falsey value for empty tooltip
-               const hasTooltipContent = me.title.length || me.beforeBody.length || me.body.length || me.afterBody.length || me.footer.length;
-
-               if (options.enabled && hasTooltipContent) {
-                       ctx.save();
-                       ctx.globalAlpha = opacity;
-
-                       // Draw Background
-                       me.drawBackground(pt, ctx, tooltipSize);
-
-                       overrideTextDirection(ctx, options.textDirection);
-
-                       pt.y += options.yPadding;
-
-                       // Titles
-                       me.drawTitle(pt, ctx);
-
-                       // Body
-                       me.drawBody(pt, ctx);
-
-                       // Footer
-                       me.drawFooter(pt, ctx);
-
-                       restoreTextDirection(ctx, options.textDirection);
-
-                       ctx.restore();
-               }
-       }
-
-       /**
+  _updateAnimationTarget() {
+    const me = this;
+    const chart = me._chart;
+    const options = me.options;
+    const anims = me.$animations;
+    const animX = anims && anims.x;
+    const animY = anims && anims.y;
+    if (animX || animY) {
+      const position = positioners[options.position].call(me, me._active, me._eventPosition);
+      if (!position) {
+        return;
+      }
+      const size = me._size = getTooltipSize(me);
+      const positionAndSize = Object.assign({}, position, me._size);
+      const alignment = determineAlignment(chart, options, positionAndSize);
+      const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
+      if (animX._to !== point.x || animY._to !== point.y) {
+        me.xAlign = alignment.xAlign;
+        me.yAlign = alignment.yAlign;
+        me.width = size.width;
+        me.height = size.height;
+        me.caretX = position.x;
+        me.caretY = position.y;
+        me._resolveAnimations().update(me, point);
+      }
+    }
+  }
+
+  draw(ctx) {
+    const me = this;
+    const options = me.options;
+    let opacity = me.opacity;
+
+    if (!opacity) {
+      return;
+    }
+
+    me._updateAnimationTarget();
+
+    const tooltipSize = {
+      width: me.width,
+      height: me.height
+    };
+    const pt = {
+      x: me.x,
+      y: me.y
+    };
+
+    // IE11/Edge does not like very small opacities, so snap to 0
+    opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
+
+    // Truthy/falsey value for empty tooltip
+    const hasTooltipContent = me.title.length || me.beforeBody.length || me.body.length || me.afterBody.length || me.footer.length;
+
+    if (options.enabled && hasTooltipContent) {
+      ctx.save();
+      ctx.globalAlpha = opacity;
+
+      // Draw Background
+      me.drawBackground(pt, ctx, tooltipSize);
+
+      overrideTextDirection(ctx, options.textDirection);
+
+      pt.y += options.yPadding;
+
+      // Titles
+      me.drawTitle(pt, ctx);
+
+      // Body
+      me.drawBody(pt, ctx);
+
+      // Footer
+      me.drawFooter(pt, ctx);
+
+      restoreTextDirection(ctx, options.textDirection);
+
+      ctx.restore();
+    }
+  }
+
+  /**
         * Get active elements in the tooltip
         * @returns {Array} Array of elements that are active in the tooltip
         */
-       getActiveElements() {
-               return this._active || [];
-       }
+  getActiveElements() {
+    return this._active || [];
+  }
 
-       /**
+  /**
         * Set active elements in the tooltip
         * @param {array} activeElements Array of active datasetIndex/index pairs.
         * @param {object} eventPosition Synthetic event position used in positioning
         */
-       setActiveElements(activeElements, eventPosition) {
-               const me = this;
-               const lastActive = me._active;
-               const active = activeElements.map(({datasetIndex, index}) => {
-                       const meta = me._chart.getDatasetMeta(datasetIndex);
-
-                       if (!meta) {
-                               throw new Error('Cannot find a dataset at index ' + datasetIndex);
-                       }
-
-                       return {
-                               datasetIndex,
-                               element: meta.data[index],
-                               index,
-                       };
-               });
-               const changed = !_elementsEqual(lastActive, active);
-               const positionChanged = me._positionChanged(active, eventPosition);
-
-               if (changed || positionChanged) {
-                       me._active = active;
-                       me._eventPosition = eventPosition;
-                       me.update(true);
-               }
-       }
-
-       /**
+  setActiveElements(activeElements, eventPosition) {
+    const me = this;
+    const lastActive = me._active;
+    const active = activeElements.map(({datasetIndex, index}) => {
+      const meta = me._chart.getDatasetMeta(datasetIndex);
+
+      if (!meta) {
+        throw new Error('Cannot find a dataset at index ' + datasetIndex);
+      }
+
+      return {
+        datasetIndex,
+        element: meta.data[index],
+        index,
+      };
+    });
+    const changed = !_elementsEqual(lastActive, active);
+    const positionChanged = me._positionChanged(active, eventPosition);
+
+    if (changed || positionChanged) {
+      me._active = active;
+      me._eventPosition = eventPosition;
+      me.update(true);
+    }
+  }
+
+  /**
         * Handle an event
         * @param {ChartEvent} e - The event to handle
         * @param {boolean} [replay] - This is a replayed event (from update)
         * @returns {boolean} true if the tooltip changed
         */
-       handleEvent(e, replay) {
-               const me = this;
-               const options = me.options;
-               const lastActive = me._active || [];
-               let changed = false;
-               let active = [];
-
-               // Find Active Elements for tooltips
-               if (e.type !== 'mouseout') {
-                       active = me._chart.getElementsAtEventForMode(e, options.mode, options, replay);
-                       if (options.reverse) {
-                               active.reverse();
-                       }
-               }
-
-               // When there are multiple items shown, but the tooltip position is nearest mode
-               // an update may need to be made because our position may have changed even though
-               // the items are the same as before.
-               const positionChanged = me._positionChanged(active, e);
-
-               // Remember Last Actives
-               changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
-
-               // Only handle target event on tooltip change
-               if (changed) {
-                       me._active = active;
-
-                       if (options.enabled || options.custom) {
-                               me._eventPosition = {
-                                       x: e.x,
-                                       y: e.y
-                               };
-
-                               me.update(true);
-                       }
-               }
-
-               return changed;
-       }
-
-       /**
+  handleEvent(e, replay) {
+    const me = this;
+    const options = me.options;
+    const lastActive = me._active || [];
+    let changed = false;
+    let active = [];
+
+    // Find Active Elements for tooltips
+    if (e.type !== 'mouseout') {
+      active = me._chart.getElementsAtEventForMode(e, options.mode, options, replay);
+      if (options.reverse) {
+        active.reverse();
+      }
+    }
+
+    // When there are multiple items shown, but the tooltip position is nearest mode
+    // an update may need to be made because our position may have changed even though
+    // the items are the same as before.
+    const positionChanged = me._positionChanged(active, e);
+
+    // Remember Last Actives
+    changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
+
+    // Only handle target event on tooltip change
+    if (changed) {
+      me._active = active;
+
+      if (options.enabled || options.custom) {
+        me._eventPosition = {
+          x: e.x,
+          y: e.y
+        };
+
+        me.update(true);
+      }
+    }
+
+    return changed;
+  }
+
+  /**
         * Determine if the active elements + event combination changes the
         * tooltip position
         * @param {array} active - Active elements
         * @param {ChartEvent} e - Event that triggered the position change
         * @returns {boolean} True if the position has changed
         */
-       _positionChanged(active, e) {
-               const me = this;
-               const position = positioners[me.options.position].call(me, active, e);
-               return me.caretX !== position.x || me.caretY !== position.y;
-       }
+  _positionChanged(active, e) {
+    const me = this;
+    const position = positioners[me.options.position].call(me, active, e);
+    return me.caretX !== position.x || me.caretY !== position.y;
+  }
 }
 
 /**
@@ -1022,179 +1022,179 @@ export class Tooltip extends Element {
 Tooltip.positioners = positioners;
 
 export default {
-       id: 'tooltip',
-       _element: Tooltip,
-       positioners,
-
-       afterInit(chart, _args, options) {
-               if (options) {
-                       chart.tooltip = new Tooltip({_chart: chart, options});
-               }
-       },
-
-       beforeUpdate(chart, _args, options) {
-               if (chart.tooltip) {
-                       chart.tooltip.initialize(options);
-               }
-       },
-
-       reset(chart, _args, options) {
-               if (chart.tooltip) {
-                       chart.tooltip.initialize(options);
-               }
-       },
-
-       afterDraw(chart) {
-               const tooltip = chart.tooltip;
-
-               const args = {
-                       tooltip
-               };
-
-               if (chart.notifyPlugins('beforeTooltipDraw', args) === false) {
-                       return;
-               }
-
-               if (tooltip) {
-                       tooltip.draw(chart.ctx);
-               }
-
-               chart.notifyPlugins('afterTooltipDraw', args);
-       },
-
-       afterEvent(chart, args) {
-               if (chart.tooltip) {
-                       // If the event is replayed from `update`, we should evaluate with the final positions.
-                       const useFinalPosition = args.replay;
-                       if (chart.tooltip.handleEvent(args.event, useFinalPosition)) {
-                               // notify chart about the change, so it will render
-                               args.changed = true;
-                       }
-               }
-       },
-
-       defaults: {
-               enabled: true,
-               custom: null,
-               position: 'average',
-               backgroundColor: 'rgba(0,0,0,0.8)',
-               titleColor: '#fff',
-               titleFont: {
-                       style: 'bold',
-               },
-               titleSpacing: 2,
-               titleMarginBottom: 6,
-               titleAlign: 'left',
-               bodyColor: '#fff',
-               bodySpacing: 2,
-               bodyFont: {
-               },
-               bodyAlign: 'left',
-               footerColor: '#fff',
-               footerSpacing: 2,
-               footerMarginTop: 6,
-               footerFont: {
-                       style: 'bold',
-               },
-               footerAlign: 'left',
-               yPadding: 6,
-               xPadding: 6,
-               caretPadding: 2,
-               caretSize: 5,
-               cornerRadius: 6,
-               multiKeyBackground: '#fff',
-               displayColors: true,
-               borderColor: 'rgba(0,0,0,0)',
-               borderWidth: 0,
-               animation: {
-                       duration: 400,
-                       easing: 'easeOutQuart',
-                       numbers: {
-                               type: 'number',
-                               properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'],
-                       },
-                       opacity: {
-                               easing: 'linear',
-                               duration: 200
-                       }
-               },
-               callbacks: {
-                       // Args are: (tooltipItems, data)
-                       beforeTitle: noop,
-                       title(tooltipItems) {
-                               if (tooltipItems.length > 0) {
-                                       const item = tooltipItems[0];
-                                       const labels = item.chart.data.labels;
-                                       const labelCount = labels ? labels.length : 0;
-
-                                       if (this && this.options && this.options.mode === 'dataset') {
-                                               return item.dataset.label || '';
-                                       } else if (item.label) {
-                                               return item.label;
-                                       } else if (labelCount > 0 && item.dataIndex < labelCount) {
-                                               return labels[item.dataIndex];
-                                       }
-                               }
-
-                               return '';
-                       },
-                       afterTitle: noop,
-
-                       // Args are: (tooltipItems, data)
-                       beforeBody: noop,
-
-                       // Args are: (tooltipItem, data)
-                       beforeLabel: noop,
-                       label(tooltipItem) {
-                               if (this && this.options && this.options.mode === 'dataset') {
-                                       return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
-                               }
-
-                               let label = tooltipItem.dataset.label || '';
-
-                               if (label) {
-                                       label += ': ';
-                               }
-                               const value = tooltipItem.formattedValue;
-                               if (!isNullOrUndef(value)) {
-                                       label += value;
-                               }
-                               return label;
-                       },
-                       labelColor(tooltipItem) {
-                               const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
-                               const options = meta.controller.getStyle(tooltipItem.dataIndex);
-                               return {
-                                       borderColor: options.borderColor,
-                                       backgroundColor: options.backgroundColor
-                               };
-                       },
-                       labelTextColor() {
-                               return this.options.bodyColor;
-                       },
-                       labelPointStyle(tooltipItem) {
-                               const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
-                               const options = meta.controller.getStyle(tooltipItem.dataIndex);
-                               return {
-                                       pointStyle: options.pointStyle,
-                                       rotation: options.rotation,
-                               };
-                       },
-                       afterLabel: noop,
-
-                       // Args are: (tooltipItems, data)
-                       afterBody: noop,
-
-                       // Args are: (tooltipItems, data)
-                       beforeFooter: noop,
-                       footer: noop,
-                       afterFooter: noop
-               }
-       },
-
-       defaultRoutes: {
-               bodyFont: 'font',
-               footerFont: 'font',
-               titleFont: 'font'
-       }
+  id: 'tooltip',
+  _element: Tooltip,
+  positioners,
+
+  afterInit(chart, _args, options) {
+    if (options) {
+      chart.tooltip = new Tooltip({_chart: chart, options});
+    }
+  },
+
+  beforeUpdate(chart, _args, options) {
+    if (chart.tooltip) {
+      chart.tooltip.initialize(options);
+    }
+  },
+
+  reset(chart, _args, options) {
+    if (chart.tooltip) {
+      chart.tooltip.initialize(options);
+    }
+  },
+
+  afterDraw(chart) {
+    const tooltip = chart.tooltip;
+
+    const args = {
+      tooltip
+    };
+
+    if (chart.notifyPlugins('beforeTooltipDraw', args) === false) {
+      return;
+    }
+
+    if (tooltip) {
+      tooltip.draw(chart.ctx);
+    }
+
+    chart.notifyPlugins('afterTooltipDraw', args);
+  },
+
+  afterEvent(chart, args) {
+    if (chart.tooltip) {
+      // If the event is replayed from `update`, we should evaluate with the final positions.
+      const useFinalPosition = args.replay;
+      if (chart.tooltip.handleEvent(args.event, useFinalPosition)) {
+        // notify chart about the change, so it will render
+        args.changed = true;
+      }
+    }
+  },
+
+  defaults: {
+    enabled: true,
+    custom: null,
+    position: 'average',
+    backgroundColor: 'rgba(0,0,0,0.8)',
+    titleColor: '#fff',
+    titleFont: {
+      style: 'bold',
+    },
+    titleSpacing: 2,
+    titleMarginBottom: 6,
+    titleAlign: 'left',
+    bodyColor: '#fff',
+    bodySpacing: 2,
+    bodyFont: {
+    },
+    bodyAlign: 'left',
+    footerColor: '#fff',
+    footerSpacing: 2,
+    footerMarginTop: 6,
+    footerFont: {
+      style: 'bold',
+    },
+    footerAlign: 'left',
+    yPadding: 6,
+    xPadding: 6,
+    caretPadding: 2,
+    caretSize: 5,
+    cornerRadius: 6,
+    multiKeyBackground: '#fff',
+    displayColors: true,
+    borderColor: 'rgba(0,0,0,0)',
+    borderWidth: 0,
+    animation: {
+      duration: 400,
+      easing: 'easeOutQuart',
+      numbers: {
+        type: 'number',
+        properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'],
+      },
+      opacity: {
+        easing: 'linear',
+        duration: 200
+      }
+    },
+    callbacks: {
+      // Args are: (tooltipItems, data)
+      beforeTitle: noop,
+      title(tooltipItems) {
+        if (tooltipItems.length > 0) {
+          const item = tooltipItems[0];
+          const labels = item.chart.data.labels;
+          const labelCount = labels ? labels.length : 0;
+
+          if (this && this.options && this.options.mode === 'dataset') {
+            return item.dataset.label || '';
+          } else if (item.label) {
+            return item.label;
+          } else if (labelCount > 0 && item.dataIndex < labelCount) {
+            return labels[item.dataIndex];
+          }
+        }
+
+        return '';
+      },
+      afterTitle: noop,
+
+      // Args are: (tooltipItems, data)
+      beforeBody: noop,
+
+      // Args are: (tooltipItem, data)
+      beforeLabel: noop,
+      label(tooltipItem) {
+        if (this && this.options && this.options.mode === 'dataset') {
+          return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
+        }
+
+        let label = tooltipItem.dataset.label || '';
+
+        if (label) {
+          label += ': ';
+        }
+        const value = tooltipItem.formattedValue;
+        if (!isNullOrUndef(value)) {
+          label += value;
+        }
+        return label;
+      },
+      labelColor(tooltipItem) {
+        const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+        const options = meta.controller.getStyle(tooltipItem.dataIndex);
+        return {
+          borderColor: options.borderColor,
+          backgroundColor: options.backgroundColor
+        };
+      },
+      labelTextColor() {
+        return this.options.bodyColor;
+      },
+      labelPointStyle(tooltipItem) {
+        const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+        const options = meta.controller.getStyle(tooltipItem.dataIndex);
+        return {
+          pointStyle: options.pointStyle,
+          rotation: options.rotation,
+        };
+      },
+      afterLabel: noop,
+
+      // Args are: (tooltipItems, data)
+      afterBody: noop,
+
+      // Args are: (tooltipItems, data)
+      beforeFooter: noop,
+      footer: noop,
+      afterFooter: noop
+    }
+  },
+
+  defaultRoutes: {
+    bodyFont: 'font',
+    footerFont: 'font',
+    titleFont: 'font'
+  }
 };
index 6c06719e8479c31b98f3ab488fd2b8fe99938591..868b24b5c810e1ff8fb02464c1b8e24d27689133 100644 (file)
 import Scale from '../core/core.scale';
 
 function findOrAddLabel(labels, raw, index) {
-       const first = labels.indexOf(raw);
-       if (first === -1) {
-               return typeof raw === 'string' ? labels.push(raw) - 1 : index;
-       }
-       const last = labels.lastIndexOf(raw);
-       return first !== last ? index : first;
+  const first = labels.indexOf(raw);
+  if (first === -1) {
+    return typeof raw === 'string' ? labels.push(raw) - 1 : index;
+  }
+  const last = labels.lastIndexOf(raw);
+  return first !== last ? index : first;
 }
 
 export default class CategoryScale extends Scale {
 
-       constructor(cfg) {
-               super(cfg);
-
-               /** @type {number} */
-               this._startValue = undefined;
-               this._valueRange = 0;
-       }
-
-       parse(raw, index) {
-               const labels = this.getLabels();
-               return isFinite(index) && labels[index] === raw
-                       ? index : findOrAddLabel(labels, raw, index);
-       }
-
-       determineDataLimits() {
-               const me = this;
-               const {minDefined, maxDefined} = me.getUserBounds();
-               let {min, max} = me.getMinMax(true);
-
-               if (me.options.bounds === 'ticks') {
-                       if (!minDefined) {
-                               min = 0;
-                       }
-                       if (!maxDefined) {
-                               max = me.getLabels().length - 1;
-                       }
-               }
-
-               me.min = min;
-               me.max = max;
-       }
-
-       buildTicks() {
-               const me = this;
-               const min = me.min;
-               const max = me.max;
-               const offset = me.options.offset;
-               const ticks = [];
-               let labels = me.getLabels();
-
-               // If we are viewing some subset of labels, slice the original array
-               labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1);
-
-               me._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
-               me._startValue = me.min - (offset ? 0.5 : 0);
-
-               for (let value = min; value <= max; value++) {
-                       ticks.push({value});
-               }
-               return ticks;
-       }
-
-       getLabelForValue(value) {
-               const me = this;
-               const labels = me.getLabels();
-
-               if (value >= 0 && value < labels.length) {
-                       return labels[value];
-               }
-               return value;
-       }
-
-       /**
+  constructor(cfg) {
+    super(cfg);
+
+    /** @type {number} */
+    this._startValue = undefined;
+    this._valueRange = 0;
+  }
+
+  parse(raw, index) {
+    const labels = this.getLabels();
+    return isFinite(index) && labels[index] === raw
+      ? index : findOrAddLabel(labels, raw, index);
+  }
+
+  determineDataLimits() {
+    const me = this;
+    const {minDefined, maxDefined} = me.getUserBounds();
+    let {min, max} = me.getMinMax(true);
+
+    if (me.options.bounds === 'ticks') {
+      if (!minDefined) {
+        min = 0;
+      }
+      if (!maxDefined) {
+        max = me.getLabels().length - 1;
+      }
+    }
+
+    me.min = min;
+    me.max = max;
+  }
+
+  buildTicks() {
+    const me = this;
+    const min = me.min;
+    const max = me.max;
+    const offset = me.options.offset;
+    const ticks = [];
+    let labels = me.getLabels();
+
+    // If we are viewing some subset of labels, slice the original array
+    labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1);
+
+    me._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
+    me._startValue = me.min - (offset ? 0.5 : 0);
+
+    for (let value = min; value <= max; value++) {
+      ticks.push({value});
+    }
+    return ticks;
+  }
+
+  getLabelForValue(value) {
+    const me = this;
+    const labels = me.getLabels();
+
+    if (value >= 0 && value < labels.length) {
+      return labels[value];
+    }
+    return value;
+  }
+
+  /**
         * @protected
         */
-       configure() {
-               const me = this;
-
-               super.configure();
-
-               if (!me.isHorizontal()) {
-                       // For backward compatibility, vertical category scale reverse is inverted.
-                       me._reversePixels = !me._reversePixels;
-               }
-       }
-
-       // Used to get data value locations. Value can either be an index or a numerical value
-       getPixelForValue(value) {
-               const me = this;
-
-               if (typeof value !== 'number') {
-                       value = me.parse(value);
-               }
-
-               return me.getPixelForDecimal((value - me._startValue) / me._valueRange);
-       }
-
-       // Must override base implementation because it calls getPixelForValue
-       // and category scale can have duplicate values
-       getPixelForTick(index) {
-               const me = this;
-               const ticks = me.ticks;
-               if (index < 0 || index > ticks.length - 1) {
-                       return null;
-               }
-               return me.getPixelForValue(ticks[index].value);
-       }
-
-       getValueForPixel(pixel) {
-               const me = this;
-               return Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
-       }
-
-       getBasePixel() {
-               return this.bottom;
-       }
+  configure() {
+    const me = this;
+
+    super.configure();
+
+    if (!me.isHorizontal()) {
+      // For backward compatibility, vertical category scale reverse is inverted.
+      me._reversePixels = !me._reversePixels;
+    }
+  }
+
+  // Used to get data value locations. Value can either be an index or a numerical value
+  getPixelForValue(value) {
+    const me = this;
+
+    if (typeof value !== 'number') {
+      value = me.parse(value);
+    }
+
+    return me.getPixelForDecimal((value - me._startValue) / me._valueRange);
+  }
+
+  // Must override base implementation because it calls getPixelForValue
+  // and category scale can have duplicate values
+  getPixelForTick(index) {
+    const me = this;
+    const ticks = me.ticks;
+    if (index < 0 || index > ticks.length - 1) {
+      return null;
+    }
+    return me.getPixelForValue(ticks[index].value);
+  }
+
+  getValueForPixel(pixel) {
+    const me = this;
+    return Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);
+  }
+
+  getBasePixel() {
+    return this.bottom;
+  }
 }
 
 CategoryScale.id = 'category';
@@ -125,7 +125,7 @@ CategoryScale.id = 'category';
  * @type {any}
  */
 CategoryScale.defaults = {
-       ticks: {
-               callback: CategoryScale.prototype.getLabelForValue
-       }
+  ticks: {
+    callback: CategoryScale.prototype.getLabelForValue
+  }
 };
index 8c14d0e225d9976cb6d5d8821d3f9f1422137937..ece759902fb82582eff2babc18c5db4bc9f2d57d 100644 (file)
@@ -4,39 +4,39 @@ import Ticks from '../core/core.ticks';
 
 export default class LinearScale extends LinearScaleBase {
 
-       determineDataLimits() {
-               const me = this;
-               const {min, max} = me.getMinMax(true);
+  determineDataLimits() {
+    const me = this;
+    const {min, max} = me.getMinMax(true);
 
-               me.min = isFinite(min) ? min : 0;
-               me.max = isFinite(max) ? max : 1;
+    me.min = isFinite(min) ? min : 0;
+    me.max = isFinite(max) ? max : 1;
 
-               // Common base implementation to handle min, max, beginAtZero
-               me.handleTickRangeOptions();
-       }
+    // Common base implementation to handle min, max, beginAtZero
+    me.handleTickRangeOptions();
+  }
 
-       /**
+  /**
         * Returns the maximum number of ticks based on the scale dimension
         * @protected
         */
-       computeTickLimit() {
-               const me = this;
-
-               if (me.isHorizontal()) {
-                       return Math.ceil(me.width / 40);
-               }
-               const tickFont = me._resolveTickFontOptions(0);
-               return Math.ceil(me.height / tickFont.lineHeight);
-       }
-
-       // Utils
-       getPixelForValue(value) {
-               return this.getPixelForDecimal((value - this._startValue) / this._valueRange);
-       }
-
-       getValueForPixel(pixel) {
-               return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
-       }
+  computeTickLimit() {
+    const me = this;
+
+    if (me.isHorizontal()) {
+      return Math.ceil(me.width / 40);
+    }
+    const tickFont = me._resolveTickFontOptions(0);
+    return Math.ceil(me.height / tickFont.lineHeight);
+  }
+
+  // Utils
+  getPixelForValue(value) {
+    return this.getPixelForDecimal((value - this._startValue) / this._valueRange);
+  }
+
+  getValueForPixel(pixel) {
+    return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
+  }
 }
 
 LinearScale.id = 'linear';
@@ -45,7 +45,7 @@ LinearScale.id = 'linear';
  * @type {any}
  */
 LinearScale.defaults = {
-       ticks: {
-               callback: Ticks.formatters.numeric
-       }
+  ticks: {
+    callback: Ticks.formatters.numeric
+  }
 };
index 0ea2b9d1cef203c52aab24f0c3c26a34416ac77c..54628a5fc01709d536122ad6e8c5ee9773e79f18 100644 (file)
@@ -8,21 +8,21 @@ import {formatNumber} from '../core/core.intl';
  * @return {number}
  */
 function niceNum(range) {
-       const exponent = Math.floor(log10(range));
-       const fraction = range / Math.pow(10, exponent);
-       let niceFraction;
-
-       if (fraction <= 1.0) {
-               niceFraction = 1;
-       } else if (fraction <= 2) {
-               niceFraction = 2;
-       } else if (fraction <= 5) {
-               niceFraction = 5;
-       } else {
-               niceFraction = 10;
-       }
-
-       return niceFraction * Math.pow(10, exponent);
+  const exponent = Math.floor(log10(range));
+  const fraction = range / Math.pow(10, exponent);
+  let niceFraction;
+
+  if (fraction <= 1.0) {
+    niceFraction = 1;
+  } else if (fraction <= 2) {
+    niceFraction = 2;
+  } else if (fraction <= 5) {
+    niceFraction = 5;
+  } else {
+    niceFraction = 10;
+  }
+
+  return niceFraction * Math.pow(10, exponent);
 }
 
 /**
@@ -32,219 +32,219 @@ function niceNum(range) {
  * @returns {object[]} array of tick objects
  */
 function generateTicks(generationOptions, dataRange) {
-       const ticks = [];
-       // To get a "nice" value for the tick spacing, we will use the appropriately named
-       // "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
-       // for details.
-
-       const MIN_SPACING = 1e-14;
-       const {stepSize, min, max, precision} = generationOptions;
-       const unit = stepSize || 1;
-       const maxNumSpaces = generationOptions.maxTicks - 1;
-       const {min: rmin, max: rmax} = dataRange;
-       let spacing = niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;
-       let factor, niceMin, niceMax, numSpaces;
-
-       // Beyond MIN_SPACING floating point numbers being to lose precision
-       // such that we can't do the math necessary to generate ticks
-       if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) {
-               return [{value: rmin}, {value: rmax}];
-       }
-
-       numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
-       if (numSpaces > maxNumSpaces) {
-               // If the calculated num of spaces exceeds maxNumSpaces, recalculate it
-               spacing = niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;
-       }
-
-       if (stepSize || isNullOrUndef(precision)) {
-               // If a precision is not specified, calculate factor based on spacing
-               factor = Math.pow(10, _decimalPlaces(spacing));
-       } else {
-               // If the user specified a precision, round to that number of decimal places
-               factor = Math.pow(10, precision);
-               spacing = Math.ceil(spacing * factor) / factor;
-       }
-
-       niceMin = Math.floor(rmin / spacing) * spacing;
-       niceMax = Math.ceil(rmax / spacing) * spacing;
-
-       // If min, max and stepSize is set and they make an evenly spaced scale use it.
-       if (stepSize && !isNullOrUndef(min) && !isNullOrUndef(max)) {
-               // If very close to our whole number, use it.
-               if (almostWhole((max - min) / stepSize, spacing / 1000)) {
-                       niceMin = min;
-                       niceMax = max;
-               }
-       }
-
-       numSpaces = (niceMax - niceMin) / spacing;
-       // If very close to our rounded value, use it.
-       if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
-               numSpaces = Math.round(numSpaces);
-       } else {
-               numSpaces = Math.ceil(numSpaces);
-       }
-
-       niceMin = Math.round(niceMin * factor) / factor;
-       niceMax = Math.round(niceMax * factor) / factor;
-       ticks.push({value: isNullOrUndef(min) ? niceMin : min});
-       for (let j = 1; j < numSpaces; ++j) {
-               ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor});
-       }
-       ticks.push({value: isNullOrUndef(max) ? niceMax : max});
-
-       return ticks;
+  const ticks = [];
+  // To get a "nice" value for the tick spacing, we will use the appropriately named
+  // "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+  // for details.
+
+  const MIN_SPACING = 1e-14;
+  const {stepSize, min, max, precision} = generationOptions;
+  const unit = stepSize || 1;
+  const maxNumSpaces = generationOptions.maxTicks - 1;
+  const {min: rmin, max: rmax} = dataRange;
+  let spacing = niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;
+  let factor, niceMin, niceMax, numSpaces;
+
+  // Beyond MIN_SPACING floating point numbers being to lose precision
+  // such that we can't do the math necessary to generate ticks
+  if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) {
+    return [{value: rmin}, {value: rmax}];
+  }
+
+  numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
+  if (numSpaces > maxNumSpaces) {
+    // If the calculated num of spaces exceeds maxNumSpaces, recalculate it
+    spacing = niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;
+  }
+
+  if (stepSize || isNullOrUndef(precision)) {
+    // If a precision is not specified, calculate factor based on spacing
+    factor = Math.pow(10, _decimalPlaces(spacing));
+  } else {
+    // If the user specified a precision, round to that number of decimal places
+    factor = Math.pow(10, precision);
+    spacing = Math.ceil(spacing * factor) / factor;
+  }
+
+  niceMin = Math.floor(rmin / spacing) * spacing;
+  niceMax = Math.ceil(rmax / spacing) * spacing;
+
+  // If min, max and stepSize is set and they make an evenly spaced scale use it.
+  if (stepSize && !isNullOrUndef(min) && !isNullOrUndef(max)) {
+    // If very close to our whole number, use it.
+    if (almostWhole((max - min) / stepSize, spacing / 1000)) {
+      niceMin = min;
+      niceMax = max;
+    }
+  }
+
+  numSpaces = (niceMax - niceMin) / spacing;
+  // If very close to our rounded value, use it.
+  if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+    numSpaces = Math.round(numSpaces);
+  } else {
+    numSpaces = Math.ceil(numSpaces);
+  }
+
+  niceMin = Math.round(niceMin * factor) / factor;
+  niceMax = Math.round(niceMax * factor) / factor;
+  ticks.push({value: isNullOrUndef(min) ? niceMin : min});
+  for (let j = 1; j < numSpaces; ++j) {
+    ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor});
+  }
+  ticks.push({value: isNullOrUndef(max) ? niceMax : max});
+
+  return ticks;
 }
 
 export default class LinearScaleBase extends Scale {
 
-       constructor(cfg) {
-               super(cfg);
-
-               /** @type {number} */
-               this.start = undefined;
-               /** @type {number} */
-               this.end = undefined;
-               /** @type {number} */
-               this._startValue = undefined;
-               /** @type {number} */
-               this._endValue = undefined;
-               this._valueRange = 0;
-       }
-
-       parse(raw, index) { // eslint-disable-line no-unused-vars
-               if (isNullOrUndef(raw)) {
-                       return NaN;
-               }
-               if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
-                       return NaN;
-               }
-
-               return +raw;
-       }
-
-       handleTickRangeOptions() {
-               const me = this;
-               const {beginAtZero, stacked} = me.options;
-               const {minDefined, maxDefined} = me.getUserBounds();
-               let {min, max} = me;
-
-               const setMin = v => (min = minDefined ? min : v);
-               const setMax = v => (max = maxDefined ? max : v);
-
-               if (beginAtZero || stacked) {
-                       const minSign = sign(min);
-                       const maxSign = sign(max);
-
-                       if (minSign < 0 && maxSign < 0) {
-                               setMax(0);
-                       } else if (minSign > 0 && maxSign > 0) {
-                               setMin(0);
-                       }
-               }
-
-               if (min === max) {
-                       setMax(max + 1);
-
-                       if (!beginAtZero) {
-                               setMin(min - 1);
-                       }
-               }
-               me.min = min;
-               me.max = max;
-       }
-
-       getTickLimit() {
-               const me = this;
-               const tickOpts = me.options.ticks;
-               // eslint-disable-next-line prefer-const
-               let {maxTicksLimit, stepSize} = tickOpts;
-               let maxTicks;
-
-               if (stepSize) {
-                       maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;
-               } else {
-                       maxTicks = me.computeTickLimit();
-                       maxTicksLimit = maxTicksLimit || 11;
-               }
-
-               if (maxTicksLimit) {
-                       maxTicks = Math.min(maxTicksLimit, maxTicks);
-               }
-
-               return maxTicks;
-       }
-
-       /**
+  constructor(cfg) {
+    super(cfg);
+
+    /** @type {number} */
+    this.start = undefined;
+    /** @type {number} */
+    this.end = undefined;
+    /** @type {number} */
+    this._startValue = undefined;
+    /** @type {number} */
+    this._endValue = undefined;
+    this._valueRange = 0;
+  }
+
+  parse(raw, index) { // eslint-disable-line no-unused-vars
+    if (isNullOrUndef(raw)) {
+      return NaN;
+    }
+    if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
+      return NaN;
+    }
+
+    return +raw;
+  }
+
+  handleTickRangeOptions() {
+    const me = this;
+    const {beginAtZero, stacked} = me.options;
+    const {minDefined, maxDefined} = me.getUserBounds();
+    let {min, max} = me;
+
+    const setMin = v => (min = minDefined ? min : v);
+    const setMax = v => (max = maxDefined ? max : v);
+
+    if (beginAtZero || stacked) {
+      const minSign = sign(min);
+      const maxSign = sign(max);
+
+      if (minSign < 0 && maxSign < 0) {
+        setMax(0);
+      } else if (minSign > 0 && maxSign > 0) {
+        setMin(0);
+      }
+    }
+
+    if (min === max) {
+      setMax(max + 1);
+
+      if (!beginAtZero) {
+        setMin(min - 1);
+      }
+    }
+    me.min = min;
+    me.max = max;
+  }
+
+  getTickLimit() {
+    const me = this;
+    const tickOpts = me.options.ticks;
+    // eslint-disable-next-line prefer-const
+    let {maxTicksLimit, stepSize} = tickOpts;
+    let maxTicks;
+
+    if (stepSize) {
+      maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;
+    } else {
+      maxTicks = me.computeTickLimit();
+      maxTicksLimit = maxTicksLimit || 11;
+    }
+
+    if (maxTicksLimit) {
+      maxTicks = Math.min(maxTicksLimit, maxTicks);
+    }
+
+    return maxTicks;
+  }
+
+  /**
         * @protected
         */
-       computeTickLimit() {
-               return Number.POSITIVE_INFINITY;
-       }
-
-       buildTicks() {
-               const me = this;
-               const opts = me.options;
-               const tickOpts = opts.ticks;
-
-               // Figure out what the max number of ticks we can support it is based on the size of
-               // the axis area. For now, we say that the minimum tick spacing in pixels must be 40
-               // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
-               // the graph. Make sure we always have at least 2 ticks
-               let maxTicks = me.getTickLimit();
-               maxTicks = Math.max(2, maxTicks);
-
-               const numericGeneratorOptions = {
-                       maxTicks,
-                       min: opts.min,
-                       max: opts.max,
-                       precision: tickOpts.precision,
-                       stepSize: valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
-               };
-               const ticks = generateTicks(numericGeneratorOptions, me);
-
-               // At this point, we need to update our max and min given the tick values,
-               // since we probably have expanded the range of the scale
-               if (opts.bounds === 'ticks') {
-                       _setMinAndMaxByKey(ticks, me, 'value');
-               }
-
-               if (opts.reverse) {
-                       ticks.reverse();
-
-                       me.start = me.max;
-                       me.end = me.min;
-               } else {
-                       me.start = me.min;
-                       me.end = me.max;
-               }
-
-               return ticks;
-       }
-
-       /**
+  computeTickLimit() {
+    return Number.POSITIVE_INFINITY;
+  }
+
+  buildTicks() {
+    const me = this;
+    const opts = me.options;
+    const tickOpts = opts.ticks;
+
+    // Figure out what the max number of ticks we can support it is based on the size of
+    // the axis area. For now, we say that the minimum tick spacing in pixels must be 40
+    // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+    // the graph. Make sure we always have at least 2 ticks
+    let maxTicks = me.getTickLimit();
+    maxTicks = Math.max(2, maxTicks);
+
+    const numericGeneratorOptions = {
+      maxTicks,
+      min: opts.min,
+      max: opts.max,
+      precision: tickOpts.precision,
+      stepSize: valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
+    };
+    const ticks = generateTicks(numericGeneratorOptions, me);
+
+    // At this point, we need to update our max and min given the tick values,
+    // since we probably have expanded the range of the scale
+    if (opts.bounds === 'ticks') {
+      _setMinAndMaxByKey(ticks, me, 'value');
+    }
+
+    if (opts.reverse) {
+      ticks.reverse();
+
+      me.start = me.max;
+      me.end = me.min;
+    } else {
+      me.start = me.min;
+      me.end = me.max;
+    }
+
+    return ticks;
+  }
+
+  /**
         * @protected
         */
-       configure() {
-               const me = this;
-               const ticks = me.ticks;
-               let start = me.min;
-               let end = me.max;
-
-               super.configure();
-
-               if (me.options.offset && ticks.length) {
-                       const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
-                       start -= offset;
-                       end += offset;
-               }
-               me._startValue = start;
-               me._endValue = end;
-               me._valueRange = end - start;
-       }
-
-       getLabelForValue(value) {
-               return formatNumber(value, this.options.locale);
-       }
+  configure() {
+    const me = this;
+    const ticks = me.ticks;
+    let start = me.min;
+    let end = me.max;
+
+    super.configure();
+
+    if (me.options.offset && ticks.length) {
+      const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
+      start -= offset;
+      end += offset;
+    }
+    me._startValue = start;
+    me._endValue = end;
+    me._valueRange = end - start;
+  }
+
+  getLabelForValue(value) {
+    return formatNumber(value, this.options.locale);
+  }
 }
index 949d67a4ea7aa0fe408592554465eb8f47a0a9b8..5dccaf7926c7b5a0f840c696eb921ce6e4c960d3 100644 (file)
@@ -6,8 +6,8 @@ import Ticks from '../core/core.ticks';
 import {formatNumber} from '../core/core.intl';
 
 function isMajor(tickVal) {
-       const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal))));
-       return remain === 1;
+  const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal))));
+  return remain === 1;
 }
 
 /**
@@ -17,169 +17,169 @@ function isMajor(tickVal) {
  * @returns {object[]} array of tick objects
  */
 function generateTicks(generationOptions, dataRange) {
-       const endExp = Math.floor(log10(dataRange.max));
-       const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
-       const ticks = [];
-       let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
-       let exp = Math.floor(log10(tickVal));
-       let significand = Math.floor(tickVal / Math.pow(10, exp));
-       let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
-
-       do {
-               ticks.push({value: tickVal, major: isMajor(tickVal)});
-
-               ++significand;
-               if (significand === 10) {
-                       significand = 1;
-                       ++exp;
-                       precision = exp >= 0 ? 1 : precision;
-               }
-
-               tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
-       } while (exp < endExp || (exp === endExp && significand < endSignificand));
-
-       const lastTick = finiteOrDefault(generationOptions.max, tickVal);
-       ticks.push({value: lastTick, major: isMajor(tickVal)});
-
-       return ticks;
+  const endExp = Math.floor(log10(dataRange.max));
+  const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+  const ticks = [];
+  let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
+  let exp = Math.floor(log10(tickVal));
+  let significand = Math.floor(tickVal / Math.pow(10, exp));
+  let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
+
+  do {
+    ticks.push({value: tickVal, major: isMajor(tickVal)});
+
+    ++significand;
+    if (significand === 10) {
+      significand = 1;
+      ++exp;
+      precision = exp >= 0 ? 1 : precision;
+    }
+
+    tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
+  } while (exp < endExp || (exp === endExp && significand < endSignificand));
+
+  const lastTick = finiteOrDefault(generationOptions.max, tickVal);
+  ticks.push({value: lastTick, major: isMajor(tickVal)});
+
+  return ticks;
 }
 
 export default class LogarithmicScale extends Scale {
 
-       constructor(cfg) {
-               super(cfg);
-
-               /** @type {number} */
-               this.start = undefined;
-               /** @type {number} */
-               this.end = undefined;
-               /** @type {number} */
-               this._startValue = undefined;
-               this._valueRange = 0;
-       }
-
-       parse(raw, index) {
-               const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]);
-               if (value === 0) {
-                       this._zero = true;
-                       return undefined;
-               }
-               return isFinite(value) && value > 0 ? value : NaN;
-       }
-
-       determineDataLimits() {
-               const me = this;
-               const {min, max} = me.getMinMax(true);
-
-               me.min = isFinite(min) ? Math.max(0, min) : null;
-               me.max = isFinite(max) ? Math.max(0, max) : null;
-
-               if (me.options.beginAtZero) {
-                       me._zero = true;
-               }
-
-               me.handleTickRangeOptions();
-       }
-
-       handleTickRangeOptions() {
-               const me = this;
-               const {minDefined, maxDefined} = me.getUserBounds();
-               let min = me.min;
-               let max = me.max;
-
-               const setMin = v => (min = minDefined ? min : v);
-               const setMax = v => (max = maxDefined ? max : v);
-               const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m);
-
-               if (min === max) {
-                       if (min <= 0) { // includes null
-                               setMin(1);
-                               setMax(10);
-                       } else {
-                               setMin(exp(min, -1));
-                               setMax(exp(max, +1));
-                       }
-               }
-               if (min <= 0) {
-                       setMin(exp(max, -1));
-               }
-               if (max <= 0) {
-                       setMax(exp(min, +1));
-               }
-               // if data has `0` in it or `beginAtZero` is true, min (non zero) value is at bottom
-               // of scale, and it does not equal suggestedMin, lower the min bound by one exp.
-               if (me._zero && me.min !== me._suggestedMin && min === exp(me.min, 0)) {
-                       setMin(exp(min, -1));
-               }
-               me.min = min;
-               me.max = max;
-       }
-
-       buildTicks() {
-               const me = this;
-               const opts = me.options;
-
-               const generationOptions = {
-                       min: me._userMin,
-                       max: me._userMax
-               };
-               const ticks = generateTicks(generationOptions, me);
-
-               // At this point, we need to update our max and min given the tick values,
-               // since we probably have expanded the range of the scale
-               if (opts.bounds === 'ticks') {
-                       _setMinAndMaxByKey(ticks, me, 'value');
-               }
-
-               if (opts.reverse) {
-                       ticks.reverse();
-
-                       me.start = me.max;
-                       me.end = me.min;
-               } else {
-                       me.start = me.min;
-                       me.end = me.max;
-               }
-
-               return ticks;
-       }
-
-       /**
+  constructor(cfg) {
+    super(cfg);
+
+    /** @type {number} */
+    this.start = undefined;
+    /** @type {number} */
+    this.end = undefined;
+    /** @type {number} */
+    this._startValue = undefined;
+    this._valueRange = 0;
+  }
+
+  parse(raw, index) {
+    const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]);
+    if (value === 0) {
+      this._zero = true;
+      return undefined;
+    }
+    return isFinite(value) && value > 0 ? value : NaN;
+  }
+
+  determineDataLimits() {
+    const me = this;
+    const {min, max} = me.getMinMax(true);
+
+    me.min = isFinite(min) ? Math.max(0, min) : null;
+    me.max = isFinite(max) ? Math.max(0, max) : null;
+
+    if (me.options.beginAtZero) {
+      me._zero = true;
+    }
+
+    me.handleTickRangeOptions();
+  }
+
+  handleTickRangeOptions() {
+    const me = this;
+    const {minDefined, maxDefined} = me.getUserBounds();
+    let min = me.min;
+    let max = me.max;
+
+    const setMin = v => (min = minDefined ? min : v);
+    const setMax = v => (max = maxDefined ? max : v);
+    const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m);
+
+    if (min === max) {
+      if (min <= 0) { // includes null
+        setMin(1);
+        setMax(10);
+      } else {
+        setMin(exp(min, -1));
+        setMax(exp(max, +1));
+      }
+    }
+    if (min <= 0) {
+      setMin(exp(max, -1));
+    }
+    if (max <= 0) {
+      setMax(exp(min, +1));
+    }
+    // if data has `0` in it or `beginAtZero` is true, min (non zero) value is at bottom
+    // of scale, and it does not equal suggestedMin, lower the min bound by one exp.
+    if (me._zero && me.min !== me._suggestedMin && min === exp(me.min, 0)) {
+      setMin(exp(min, -1));
+    }
+    me.min = min;
+    me.max = max;
+  }
+
+  buildTicks() {
+    const me = this;
+    const opts = me.options;
+
+    const generationOptions = {
+      min: me._userMin,
+      max: me._userMax
+    };
+    const ticks = generateTicks(generationOptions, me);
+
+    // At this point, we need to update our max and min given the tick values,
+    // since we probably have expanded the range of the scale
+    if (opts.bounds === 'ticks') {
+      _setMinAndMaxByKey(ticks, me, 'value');
+    }
+
+    if (opts.reverse) {
+      ticks.reverse();
+
+      me.start = me.max;
+      me.end = me.min;
+    } else {
+      me.start = me.min;
+      me.end = me.max;
+    }
+
+    return ticks;
+  }
+
+  /**
         * @param {number} value
         * @return {string}
         */
-       getLabelForValue(value) {
-               return value === undefined ? '0' : formatNumber(value, this.options.locale);
-       }
+  getLabelForValue(value) {
+    return value === undefined ? '0' : formatNumber(value, this.options.locale);
+  }
 
-       /**
+  /**
         * @protected
         */
-       configure() {
-               const me = this;
-               const start = me.min;
-
-               super.configure();
-
-               me._startValue = log10(start);
-               me._valueRange = log10(me.max) - log10(start);
-       }
-
-       getPixelForValue(value) {
-               const me = this;
-               if (value === undefined || value === 0) {
-                       value = me.min;
-               }
-               return me.getPixelForDecimal(value === me.min
-                       ? 0
-                       : (log10(value) - me._startValue) / me._valueRange);
-       }
-
-       getValueForPixel(pixel) {
-               const me = this;
-               const decimal = me.getDecimalForPixel(pixel);
-               return Math.pow(10, me._startValue + decimal * me._valueRange);
-       }
+  configure() {
+    const me = this;
+    const start = me.min;
+
+    super.configure();
+
+    me._startValue = log10(start);
+    me._valueRange = log10(me.max) - log10(start);
+  }
+
+  getPixelForValue(value) {
+    const me = this;
+    if (value === undefined || value === 0) {
+      value = me.min;
+    }
+    return me.getPixelForDecimal(value === me.min
+      ? 0
+      : (log10(value) - me._startValue) / me._valueRange);
+  }
+
+  getValueForPixel(pixel) {
+    const me = this;
+    const decimal = me.getDecimalForPixel(pixel);
+    return Math.pow(10, me._startValue + decimal * me._valueRange);
+  }
 }
 
 LogarithmicScale.id = 'logarithmic';
@@ -188,10 +188,10 @@ LogarithmicScale.id = 'logarithmic';
  * @type {any}
  */
 LogarithmicScale.defaults = {
-       ticks: {
-               callback: Ticks.formatters.logarithmic,
-               major: {
-                       enabled: true
-               }
-       }
+  ticks: {
+    callback: Ticks.formatters.logarithmic,
+    major: {
+      enabled: true
+    }
+  }
 };
index 92411cfbf8ea1c023dd3dc2434fa42f5910f1ca3..45e938e29385769778dbfb9bba71885844f192de 100644 (file)
@@ -7,45 +7,45 @@ import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUnd
 import {toFont, resolve} from '../helpers/helpers.options';
 
 function getTickBackdropHeight(opts) {
-       const tickOpts = opts.ticks;
+  const tickOpts = opts.ticks;
 
-       if (tickOpts.display && opts.display) {
-               return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + tickOpts.backdropPaddingY * 2;
-       }
-       return 0;
+  if (tickOpts.display && opts.display) {
+    return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + tickOpts.backdropPaddingY * 2;
+  }
+  return 0;
 }
 
 function measureLabelSize(ctx, lineHeight, label) {
-       if (isArray(label)) {
-               return {
-                       w: _longestText(ctx, ctx.font, label),
-                       h: label.length * lineHeight
-               };
-       }
-
-       return {
-               w: ctx.measureText(label).width,
-               h: lineHeight
-       };
+  if (isArray(label)) {
+    return {
+      w: _longestText(ctx, ctx.font, label),
+      h: label.length * lineHeight
+    };
+  }
+
+  return {
+    w: ctx.measureText(label).width,
+    h: lineHeight
+  };
 }
 
 function determineLimits(angle, pos, size, min, max) {
-       if (angle === min || angle === max) {
-               return {
-                       start: pos - (size / 2),
-                       end: pos + (size / 2)
-               };
-       } else if (angle < min || angle > max) {
-               return {
-                       start: pos - size,
-                       end: pos
-               };
-       }
-
-       return {
-               start: pos,
-               end: pos + size
-       };
+  if (angle === min || angle === max) {
+    return {
+      start: pos - (size / 2),
+      end: pos + (size / 2)
+    };
+  } else if (angle < min || angle > max) {
+    return {
+      start: pos - size,
+      end: pos
+    };
+  }
+
+  return {
+    start: pos,
+    end: pos + size
+  };
 }
 
 /**
@@ -53,455 +53,455 @@ function determineLimits(angle, pos, size, min, max) {
  */
 function fitWithPointLabels(scale) {
 
-       // Right, this is really confusing and there is a lot of maths going on here
-       // The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
-       //
-       // Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
-       //
-       // Solution:
-       //
-       // We assume the radius of the polygon is half the size of the canvas at first
-       // at each index we check if the text overlaps.
-       //
-       // Where it does, we store that angle and that index.
-       //
-       // After finding the largest index and angle we calculate how much we need to remove
-       // from the shape radius to move the point inwards by that x.
-       //
-       // We average the left and right distances to get the maximum shape radius that can fit in the box
-       // along with labels.
-       //
-       // Once we have that, we can find the centre point for the chart, by taking the x text protrusion
-       // on each side, removing that from the size, halving it and adding the left x protrusion width.
-       //
-       // This will mean we have a shape fitted to the canvas, as large as it can be with the labels
-       // and position it in the most space efficient manner
-       //
-       // https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
-
-       // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
-       // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
-       const furthestLimits = {
-               l: 0,
-               r: scale.width,
-               t: 0,
-               b: scale.height - scale.paddingTop
-       };
-       const furthestAngles = {};
-       let i, textSize, pointPosition;
-
-       scale._pointLabelSizes = [];
-
-       const valueCount = scale.chart.data.labels.length;
-       for (i = 0; i < valueCount; i++) {
-               pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
-
-               const context = scale.getContext(i);
-               const plFont = toFont(resolve([scale.options.pointLabels.font], context, i), scale.chart.options.font);
-               scale.ctx.font = plFont.string;
-               textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]);
-               scale._pointLabelSizes[i] = textSize;
-
-               // Add quarter circle to make degree 0 mean top of circle
-               const angleRadians = scale.getIndexAngle(i);
-               const angle = toDegrees(angleRadians);
-               const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
-               const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
-
-               if (hLimits.start < furthestLimits.l) {
-                       furthestLimits.l = hLimits.start;
-                       furthestAngles.l = angleRadians;
-               }
-
-               if (hLimits.end > furthestLimits.r) {
-                       furthestLimits.r = hLimits.end;
-                       furthestAngles.r = angleRadians;
-               }
-
-               if (vLimits.start < furthestLimits.t) {
-                       furthestLimits.t = vLimits.start;
-                       furthestAngles.t = angleRadians;
-               }
-
-               if (vLimits.end > furthestLimits.b) {
-                       furthestLimits.b = vLimits.end;
-                       furthestAngles.b = angleRadians;
-               }
-       }
-
-       scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles);
+  // Right, this is really confusing and there is a lot of maths going on here
+  // The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+  //
+  // Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+  //
+  // Solution:
+  //
+  // We assume the radius of the polygon is half the size of the canvas at first
+  // at each index we check if the text overlaps.
+  //
+  // Where it does, we store that angle and that index.
+  //
+  // After finding the largest index and angle we calculate how much we need to remove
+  // from the shape radius to move the point inwards by that x.
+  //
+  // We average the left and right distances to get the maximum shape radius that can fit in the box
+  // along with labels.
+  //
+  // Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+  // on each side, removing that from the size, halving it and adding the left x protrusion width.
+  //
+  // This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+  // and position it in the most space efficient manner
+  //
+  // https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+
+  // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+  // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+  const furthestLimits = {
+    l: 0,
+    r: scale.width,
+    t: 0,
+    b: scale.height - scale.paddingTop
+  };
+  const furthestAngles = {};
+  let i, textSize, pointPosition;
+
+  scale._pointLabelSizes = [];
+
+  const valueCount = scale.chart.data.labels.length;
+  for (i = 0; i < valueCount; i++) {
+    pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
+
+    const context = scale.getContext(i);
+    const plFont = toFont(resolve([scale.options.pointLabels.font], context, i), scale.chart.options.font);
+    scale.ctx.font = plFont.string;
+    textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]);
+    scale._pointLabelSizes[i] = textSize;
+
+    // Add quarter circle to make degree 0 mean top of circle
+    const angleRadians = scale.getIndexAngle(i);
+    const angle = toDegrees(angleRadians);
+    const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+    const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+
+    if (hLimits.start < furthestLimits.l) {
+      furthestLimits.l = hLimits.start;
+      furthestAngles.l = angleRadians;
+    }
+
+    if (hLimits.end > furthestLimits.r) {
+      furthestLimits.r = hLimits.end;
+      furthestAngles.r = angleRadians;
+    }
+
+    if (vLimits.start < furthestLimits.t) {
+      furthestLimits.t = vLimits.start;
+      furthestAngles.t = angleRadians;
+    }
+
+    if (vLimits.end > furthestLimits.b) {
+      furthestLimits.b = vLimits.end;
+      furthestAngles.b = angleRadians;
+    }
+  }
+
+  scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles);
 }
 
 function getTextAlignForAngle(angle) {
-       if (angle === 0 || angle === 180) {
-               return 'center';
-       } else if (angle < 180) {
-               return 'left';
-       }
+  if (angle === 0 || angle === 180) {
+    return 'center';
+  } else if (angle < 180) {
+    return 'left';
+  }
 
-       return 'right';
+  return 'right';
 }
 
 function adjustPointPositionForLabelHeight(angle, textSize, position) {
-       if (angle === 90 || angle === 270) {
-               position.y -= (textSize.h / 2);
-       } else if (angle > 270 || angle < 90) {
-               position.y -= textSize.h;
-       }
+  if (angle === 90 || angle === 270) {
+    position.y -= (textSize.h / 2);
+  } else if (angle > 270 || angle < 90) {
+    position.y -= textSize.h;
+  }
 }
 
 function drawPointLabels(scale) {
-       const ctx = scale.ctx;
-       const opts = scale.options;
-       const pointLabelOpts = opts.pointLabels;
-       const tickBackdropHeight = getTickBackdropHeight(opts);
-       const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
-
-       ctx.save();
-
-       ctx.textBaseline = 'middle';
-
-       for (let i = scale.chart.data.labels.length - 1; i >= 0; i--) {
-               // Extra pixels out for some label spacing
-               const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
-               const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
-
-               const context = scale.getContext(i);
-               const plFont = toFont(resolve([pointLabelOpts.font], context, i), scale.chart.options.font);
-               const angle = toDegrees(scale.getIndexAngle(i));
-               adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
-               renderText(
-                       ctx,
-                       scale.pointLabels[i],
-                       pointLabelPosition.x,
-                       pointLabelPosition.y + (plFont.lineHeight / 2),
-                       plFont,
-                       {
-                               color: resolve([pointLabelOpts.color], context, i),
-                               textAlign: getTextAlignForAngle(angle),
-                       }
-               );
-       }
-       ctx.restore();
+  const ctx = scale.ctx;
+  const opts = scale.options;
+  const pointLabelOpts = opts.pointLabels;
+  const tickBackdropHeight = getTickBackdropHeight(opts);
+  const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
+
+  ctx.save();
+
+  ctx.textBaseline = 'middle';
+
+  for (let i = scale.chart.data.labels.length - 1; i >= 0; i--) {
+    // Extra pixels out for some label spacing
+    const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
+    const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
+
+    const context = scale.getContext(i);
+    const plFont = toFont(resolve([pointLabelOpts.font], context, i), scale.chart.options.font);
+    const angle = toDegrees(scale.getIndexAngle(i));
+    adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
+    renderText(
+      ctx,
+      scale.pointLabels[i],
+      pointLabelPosition.x,
+      pointLabelPosition.y + (plFont.lineHeight / 2),
+      plFont,
+      {
+        color: resolve([pointLabelOpts.color], context, i),
+        textAlign: getTextAlignForAngle(angle),
+      }
+    );
+  }
+  ctx.restore();
 }
 
 function drawRadiusLine(scale, gridLineOpts, radius, index) {
-       const ctx = scale.ctx;
-       const circular = gridLineOpts.circular;
-       const valueCount = scale.chart.data.labels.length;
-
-       const context = scale.getContext(index);
-       const lineColor = resolve([gridLineOpts.color], context, index - 1);
-       const lineWidth = resolve([gridLineOpts.lineWidth], context, index - 1);
-       let pointPosition;
-
-       if ((!circular && !valueCount) || !lineColor || !lineWidth || radius < 0) {
-               return;
-       }
-
-       ctx.save();
-       ctx.strokeStyle = lineColor;
-       ctx.lineWidth = lineWidth;
-       if (ctx.setLineDash) {
-               ctx.setLineDash(resolve([gridLineOpts.borderDash, []], context));
-               ctx.lineDashOffset = resolve([gridLineOpts.borderDashOffset], context, index - 1);
-       }
-
-       ctx.beginPath();
-       if (circular) {
-               // Draw circular arcs between the points
-               ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);
-       } else {
-               // Draw straight lines connecting each index
-               pointPosition = scale.getPointPosition(0, radius);
-               ctx.moveTo(pointPosition.x, pointPosition.y);
-
-               for (let i = 1; i < valueCount; i++) {
-                       pointPosition = scale.getPointPosition(i, radius);
-                       ctx.lineTo(pointPosition.x, pointPosition.y);
-               }
-       }
-       ctx.closePath();
-       ctx.stroke();
-       ctx.restore();
+  const ctx = scale.ctx;
+  const circular = gridLineOpts.circular;
+  const valueCount = scale.chart.data.labels.length;
+
+  const context = scale.getContext(index);
+  const lineColor = resolve([gridLineOpts.color], context, index - 1);
+  const lineWidth = resolve([gridLineOpts.lineWidth], context, index - 1);
+  let pointPosition;
+
+  if ((!circular && !valueCount) || !lineColor || !lineWidth || radius < 0) {
+    return;
+  }
+
+  ctx.save();
+  ctx.strokeStyle = lineColor;
+  ctx.lineWidth = lineWidth;
+  if (ctx.setLineDash) {
+    ctx.setLineDash(resolve([gridLineOpts.borderDash, []], context));
+    ctx.lineDashOffset = resolve([gridLineOpts.borderDashOffset], context, index - 1);
+  }
+
+  ctx.beginPath();
+  if (circular) {
+    // Draw circular arcs between the points
+    ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);
+  } else {
+    // Draw straight lines connecting each index
+    pointPosition = scale.getPointPosition(0, radius);
+    ctx.moveTo(pointPosition.x, pointPosition.y);
+
+    for (let i = 1; i < valueCount; i++) {
+      pointPosition = scale.getPointPosition(i, radius);
+      ctx.lineTo(pointPosition.x, pointPosition.y);
+    }
+  }
+  ctx.closePath();
+  ctx.stroke();
+  ctx.restore();
 }
 
 function numberOrZero(param) {
-       return isNumber(param) ? param : 0;
+  return isNumber(param) ? param : 0;
 }
 
 export default class RadialLinearScale extends LinearScaleBase {
 
-       constructor(cfg) {
-               super(cfg);
-
-               /** @type {number} */
-               this.xCenter = undefined;
-               /** @type {number} */
-               this.yCenter = undefined;
-               /** @type {number} */
-               this.drawingArea = undefined;
-               /** @type {string[]} */
-               this.pointLabels = [];
-       }
-
-       init(options) {
-               super.init(options);
-               this.axis = 'r';
-       }
-
-       setDimensions() {
-               const me = this;
-
-               // Set the unconstrained dimension before label rotation
-               me.width = me.maxWidth;
-               me.height = me.maxHeight;
-               me.paddingTop = getTickBackdropHeight(me.options) / 2;
-               me.xCenter = Math.floor(me.width / 2);
-               me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
-               me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
-       }
-
-       determineDataLimits() {
-               const me = this;
-               const {min, max} = me.getMinMax(false);
-
-               me.min = isFinite(min) && !isNaN(min) ? min : 0;
-               me.max = isFinite(max) && !isNaN(max) ? max : 0;
-
-               // Common base implementation to handle min, max, beginAtZero
-               me.handleTickRangeOptions();
-       }
-
-       /**
+  constructor(cfg) {
+    super(cfg);
+
+    /** @type {number} */
+    this.xCenter = undefined;
+    /** @type {number} */
+    this.yCenter = undefined;
+    /** @type {number} */
+    this.drawingArea = undefined;
+    /** @type {string[]} */
+    this.pointLabels = [];
+  }
+
+  init(options) {
+    super.init(options);
+    this.axis = 'r';
+  }
+
+  setDimensions() {
+    const me = this;
+
+    // Set the unconstrained dimension before label rotation
+    me.width = me.maxWidth;
+    me.height = me.maxHeight;
+    me.paddingTop = getTickBackdropHeight(me.options) / 2;
+    me.xCenter = Math.floor(me.width / 2);
+    me.yCenter = Math.floor((me.height - me.paddingTop) / 2);
+    me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;
+  }
+
+  determineDataLimits() {
+    const me = this;
+    const {min, max} = me.getMinMax(false);
+
+    me.min = isFinite(min) && !isNaN(min) ? min : 0;
+    me.max = isFinite(max) && !isNaN(max) ? max : 0;
+
+    // Common base implementation to handle min, max, beginAtZero
+    me.handleTickRangeOptions();
+  }
+
+  /**
         * Returns the maximum number of ticks based on the scale dimension
         * @protected
         */
-       computeTickLimit() {
-               return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
-       }
-
-       generateTickLabels(ticks) {
-               const me = this;
-
-               LinearScaleBase.prototype.generateTickLabels.call(me, ticks);
-
-               // Point labels
-               me.pointLabels = me.chart.data.labels.map((value, index) => {
-                       const label = callCallback(me.options.pointLabels.callback, [value, index], me);
-                       return label || label === 0 ? label : '';
-               });
-       }
-
-       fit() {
-               const me = this;
-               const opts = me.options;
-
-               if (opts.display && opts.pointLabels.display) {
-                       fitWithPointLabels(me);
-               } else {
-                       me.setCenterPoint(0, 0, 0, 0);
-               }
-       }
-
-       /**
+  computeTickLimit() {
+    return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
+  }
+
+  generateTickLabels(ticks) {
+    const me = this;
+
+    LinearScaleBase.prototype.generateTickLabels.call(me, ticks);
+
+    // Point labels
+    me.pointLabels = me.chart.data.labels.map((value, index) => {
+      const label = callCallback(me.options.pointLabels.callback, [value, index], me);
+      return label || label === 0 ? label : '';
+    });
+  }
+
+  fit() {
+    const me = this;
+    const opts = me.options;
+
+    if (opts.display && opts.pointLabels.display) {
+      fitWithPointLabels(me);
+    } else {
+      me.setCenterPoint(0, 0, 0, 0);
+    }
+  }
+
+  /**
         * Set radius reductions and determine new radius and center point
         * @private
         */
-       _setReductions(largestPossibleRadius, furthestLimits, furthestAngles) {
-               const me = this;
-               let radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
-               let radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
-               let radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
-               let radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
-
-               radiusReductionLeft = numberOrZero(radiusReductionLeft);
-               radiusReductionRight = numberOrZero(radiusReductionRight);
-               radiusReductionTop = numberOrZero(radiusReductionTop);
-               radiusReductionBottom = numberOrZero(radiusReductionBottom);
-
-               me.drawingArea = Math.min(
-                       Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
-                       Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
-               me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
-       }
-
-       setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
-               const me = this;
-               const maxRight = me.width - rightMovement - me.drawingArea;
-               const maxLeft = leftMovement + me.drawingArea;
-               const maxTop = topMovement + me.drawingArea;
-               const maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
-
-               me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
-               me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
-       }
-
-       getIndexAngle(index) {
-               const chart = this.chart;
-               const angleMultiplier = TAU / chart.data.labels.length;
-               const options = chart.options || {};
-               const startAngle = options.startAngle || 0;
-
-               return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));
-       }
-
-       getDistanceFromCenterForValue(value) {
-               const me = this;
-
-               if (isNullOrUndef(value)) {
-                       return NaN;
-               }
-
-               // Take into account half font size + the yPadding of the top value
-               const scalingFactor = me.drawingArea / (me.max - me.min);
-               if (me.options.reverse) {
-                       return (me.max - value) * scalingFactor;
-               }
-               return (value - me.min) * scalingFactor;
-       }
-
-       getValueForDistanceFromCenter(distance) {
-               if (isNullOrUndef(distance)) {
-                       return NaN;
-               }
-
-               const me = this;
-               const scaledDistance = distance / (me.drawingArea / (me.max - me.min));
-               return me.options.reverse ? me.max - scaledDistance : me.min + scaledDistance;
-       }
-
-       getPointPosition(index, distanceFromCenter) {
-               const me = this;
-               const angle = me.getIndexAngle(index) - HALF_PI;
-               return {
-                       x: Math.cos(angle) * distanceFromCenter + me.xCenter,
-                       y: Math.sin(angle) * distanceFromCenter + me.yCenter,
-                       angle
-               };
-       }
-
-       getPointPositionForValue(index, value) {
-               return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
-       }
-
-       getBasePosition(index) {
-               return this.getPointPositionForValue(index || 0, this.getBaseValue());
-       }
-
-       /**
+  _setReductions(largestPossibleRadius, furthestLimits, furthestAngles) {
+    const me = this;
+    let radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
+    let radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
+    let radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
+    let radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);
+
+    radiusReductionLeft = numberOrZero(radiusReductionLeft);
+    radiusReductionRight = numberOrZero(radiusReductionRight);
+    radiusReductionTop = numberOrZero(radiusReductionTop);
+    radiusReductionBottom = numberOrZero(radiusReductionBottom);
+
+    me.drawingArea = Math.min(
+      Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
+      Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
+    me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
+  }
+
+  setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
+    const me = this;
+    const maxRight = me.width - rightMovement - me.drawingArea;
+    const maxLeft = leftMovement + me.drawingArea;
+    const maxTop = topMovement + me.drawingArea;
+    const maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;
+
+    me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);
+    me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);
+  }
+
+  getIndexAngle(index) {
+    const chart = this.chart;
+    const angleMultiplier = TAU / chart.data.labels.length;
+    const options = chart.options || {};
+    const startAngle = options.startAngle || 0;
+
+    return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));
+  }
+
+  getDistanceFromCenterForValue(value) {
+    const me = this;
+
+    if (isNullOrUndef(value)) {
+      return NaN;
+    }
+
+    // Take into account half font size + the yPadding of the top value
+    const scalingFactor = me.drawingArea / (me.max - me.min);
+    if (me.options.reverse) {
+      return (me.max - value) * scalingFactor;
+    }
+    return (value - me.min) * scalingFactor;
+  }
+
+  getValueForDistanceFromCenter(distance) {
+    if (isNullOrUndef(distance)) {
+      return NaN;
+    }
+
+    const me = this;
+    const scaledDistance = distance / (me.drawingArea / (me.max - me.min));
+    return me.options.reverse ? me.max - scaledDistance : me.min + scaledDistance;
+  }
+
+  getPointPosition(index, distanceFromCenter) {
+    const me = this;
+    const angle = me.getIndexAngle(index) - HALF_PI;
+    return {
+      x: Math.cos(angle) * distanceFromCenter + me.xCenter,
+      y: Math.sin(angle) * distanceFromCenter + me.yCenter,
+      angle
+    };
+  }
+
+  getPointPositionForValue(index, value) {
+    return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+  }
+
+  getBasePosition(index) {
+    return this.getPointPositionForValue(index || 0, this.getBaseValue());
+  }
+
+  /**
         * @protected
         */
-       drawGrid() {
-               const me = this;
-               const ctx = me.ctx;
-               const opts = me.options;
-               const gridLineOpts = opts.gridLines;
-               const angleLineOpts = opts.angleLines;
-               let i, offset, position;
-
-               if (opts.pointLabels.display) {
-                       drawPointLabels(me);
-               }
-
-               if (gridLineOpts.display) {
-                       me.ticks.forEach((tick, index) => {
-                               if (index !== 0) {
-                                       offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
-                                       drawRadiusLine(me, gridLineOpts, offset, index);
-                               }
-                       });
-               }
-
-               if (angleLineOpts.display) {
-                       ctx.save();
-
-                       for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
-                               const context = me.getContext(i);
-                               const lineWidth = resolve([angleLineOpts.lineWidth, gridLineOpts.lineWidth], context, i);
-                               const color = resolve([angleLineOpts.color, gridLineOpts.color], context, i);
-
-                               if (!lineWidth || !color) {
-                                       continue;
-                               }
-
-                               ctx.lineWidth = lineWidth;
-                               ctx.strokeStyle = color;
-
-                               if (ctx.setLineDash) {
-                                       ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []], context));
-                                       ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0], context, i);
-                               }
-
-                               offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
-                               position = me.getPointPosition(i, offset);
-                               ctx.beginPath();
-                               ctx.moveTo(me.xCenter, me.yCenter);
-                               ctx.lineTo(position.x, position.y);
-                               ctx.stroke();
-                       }
-
-                       ctx.restore();
-               }
-       }
-
-       /**
+  drawGrid() {
+    const me = this;
+    const ctx = me.ctx;
+    const opts = me.options;
+    const gridLineOpts = opts.gridLines;
+    const angleLineOpts = opts.angleLines;
+    let i, offset, position;
+
+    if (opts.pointLabels.display) {
+      drawPointLabels(me);
+    }
+
+    if (gridLineOpts.display) {
+      me.ticks.forEach((tick, index) => {
+        if (index !== 0) {
+          offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
+          drawRadiusLine(me, gridLineOpts, offset, index);
+        }
+      });
+    }
+
+    if (angleLineOpts.display) {
+      ctx.save();
+
+      for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
+        const context = me.getContext(i);
+        const lineWidth = resolve([angleLineOpts.lineWidth, gridLineOpts.lineWidth], context, i);
+        const color = resolve([angleLineOpts.color, gridLineOpts.color], context, i);
+
+        if (!lineWidth || !color) {
+          continue;
+        }
+
+        ctx.lineWidth = lineWidth;
+        ctx.strokeStyle = color;
+
+        if (ctx.setLineDash) {
+          ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []], context));
+          ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0], context, i);
+        }
+
+        offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
+        position = me.getPointPosition(i, offset);
+        ctx.beginPath();
+        ctx.moveTo(me.xCenter, me.yCenter);
+        ctx.lineTo(position.x, position.y);
+        ctx.stroke();
+      }
+
+      ctx.restore();
+    }
+  }
+
+  /**
         * @protected
         */
-       drawLabels() {
-               const me = this;
-               const ctx = me.ctx;
-               const opts = me.options;
-               const tickOpts = opts.ticks;
-
-               if (!tickOpts.display) {
-                       return;
-               }
-
-               const startAngle = me.getIndexAngle(0);
-               let offset, width;
-
-               ctx.save();
-               ctx.translate(me.xCenter, me.yCenter);
-               ctx.rotate(startAngle);
-               ctx.textAlign = 'center';
-               ctx.textBaseline = 'middle';
-
-               me.ticks.forEach((tick, index) => {
-                       if (index === 0 && !opts.reverse) {
-                               return;
-                       }
-
-                       const context = me.getContext(index);
-                       const tickFont = me._resolveTickFontOptions(index);
-                       offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
-
-                       const showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index);
-
-                       if (showLabelBackdrop) {
-                               width = ctx.measureText(tick.label).width;
-                               ctx.fillStyle = resolve([tickOpts.backdropColor], context, index);
-
-                               ctx.fillRect(
-                                       -width / 2 - tickOpts.backdropPaddingX,
-                                       -offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
-                                       width + tickOpts.backdropPaddingX * 2,
-                                       tickFont.size + tickOpts.backdropPaddingY * 2
-                               );
-                       }
-
-                       renderText(ctx, tick.label, 0, -offset, tickFont, {
-                               color: tickOpts.color,
-                       });
-               });
-
-               ctx.restore();
-       }
-
-       /**
+  drawLabels() {
+    const me = this;
+    const ctx = me.ctx;
+    const opts = me.options;
+    const tickOpts = opts.ticks;
+
+    if (!tickOpts.display) {
+      return;
+    }
+
+    const startAngle = me.getIndexAngle(0);
+    let offset, width;
+
+    ctx.save();
+    ctx.translate(me.xCenter, me.yCenter);
+    ctx.rotate(startAngle);
+    ctx.textAlign = 'center';
+    ctx.textBaseline = 'middle';
+
+    me.ticks.forEach((tick, index) => {
+      if (index === 0 && !opts.reverse) {
+        return;
+      }
+
+      const context = me.getContext(index);
+      const tickFont = me._resolveTickFontOptions(index);
+      offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
+
+      const showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index);
+
+      if (showLabelBackdrop) {
+        width = ctx.measureText(tick.label).width;
+        ctx.fillStyle = resolve([tickOpts.backdropColor], context, index);
+
+        ctx.fillRect(
+          -width / 2 - tickOpts.backdropPaddingX,
+          -offset - tickFont.size / 2 - tickOpts.backdropPaddingY,
+          width + tickOpts.backdropPaddingX * 2,
+          tickFont.size + tickOpts.backdropPaddingY * 2
+        );
+      }
+
+      renderText(ctx, tick.label, 0, -offset, tickFont, {
+        color: tickOpts.color,
+      });
+    });
+
+    ctx.restore();
+  }
+
+  /**
         * @protected
         */
-       drawTitle() {}
+  drawTitle() {}
 }
 
 RadialLinearScale.id = 'radialLinear';
@@ -510,58 +510,58 @@ RadialLinearScale.id = 'radialLinear';
  * @type {any}
  */
 RadialLinearScale.defaults = {
-       display: true,
-
-       // Boolean - Whether to animate scaling the chart from the centre
-       animate: true,
-       position: 'chartArea',
-
-       angleLines: {
-               display: true,
-               lineWidth: 1,
-               borderDash: [],
-               borderDashOffset: 0.0
-       },
-
-       gridLines: {
-               circular: false
-       },
-
-       // label settings
-       ticks: {
-               // Boolean - Show a backdrop to the scale label
-               showLabelBackdrop: true,
-
-               // String - The colour of the label backdrop
-               backdropColor: 'rgba(255,255,255,0.75)',
-
-               // Number - The backdrop padding above & below the label in pixels
-               backdropPaddingY: 2,
-
-               // Number - The backdrop padding to the side of the label in pixels
-               backdropPaddingX: 2,
-
-               callback: Ticks.formatters.numeric
-       },
-
-       pointLabels: {
-               // Boolean - if true, show point labels
-               display: true,
-
-               // Number - Point label font size in pixels
-               font: {
-                       size: 10
-               },
-
-               // Function - Used to convert point labels
-               callback(label) {
-                       return label;
-               }
-       }
+  display: true,
+
+  // Boolean - Whether to animate scaling the chart from the centre
+  animate: true,
+  position: 'chartArea',
+
+  angleLines: {
+    display: true,
+    lineWidth: 1,
+    borderDash: [],
+    borderDashOffset: 0.0
+  },
+
+  gridLines: {
+    circular: false
+  },
+
+  // label settings
+  ticks: {
+    // Boolean - Show a backdrop to the scale label
+    showLabelBackdrop: true,
+
+    // String - The colour of the label backdrop
+    backdropColor: 'rgba(255,255,255,0.75)',
+
+    // Number - The backdrop padding above & below the label in pixels
+    backdropPaddingY: 2,
+
+    // Number - The backdrop padding to the side of the label in pixels
+    backdropPaddingX: 2,
+
+    callback: Ticks.formatters.numeric
+  },
+
+  pointLabels: {
+    // Boolean - if true, show point labels
+    display: true,
+
+    // Number - Point label font size in pixels
+    font: {
+      size: 10
+    },
+
+    // Function - Used to convert point labels
+    callback(label) {
+      return label;
+    }
+  }
 };
 
 RadialLinearScale.defaultRoutes = {
-       'angleLines.color': 'borderColor',
-       'pointLabels.color': 'color',
-       'ticks.color': 'color'
+  'angleLines.color': 'borderColor',
+  'pointLabels.color': 'color',
+  'ticks.color': 'color'
 };
index 1a371f70ae6ad008b04fd73ddb027478aff37452..b4f702d254e7154a0ef97da10c5c1eadc6fba81b 100644 (file)
@@ -16,15 +16,15 @@ const MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
  * @type {Object<Unit, Interval>}
  */
 const INTERVALS = {
-       millisecond: {common: true, size: 1, steps: 1000},
-       second: {common: true, size: 1000, steps: 60},
-       minute: {common: true, size: 60000, steps: 60},
-       hour: {common: true, size: 3600000, steps: 24},
-       day: {common: true, size: 86400000, steps: 30},
-       week: {common: false, size: 604800000, steps: 4},
-       month: {common: true, size: 2.628e9, steps: 12},
-       quarter: {common: false, size: 7.884e9, steps: 4},
-       year: {common: true, size: 3.154e10}
+  millisecond: {common: true, size: 1, steps: 1000},
+  second: {common: true, size: 1000, steps: 60},
+  minute: {common: true, size: 60000, steps: 60},
+  hour: {common: true, size: 3600000, steps: 24},
+  day: {common: true, size: 86400000, steps: 30},
+  week: {common: false, size: 604800000, steps: 4},
+  month: {common: true, size: 2.628e9, steps: 12},
+  quarter: {common: false, size: 7.884e9, steps: 4},
+  year: {common: true, size: 3.154e10}
 };
 
 /**
@@ -37,7 +37,7 @@ const UNITS = /** @type Unit[] */(Object.keys(INTERVALS));
  * @param {number} b
  */
 function sorter(a, b) {
-       return a - b;
+  return a - b;
 }
 
 /**
@@ -46,37 +46,37 @@ function sorter(a, b) {
  * @return {number}
  */
 function parse(scale, input) {
-       if (isNullOrUndef(input)) {
-               return null;
-       }
-
-       const adapter = scale._adapter;
-       const options = scale.options.time;
-       const {parser, round, isoWeekday} = options;
-       let value = input;
-
-       if (typeof parser === 'function') {
-               value = parser(value);
-       }
-
-       // Only parse if its not a timestamp already
-       if (!isFinite(value)) {
-               value = typeof parser === 'string'
-                       ? adapter.parse(value, parser)
-                       : adapter.parse(value);
-       }
-
-       if (value === null) {
-               return value;
-       }
-
-       if (round) {
-               value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true)
-                       ? scale._adapter.startOf(value, 'isoWeek', isoWeekday)
-                       : scale._adapter.startOf(value, round);
-       }
-
-       return +value;
+  if (isNullOrUndef(input)) {
+    return null;
+  }
+
+  const adapter = scale._adapter;
+  const options = scale.options.time;
+  const {parser, round, isoWeekday} = options;
+  let value = input;
+
+  if (typeof parser === 'function') {
+    value = parser(value);
+  }
+
+  // Only parse if its not a timestamp already
+  if (!isFinite(value)) {
+    value = typeof parser === 'string'
+      ? adapter.parse(value, parser)
+      : adapter.parse(value);
+  }
+
+  if (value === null) {
+    return value;
+  }
+
+  if (round) {
+    value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true)
+      ? scale._adapter.startOf(value, 'isoWeek', isoWeekday)
+      : scale._adapter.startOf(value, round);
+  }
+
+  return +value;
 }
 
 /**
@@ -88,18 +88,18 @@ function parse(scale, input) {
  * @return {object}
  */
 function determineUnitForAutoTicks(minUnit, min, max, capacity) {
-       const ilen = UNITS.length;
+  const ilen = UNITS.length;
 
-       for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
-               const interval = INTERVALS[UNITS[i]];
-               const factor = interval.steps ? interval.steps : MAX_INTEGER;
+  for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
+    const interval = INTERVALS[UNITS[i]];
+    const factor = interval.steps ? interval.steps : MAX_INTEGER;
 
-               if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
-                       return UNITS[i];
-               }
-       }
+    if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
+      return UNITS[i];
+    }
+  }
 
-       return UNITS[ilen - 1];
+  return UNITS[ilen - 1];
 }
 
 /**
@@ -112,14 +112,14 @@ function determineUnitForAutoTicks(minUnit, min, max, capacity) {
  * @return {Unit}
  */
 function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
-       for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
-               const unit = UNITS[i];
-               if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
-                       return unit;
-               }
-       }
-
-       return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
+  for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
+    const unit = UNITS[i];
+    if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
+      return unit;
+    }
+  }
+
+  return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
 }
 
 /**
@@ -127,11 +127,11 @@ function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
  * @return {object}
  */
 function determineMajorUnit(unit) {
-       for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
-               if (INTERVALS[UNITS[i]].common) {
-                       return UNITS[i];
-               }
-       }
+  for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
+    if (INTERVALS[UNITS[i]].common) {
+      return UNITS[i];
+    }
+  }
 }
 
 /**
@@ -140,13 +140,13 @@ function determineMajorUnit(unit) {
  * @param {number[]} [timestamps] - if defined, snap to these timestamps
  */
 function addTick(ticks, time, timestamps) {
-       if (!timestamps) {
-               ticks[time] = true;
-       } else if (timestamps.length) {
-               const {lo, hi} = _lookup(timestamps, time);
-               const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
-               ticks[timestamp] = true;
-       }
+  if (!timestamps) {
+    ticks[time] = true;
+  } else if (timestamps.length) {
+    const {lo, hi} = _lookup(timestamps, time);
+    const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
+    ticks[timestamp] = true;
+  }
 }
 
 /**
@@ -157,18 +157,18 @@ function addTick(ticks, time, timestamps) {
  * @return {object[]}
  */
 function setMajorTicks(scale, ticks, map, majorUnit) {
-       const adapter = scale._adapter;
-       const first = +adapter.startOf(ticks[0].value, majorUnit);
-       const last = ticks[ticks.length - 1].value;
-       let major, index;
-
-       for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
-               index = map[major];
-               if (index >= 0) {
-                       ticks[index].major = true;
-               }
-       }
-       return ticks;
+  const adapter = scale._adapter;
+  const first = +adapter.startOf(ticks[0].value, majorUnit);
+  const last = ticks[ticks.length - 1].value;
+  let major, index;
+
+  for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
+    index = map[major];
+    if (index >= 0) {
+      ticks[index].major = true;
+    }
+  }
+  return ticks;
 }
 
 /**
@@ -178,179 +178,179 @@ function setMajorTicks(scale, ticks, map, majorUnit) {
  * @return {object[]}
  */
 function ticksFromTimestamps(scale, values, majorUnit) {
-       const ticks = [];
-       /** @type {Object<number,object>} */
-       const map = {};
-       const ilen = values.length;
-       let i, value;
-
-       for (i = 0; i < ilen; ++i) {
-               value = values[i];
-               map[value] = i;
-
-               ticks.push({
-                       value,
-                       major: false
-               });
-       }
-
-       // We set the major ticks separately from the above loop because calling startOf for every tick
-       // is expensive when there is a large number of ticks
-       return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
+  const ticks = [];
+  /** @type {Object<number,object>} */
+  const map = {};
+  const ilen = values.length;
+  let i, value;
+
+  for (i = 0; i < ilen; ++i) {
+    value = values[i];
+    map[value] = i;
+
+    ticks.push({
+      value,
+      major: false
+    });
+  }
+
+  // We set the major ticks separately from the above loop because calling startOf for every tick
+  // is expensive when there is a large number of ticks
+  return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
 }
 
 export default class TimeScale extends Scale {
 
-       /**
+  /**
         * @param {object} props
         */
-       constructor(props) {
-               super(props);
-
-               /** @type {{data: number[], labels: number[], all: number[]}} */
-               this._cache = {
-                       data: [],
-                       labels: [],
-                       all: []
-               };
-
-               /** @type {Unit} */
-               this._unit = 'day';
-               /** @type {Unit=} */
-               this._majorUnit = undefined;
-               this._offsets = {};
-               this._normalized = false;
-       }
-
-       init(scaleOpts, opts) {
-               const time = scaleOpts.time || (scaleOpts.time = {});
-               const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
-
-               // Backward compatibility: before introducing adapter, `displayFormats` was
-               // supposed to contain *all* unit/string pairs but this can't be resolved
-               // when loading the scale (adapters are loaded afterward), so let's populate
-               // missing formats on update
-               mergeIf(time.displayFormats, adapter.formats());
-
-               super.init(scaleOpts);
-
-               this._normalized = opts.normalized;
-       }
-
-       /**
+  constructor(props) {
+    super(props);
+
+    /** @type {{data: number[], labels: number[], all: number[]}} */
+    this._cache = {
+      data: [],
+      labels: [],
+      all: []
+    };
+
+    /** @type {Unit} */
+    this._unit = 'day';
+    /** @type {Unit=} */
+    this._majorUnit = undefined;
+    this._offsets = {};
+    this._normalized = false;
+  }
+
+  init(scaleOpts, opts) {
+    const time = scaleOpts.time || (scaleOpts.time = {});
+    const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);
+
+    // Backward compatibility: before introducing adapter, `displayFormats` was
+    // supposed to contain *all* unit/string pairs but this can't be resolved
+    // when loading the scale (adapters are loaded afterward), so let's populate
+    // missing formats on update
+    mergeIf(time.displayFormats, adapter.formats());
+
+    super.init(scaleOpts);
+
+    this._normalized = opts.normalized;
+  }
+
+  /**
         * @param {*} raw
         * @param {number?} [index]
         * @return {number}
         */
-       parse(raw, index) { // eslint-disable-line no-unused-vars
-               if (raw === undefined) {
-                       return NaN;
-               }
-               return parse(this, raw);
-       }
-
-       beforeLayout() {
-               super.beforeLayout();
-               this._cache = {
-                       data: [],
-                       labels: [],
-                       all: []
-               };
-       }
-
-       determineDataLimits() {
-               const me = this;
-               const options = me.options;
-               const adapter = me._adapter;
-               const unit = options.time.unit || 'day';
-               // eslint-disable-next-line prefer-const
-               let {min, max, minDefined, maxDefined} = me.getUserBounds();
-
-               /**
+  parse(raw, index) { // eslint-disable-line no-unused-vars
+    if (raw === undefined) {
+      return NaN;
+    }
+    return parse(this, raw);
+  }
+
+  beforeLayout() {
+    super.beforeLayout();
+    this._cache = {
+      data: [],
+      labels: [],
+      all: []
+    };
+  }
+
+  determineDataLimits() {
+    const me = this;
+    const options = me.options;
+    const adapter = me._adapter;
+    const unit = options.time.unit || 'day';
+    // eslint-disable-next-line prefer-const
+    let {min, max, minDefined, maxDefined} = me.getUserBounds();
+
+    /**
                 * @param {object} bounds
                 */
-               function _applyBounds(bounds) {
-                       if (!minDefined && !isNaN(bounds.min)) {
-                               min = Math.min(min, bounds.min);
-                       }
-                       if (!maxDefined && !isNaN(bounds.max)) {
-                               max = Math.max(max, bounds.max);
-                       }
-               }
-
-               // If we have user provided `min` and `max` labels / data bounds can be ignored
-               if (!minDefined || !maxDefined) {
-                       // Labels are always considered, when user did not force bounds
-                       _applyBounds(me._getLabelBounds());
-
-                       // If `bounds` is `'ticks'` and `ticks.source` is `'labels'`,
-                       // data bounds are ignored (and don't need to be determined)
-                       if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
-                               _applyBounds(me.getMinMax(false));
-                       }
-               }
-
-               min = isFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
-               max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
-
-               // Make sure that max is strictly higher than min (required by the timeseries lookup table)
-               me.min = Math.min(min, max);
-               me.max = Math.max(min + 1, max);
-       }
-
-       /**
+    function _applyBounds(bounds) {
+      if (!minDefined && !isNaN(bounds.min)) {
+        min = Math.min(min, bounds.min);
+      }
+      if (!maxDefined && !isNaN(bounds.max)) {
+        max = Math.max(max, bounds.max);
+      }
+    }
+
+    // If we have user provided `min` and `max` labels / data bounds can be ignored
+    if (!minDefined || !maxDefined) {
+      // Labels are always considered, when user did not force bounds
+      _applyBounds(me._getLabelBounds());
+
+      // If `bounds` is `'ticks'` and `ticks.source` is `'labels'`,
+      // data bounds are ignored (and don't need to be determined)
+      if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
+        _applyBounds(me.getMinMax(false));
+      }
+    }
+
+    min = isFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
+    max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
+
+    // Make sure that max is strictly higher than min (required by the timeseries lookup table)
+    me.min = Math.min(min, max);
+    me.max = Math.max(min + 1, max);
+  }
+
+  /**
         * @private
         */
-       _getLabelBounds() {
-               const arr = this.getLabelTimestamps();
-               let min = Number.POSITIVE_INFINITY;
-               let max = Number.NEGATIVE_INFINITY;
-
-               if (arr.length) {
-                       min = arr[0];
-                       max = arr[arr.length - 1];
-               }
-               return {min, max};
-       }
-
-       /**
+  _getLabelBounds() {
+    const arr = this.getLabelTimestamps();
+    let min = Number.POSITIVE_INFINITY;
+    let max = Number.NEGATIVE_INFINITY;
+
+    if (arr.length) {
+      min = arr[0];
+      max = arr[arr.length - 1];
+    }
+    return {min, max};
+  }
+
+  /**
         * @return {object[]}
         */
-       buildTicks() {
-               const me = this;
-               const options = me.options;
-               const timeOpts = options.time;
-               const tickOpts = options.ticks;
-               const timestamps = tickOpts.source === 'labels' ? me.getLabelTimestamps() : me._generate();
-
-               if (options.bounds === 'ticks' && timestamps.length) {
-                       me.min = me._userMin || timestamps[0];
-                       me.max = me._userMax || timestamps[timestamps.length - 1];
-               }
-
-               const min = me.min;
-               const max = me.max;
-
-               const ticks = _filterBetween(timestamps, min, max);
-
-               // PRIVATE
-               // determineUnitForFormatting relies on the number of ticks so we don't use it when
-               // autoSkip is enabled because we don't yet know what the final number of ticks will be
-               me._unit = timeOpts.unit || (tickOpts.autoSkip
-                       ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, me._getLabelCapacity(min))
-                       : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
-               me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
-                       : determineMajorUnit(me._unit);
-               me.initOffsets(timestamps);
-
-               if (options.reverse) {
-                       ticks.reverse();
-               }
-
-               return ticksFromTimestamps(me, ticks, me._majorUnit);
-       }
-
-       /**
+  buildTicks() {
+    const me = this;
+    const options = me.options;
+    const timeOpts = options.time;
+    const tickOpts = options.ticks;
+    const timestamps = tickOpts.source === 'labels' ? me.getLabelTimestamps() : me._generate();
+
+    if (options.bounds === 'ticks' && timestamps.length) {
+      me.min = me._userMin || timestamps[0];
+      me.max = me._userMax || timestamps[timestamps.length - 1];
+    }
+
+    const min = me.min;
+    const max = me.max;
+
+    const ticks = _filterBetween(timestamps, min, max);
+
+    // PRIVATE
+    // determineUnitForFormatting relies on the number of ticks so we don't use it when
+    // autoSkip is enabled because we don't yet know what the final number of ticks will be
+    me._unit = timeOpts.unit || (tickOpts.autoSkip
+      ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, me._getLabelCapacity(min))
+      : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));
+    me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined
+      : determineMajorUnit(me._unit);
+    me.initOffsets(timestamps);
+
+    if (options.reverse) {
+      ticks.reverse();
+    }
+
+    return ticksFromTimestamps(me, ticks, me._majorUnit);
+  }
+
+  /**
         * Returns the start and end offsets from edges in the form of {start, end}
         * where each value is a relative width to the scale and ranges between 0 and 1.
         * They add extra margins on the both sides by scaling down the original scale.
@@ -359,95 +359,95 @@ export default class TimeScale extends Scale {
         * @return {object}
         * @protected
         */
-       initOffsets(timestamps) {
-               const me = this;
-               let start = 0;
-               let end = 0;
-               let first, last;
-
-               if (me.options.offset && timestamps.length) {
-                       first = me.getDecimalForValue(timestamps[0]);
-                       if (timestamps.length === 1) {
-                               start = 1 - first;
-                       } else {
-                               start = (me.getDecimalForValue(timestamps[1]) - first) / 2;
-                       }
-                       last = me.getDecimalForValue(timestamps[timestamps.length - 1]);
-                       if (timestamps.length === 1) {
-                               end = last;
-                       } else {
-                               end = (last - me.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
-                       }
-               }
-
-               me._offsets = {start, end, factor: 1 / (start + 1 + end)};
-       }
-
-       /**
+  initOffsets(timestamps) {
+    const me = this;
+    let start = 0;
+    let end = 0;
+    let first, last;
+
+    if (me.options.offset && timestamps.length) {
+      first = me.getDecimalForValue(timestamps[0]);
+      if (timestamps.length === 1) {
+        start = 1 - first;
+      } else {
+        start = (me.getDecimalForValue(timestamps[1]) - first) / 2;
+      }
+      last = me.getDecimalForValue(timestamps[timestamps.length - 1]);
+      if (timestamps.length === 1) {
+        end = last;
+      } else {
+        end = (last - me.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
+      }
+    }
+
+    me._offsets = {start, end, factor: 1 / (start + 1 + end)};
+  }
+
+  /**
         * Generates a maximum of `capacity` timestamps between min and max, rounded to the
         * `minor` unit using the given scale time `options`.
         * Important: this method can return ticks outside the min and max range, it's the
         * responsibility of the calling code to clamp values if needed.
         * @private
         */
-       _generate() {
-               const me = this;
-               const adapter = me._adapter;
-               const min = me.min;
-               const max = me.max;
-               const options = me.options;
-               const timeOpts = options.time;
-               // @ts-ignore
-               const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, me._getLabelCapacity(min));
-               const stepSize = valueOrDefault(timeOpts.stepSize, 1);
-               const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
-               const hasWeekday = isNumber(weekday) || weekday === true;
-               const ticks = {};
-               let first = min;
-               let time;
-
-               // For 'week' unit, handle the first day of week option
-               if (hasWeekday) {
-                       first = +adapter.startOf(first, 'isoWeek', weekday);
-               }
-
-               // Align first ticks on unit
-               first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
-
-               // Prevent browser from freezing in case user options request millions of milliseconds
-               if (adapter.diff(max, min, minor) > 100000 * stepSize) {
-                       throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
-               }
-
-               const timestamps = options.ticks.source === 'data' && me.getDataTimestamps();
-               for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
-                       addTick(ticks, time, timestamps);
-               }
-
-               if (time === max || options.bounds === 'ticks') {
-                       addTick(ticks, time, timestamps);
-               }
-
-               // @ts-ignore
-               return Object.keys(ticks).sort((a, b) => a - b).map(x => +x);
-       }
-
-       /**
+  _generate() {
+    const me = this;
+    const adapter = me._adapter;
+    const min = me.min;
+    const max = me.max;
+    const options = me.options;
+    const timeOpts = options.time;
+    // @ts-ignore
+    const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, me._getLabelCapacity(min));
+    const stepSize = valueOrDefault(timeOpts.stepSize, 1);
+    const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+    const hasWeekday = isNumber(weekday) || weekday === true;
+    const ticks = {};
+    let first = min;
+    let time;
+
+    // For 'week' unit, handle the first day of week option
+    if (hasWeekday) {
+      first = +adapter.startOf(first, 'isoWeek', weekday);
+    }
+
+    // Align first ticks on unit
+    first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
+
+    // Prevent browser from freezing in case user options request millions of milliseconds
+    if (adapter.diff(max, min, minor) > 100000 * stepSize) {
+      throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
+    }
+
+    const timestamps = options.ticks.source === 'data' && me.getDataTimestamps();
+    for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
+      addTick(ticks, time, timestamps);
+    }
+
+    if (time === max || options.bounds === 'ticks') {
+      addTick(ticks, time, timestamps);
+    }
+
+    // @ts-ignore
+    return Object.keys(ticks).sort((a, b) => a - b).map(x => +x);
+  }
+
+  /**
         * @param {number} value
         * @return {string}
         */
-       getLabelForValue(value) {
-               const me = this;
-               const adapter = me._adapter;
-               const timeOpts = me.options.time;
-
-               if (timeOpts.tooltipFormat) {
-                       return adapter.format(value, timeOpts.tooltipFormat);
-               }
-               return adapter.format(value, timeOpts.displayFormats.datetime);
-       }
-
-       /**
+  getLabelForValue(value) {
+    const me = this;
+    const adapter = me._adapter;
+    const timeOpts = me.options.time;
+
+    if (timeOpts.tooltipFormat) {
+      return adapter.format(value, timeOpts.tooltipFormat);
+    }
+    return adapter.format(value, timeOpts.displayFormats.datetime);
+  }
+
+  /**
         * Function to format an individual tick mark
         * @param {number} time
         * @param {number} index
@@ -456,157 +456,157 @@ export default class TimeScale extends Scale {
         * @return {string}
         * @private
         */
-       _tickFormatFunction(time, index, ticks, format) {
-               const me = this;
-               const options = me.options;
-               const formats = options.time.displayFormats;
-               const unit = me._unit;
-               const majorUnit = me._majorUnit;
-               const minorFormat = unit && formats[unit];
-               const majorFormat = majorUnit && formats[majorUnit];
-               const tick = ticks[index];
-               const major = majorUnit && majorFormat && tick && tick.major;
-               const label = me._adapter.format(time, format || (major ? majorFormat : minorFormat));
-               const formatter = options.ticks.callback;
-               return formatter ? formatter(label, index, ticks) : label;
-       }
-
-       /**
+  _tickFormatFunction(time, index, ticks, format) {
+    const me = this;
+    const options = me.options;
+    const formats = options.time.displayFormats;
+    const unit = me._unit;
+    const majorUnit = me._majorUnit;
+    const minorFormat = unit && formats[unit];
+    const majorFormat = majorUnit && formats[majorUnit];
+    const tick = ticks[index];
+    const major = majorUnit && majorFormat && tick && tick.major;
+    const label = me._adapter.format(time, format || (major ? majorFormat : minorFormat));
+    const formatter = options.ticks.callback;
+    return formatter ? formatter(label, index, ticks) : label;
+  }
+
+  /**
         * @param {object[]} ticks
         */
-       generateTickLabels(ticks) {
-               let i, ilen, tick;
+  generateTickLabels(ticks) {
+    let i, ilen, tick;
 
-               for (i = 0, ilen = ticks.length; i < ilen; ++i) {
-                       tick = ticks[i];
-                       tick.label = this._tickFormatFunction(tick.value, i, ticks);
-               }
-       }
+    for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+      tick = ticks[i];
+      tick.label = this._tickFormatFunction(tick.value, i, ticks);
+    }
+  }
 
-       /**
+  /**
         * @param {number} value - Milliseconds since epoch (1 January 1970 00:00:00 UTC)
         * @return {number}
         */
-       getDecimalForValue(value) {
-               const me = this;
-               return (value - me.min) / (me.max - me.min);
-       }
+  getDecimalForValue(value) {
+    const me = this;
+    return (value - me.min) / (me.max - me.min);
+  }
 
-       /**
+  /**
         * @param {number} value - Milliseconds since epoch (1 January 1970 00:00:00 UTC)
         * @return {number}
         */
-       getPixelForValue(value) {
-               const me = this;
-               const offsets = me._offsets;
-               const pos = me.getDecimalForValue(value);
-               return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
-       }
-
-       /**
+  getPixelForValue(value) {
+    const me = this;
+    const offsets = me._offsets;
+    const pos = me.getDecimalForValue(value);
+    return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
+  }
+
+  /**
         * @param {number} pixel
         * @return {number}
         */
-       getValueForPixel(pixel) {
-               const me = this;
-               const offsets = me._offsets;
-               const pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
-               return me.min + pos * (me.max - me.min);
-       }
-
-       /**
+  getValueForPixel(pixel) {
+    const me = this;
+    const offsets = me._offsets;
+    const pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+    return me.min + pos * (me.max - me.min);
+  }
+
+  /**
         * @param {string} label
         * @return {{w:number, h:number}}
         * @private
         */
-       _getLabelSize(label) {
-               const me = this;
-               const ticksOpts = me.options.ticks;
-               const tickLabelWidth = me.ctx.measureText(label).width;
-               const angle = toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
-               const cosRotation = Math.cos(angle);
-               const sinRotation = Math.sin(angle);
-               const tickFontSize = me._resolveTickFontOptions(0).size;
-
-               return {
-                       w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
-                       h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
-               };
-       }
-
-       /**
+  _getLabelSize(label) {
+    const me = this;
+    const ticksOpts = me.options.ticks;
+    const tickLabelWidth = me.ctx.measureText(label).width;
+    const angle = toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
+    const cosRotation = Math.cos(angle);
+    const sinRotation = Math.sin(angle);
+    const tickFontSize = me._resolveTickFontOptions(0).size;
+
+    return {
+      w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
+      h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
+    };
+  }
+
+  /**
         * @param {number} exampleTime
         * @return {number}
         * @private
         */
-       _getLabelCapacity(exampleTime) {
-               const me = this;
-               const timeOpts = me.options.time;
-               const displayFormats = timeOpts.displayFormats;
-
-               // pick the longest format (milliseconds) for guestimation
-               const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
-               const exampleLabel = me._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);
-               const size = me._getLabelSize(exampleLabel);
-               // subtract 1 - if offset then there's one less label than tick
-               // if not offset then one half label padding is added to each end leaving room for one less label
-               const capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h) - 1;
-               return capacity > 0 ? capacity : 1;
-       }
-
-       /**
+  _getLabelCapacity(exampleTime) {
+    const me = this;
+    const timeOpts = me.options.time;
+    const displayFormats = timeOpts.displayFormats;
+
+    // pick the longest format (milliseconds) for guestimation
+    const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
+    const exampleLabel = me._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);
+    const size = me._getLabelSize(exampleLabel);
+    // subtract 1 - if offset then there's one less label than tick
+    // if not offset then one half label padding is added to each end leaving room for one less label
+    const capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h) - 1;
+    return capacity > 0 ? capacity : 1;
+  }
+
+  /**
         * @protected
         */
-       getDataTimestamps() {
-               const me = this;
-               let timestamps = me._cache.data || [];
-               let i, ilen;
+  getDataTimestamps() {
+    const me = this;
+    let timestamps = me._cache.data || [];
+    let i, ilen;
 
-               if (timestamps.length) {
-                       return timestamps;
-               }
+    if (timestamps.length) {
+      return timestamps;
+    }
 
-               const metas = me.getMatchingVisibleMetas();
+    const metas = me.getMatchingVisibleMetas();
 
-               if (me._normalized && metas.length) {
-                       return (me._cache.data = metas[0].controller.getAllParsedValues(me));
-               }
+    if (me._normalized && metas.length) {
+      return (me._cache.data = metas[0].controller.getAllParsedValues(me));
+    }
 
-               for (i = 0, ilen = metas.length; i < ilen; ++i) {
-                       timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(me));
-               }
+    for (i = 0, ilen = metas.length; i < ilen; ++i) {
+      timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(me));
+    }
 
-               return (me._cache.data = me.normalize(timestamps));
-       }
+    return (me._cache.data = me.normalize(timestamps));
+  }
 
-       /**
+  /**
         * @protected
         */
-       getLabelTimestamps() {
-               const me = this;
-               const timestamps = me._cache.labels || [];
-               let i, ilen;
+  getLabelTimestamps() {
+    const me = this;
+    const timestamps = me._cache.labels || [];
+    let i, ilen;
 
-               if (timestamps.length) {
-                       return timestamps;
-               }
+    if (timestamps.length) {
+      return timestamps;
+    }
 
-               const labels = me.getLabels();
-               for (i = 0, ilen = labels.length; i < ilen; ++i) {
-                       timestamps.push(parse(me, labels[i]));
-               }
+    const labels = me.getLabels();
+    for (i = 0, ilen = labels.length; i < ilen; ++i) {
+      timestamps.push(parse(me, labels[i]));
+    }
 
-               return (me._cache.labels = me._normalized ? timestamps : me.normalize(timestamps));
-       }
+    return (me._cache.labels = me._normalized ? timestamps : me.normalize(timestamps));
+  }
 
-       /**
+  /**
         * @param {number[]} values
         * @protected
         */
-       normalize(values) {
-               // It seems to be somewhat faster to do sorting first
-               return _arrayUnique(values.sort(sorter));
-       }
+  normalize(values) {
+    // It seems to be somewhat faster to do sorting first
+    return _arrayUnique(values.sort(sorter));
+  }
 }
 
 TimeScale.id = 'time';
@@ -615,26 +615,26 @@ TimeScale.id = 'time';
  * @type {any}
  */
 TimeScale.defaults = {
-       /**
+  /**
         * Scale boundary strategy (bypassed by min/max time options)
         * - `data`: make sure data are fully visible, ticks outside are removed
         * - `ticks`: make sure ticks are fully visible, data outside are truncated
         * @see https://github.com/chartjs/Chart.js/pull/4556
         * @since 2.7.0
         */
-       bounds: 'data',
-
-       adapters: {},
-       time: {
-               parser: false, // false == a pattern string from or a custom callback that converts its argument to a timestamp
-               unit: false, // false == automatic or override with week, month, year, etc.
-               round: false, // none, or override with week, month, year, etc.
-               isoWeekday: false, // override week start day
-               minUnit: 'millisecond',
-               displayFormats: {}
-       },
-       ticks: {
-               /**
+  bounds: 'data',
+
+  adapters: {},
+  time: {
+    parser: false, // false == a pattern string from or a custom callback that converts its argument to a timestamp
+    unit: false, // false == automatic or override with week, month, year, etc.
+    round: false, // none, or override with week, month, year, etc.
+    isoWeekday: false, // override week start day
+    minUnit: 'millisecond',
+    displayFormats: {}
+  },
+  ticks: {
+    /**
                 * Ticks generation input values:
                 * - 'auto': generates "optimal" ticks based on scale size and time options.
                 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
@@ -642,10 +642,10 @@ TimeScale.defaults = {
                 * @see https://github.com/chartjs/Chart.js/pull/4507
                 * @since 2.7.0
                 */
-               source: 'auto',
+    source: 'auto',
 
-               major: {
-                       enabled: false
-               }
-       }
+    major: {
+      enabled: false
+    }
+  }
 };
index 232b49d22098845ce6a6046752fe0251ce3adffe..f8228fe3431010d660b1b621f14dbaac1814c689 100644 (file)
@@ -11,52 +11,52 @@ import {isNullOrUndef} from '../helpers/helpers.core';
  * @return {object}
  */
 function interpolate(table, val, reverse) {
-       let prevSource, nextSource, prevTarget, nextTarget;
-
-       // Note: the lookup table ALWAYS contains at least 2 items (min and max)
-       if (reverse) {
-               prevSource = Math.floor(val);
-               nextSource = Math.ceil(val);
-               prevTarget = table[prevSource];
-               nextTarget = table[nextSource];
-       } else {
-               const result = _lookup(table, val);
-               prevTarget = result.lo;
-               nextTarget = result.hi;
-               prevSource = table[prevTarget];
-               nextSource = table[nextTarget];
-       }
-
-       const span = nextSource - prevSource;
-       return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
+  let prevSource, nextSource, prevTarget, nextTarget;
+
+  // Note: the lookup table ALWAYS contains at least 2 items (min and max)
+  if (reverse) {
+    prevSource = Math.floor(val);
+    nextSource = Math.ceil(val);
+    prevTarget = table[prevSource];
+    nextTarget = table[nextSource];
+  } else {
+    const result = _lookup(table, val);
+    prevTarget = result.lo;
+    nextTarget = result.hi;
+    prevSource = table[prevTarget];
+    nextSource = table[nextTarget];
+  }
+
+  const span = nextSource - prevSource;
+  return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
 }
 
 class TimeSeriesScale extends TimeScale {
 
-       /**
+  /**
         * @param {object} props
         */
-       constructor(props) {
-               super(props);
+  constructor(props) {
+    super(props);
 
-               /** @type {object[]} */
-               this._table = [];
-               /** @type {number} */
-               this._maxIndex = undefined;
-       }
+    /** @type {object[]} */
+    this._table = [];
+    /** @type {number} */
+    this._maxIndex = undefined;
+  }
 
-       /**
+  /**
         * @protected
         */
-       initOffsets() {
-               const me = this;
-               const timestamps = me._getTimestampsForTable();
-               me._table = me.buildLookupTable(timestamps);
-               me._maxIndex = me._table.length - 1;
-               super.initOffsets(timestamps);
-       }
-
-       /**
+  initOffsets() {
+    const me = this;
+    const timestamps = me._getTimestampsForTable();
+    me._table = me.buildLookupTable(timestamps);
+    me._maxIndex = me._table.length - 1;
+    super.initOffsets(timestamps);
+  }
+
+  /**
         * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
         * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
         * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
@@ -67,89 +67,89 @@ class TimeSeriesScale extends TimeScale {
         * @return {object[]}
         * @protected
         */
-       buildLookupTable(timestamps) {
-               const me = this;
-               const {min, max} = me;
-               if (!timestamps.length) {
-                       return [
-                               {time: min, pos: 0},
-                               {time: max, pos: 1}
-                       ];
-               }
-
-               const items = [min];
-               let i, ilen, curr;
-
-               for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
-                       curr = timestamps[i];
-                       if (curr > min && curr < max) {
-                               items.push(curr);
-                       }
-               }
-
-               items.push(max);
-
-               return items;
-       }
-
-       /**
+  buildLookupTable(timestamps) {
+    const me = this;
+    const {min, max} = me;
+    if (!timestamps.length) {
+      return [
+        {time: min, pos: 0},
+        {time: max, pos: 1}
+      ];
+    }
+
+    const items = [min];
+    let i, ilen, curr;
+
+    for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+      curr = timestamps[i];
+      if (curr > min && curr < max) {
+        items.push(curr);
+      }
+    }
+
+    items.push(max);
+
+    return items;
+  }
+
+  /**
         * Returns all timestamps
         * @return {number[]}
         * @private
         */
-       _getTimestampsForTable() {
-               const me = this;
-               let timestamps = me._cache.all || [];
-
-               if (timestamps.length) {
-                       return timestamps;
-               }
-
-               const data = me.getDataTimestamps();
-               const label = me.getLabelTimestamps();
-               if (data.length && label.length) {
-                       // If combining labels and data (data might not contain all labels),
-                       // we need to recheck uniqueness and sort
-                       timestamps = me.normalize(data.concat(label));
-               } else {
-                       timestamps = data.length ? data : label;
-               }
-               timestamps = me._cache.all = timestamps;
-
-               return timestamps;
-       }
-
-       /**
+  _getTimestampsForTable() {
+    const me = this;
+    let timestamps = me._cache.all || [];
+
+    if (timestamps.length) {
+      return timestamps;
+    }
+
+    const data = me.getDataTimestamps();
+    const label = me.getLabelTimestamps();
+    if (data.length && label.length) {
+      // If combining labels and data (data might not contain all labels),
+      // we need to recheck uniqueness and sort
+      timestamps = me.normalize(data.concat(label));
+    } else {
+      timestamps = data.length ? data : label;
+    }
+    timestamps = me._cache.all = timestamps;
+
+    return timestamps;
+  }
+
+  /**
         * @param {number} value - Milliseconds since epoch (1 January 1970 00:00:00 UTC)
         * @param {number} [index]
         * @return {number}
         */
-       getPixelForValue(value, index) {
-               const me = this;
-               const offsets = me._offsets;
-               const pos = me._normalized && me._maxIndex > 0 && !isNullOrUndef(index)
-                       ? index / me._maxIndex : me.getDecimalForValue(value);
-               return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
-       }
-
-       /**
+  getPixelForValue(value, index) {
+    const me = this;
+    const offsets = me._offsets;
+    const pos = me._normalized && me._maxIndex > 0 && !isNullOrUndef(index)
+      ? index / me._maxIndex : me.getDecimalForValue(value);
+    return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);
+  }
+
+  /**
         * @param {number} value - Milliseconds since epoch (1 January 1970 00:00:00 UTC)
         * @return {number}
         */
-       getDecimalForValue(value) {
-               return interpolate(this._table, value) / this._maxIndex;
-       }
+  getDecimalForValue(value) {
+    return interpolate(this._table, value) / this._maxIndex;
+  }
 
-       /**
+  /**
         * @param {number} pixel
         * @return {number}
         */
-       getValueForPixel(pixel) {
-               const me = this;
-               const offsets = me._offsets;
-               const decimal = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
-               return interpolate(me._table, decimal * this._maxIndex, true);
-       }
+  getValueForPixel(pixel) {
+    const me = this;
+    const offsets = me._offsets;
+    const decimal = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+    return interpolate(me._table, decimal * this._maxIndex, true);
+  }
 }
 
 TimeSeriesScale.id = 'timeseries';
index 867969a719b43e7d3c7f7ffc751571e6a7381ee2..ca267713eb6e5e29867284078e96bb7fb711f04f 100644 (file)
@@ -9,19 +9,19 @@
 importScripts('../src/chart.js');
 
 onmessage = function(event) {
-       try {
-               const {type, canvas} = event.data;
-               if (type !== 'initialize') {
-                       throw new Error('invalid message type received by worker: ' + type);
-               }
+  try {
+    const {type, canvas} = event.data;
+    if (type !== 'initialize') {
+      throw new Error('invalid message type received by worker: ' + type);
+    }
 
-               const chart = new Chart(canvas);
-               if (!(chart.platform instanceof Chart.platforms.BasicPlatform)) {
-                       throw new Error('did not use basic platform for chart in web worker');
-               }
+    const chart = new Chart(canvas);
+    if (!(chart.platform instanceof Chart.platforms.BasicPlatform)) {
+      throw new Error('did not use basic platform for chart in web worker');
+    }
 
-               postMessage({type: 'success'});
-       } catch (error) {
-               postMessage({type: 'error', errorMessage: error.stack});
-       }
+    postMessage({type: 'success'});
+  } catch (error) {
+    postMessage({type: 'error', errorMessage: error.stack});
+  }
 };
index a3a2bbeaf99ca8bf82e27a192fc84b25fc25f1d4..ca02427e5b5b9f4f1855501b5051f544b60ba838 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ]
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ]
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 78616b6fe2be90e0b42660dca912be7406e41771..345b85038b49bb85a610bb9f81e55f2bada9556b 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 3, 4, 5, 6],
-                                       backgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [6, 5, 4, 3, 2, 1],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: [
-                                               '#000000',
-                                               '#888888'
-                                       ]
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 3, 4, 5, 6],
+          backgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [6, 5, 4, 3, 2, 1],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: [
+            '#000000',
+            '#888888'
+          ]
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 4f9d9e5ce82b767493ca0e5a2370543a771268ea..97b0829df2858fe5d22189226ab275fae3924223 100644 (file)
@@ -1,51 +1,51 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0a56893aabdbaf17e63047388ed120d6b9405111..0979ae32b34d0c94fa0a038908d71b7d049a409e 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#00ff00'
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: '#00ff00'
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 5684223387327ca5fa6d491c472d328a95d26b95..3f576f1a7c4b5a0943549438ac9d61d60d26b4bd 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 3, 4],
-                       datasets: [
-                               {
-                                       data: [5, 20, 10, 11],
-                                       base: 10,
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#ff0000',
-                                       borderWidth: 2,
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 3, 4],
+      datasets: [
+        {
+          data: [5, 20, 10, 11],
+          base: 10,
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000',
+          borderWidth: 2,
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index acd24711aceda61f4a3262aa81f5fd52c3ba10da..1f2b4b8afeabc4777a68962c5c168c6b98d411ce 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 3, 4],
-                       datasets: [
-                               {
-                                       data: [5, 20, 1, 10],
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#ff0000'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 3, 4],
+      datasets: [
+        {
+          data: [5, 20, 1, 10],
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b0b52688c7af3ca7fd7e1e57e4a6c9ac3e66e720..b21ec623c5def7d69e5b17f1768569da0537418a 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [
-                               {
-                                       data: {0: 5, 1: 20, 2: 1, 3: 10},
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       data: {0: 10, 1: null, 2: 1, 3: NaN},
-                                       backgroundColor: '#ff0000',
-                                       borderColor: '#ff0000'
-                               }
-                       ]
-               },
-               options: {
-                       skipNull: true,
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [
+        {
+          data: {0: 5, 1: 20, 2: 1, 3: 10},
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000'
+        },
+        {
+          data: {0: 10, 1: null, 2: 1, 3: NaN},
+          backgroundColor: '#ff0000',
+          borderColor: '#ff0000'
+        }
+      ]
+    },
+    options: {
+      skipNull: true,
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 4205a1627aceec9a3976d49d64ff8d2cf4882697..fbbdaf0ce66215463810e6ae6ed0acde8d7d31f9 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 3, 4],
-                       datasets: [
-                               {
-                                       data: [5, 20, 1, 10],
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       data: [10, null, 1, undefined],
-                                       backgroundColor: '#ff0000',
-                                       borderColor: '#ff0000'
-                               }
-                       ]
-               },
-               options: {
-                       skipNull: true,
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 3, 4],
+      datasets: [
+        {
+          data: [5, 20, 1, 10],
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000'
+        },
+        {
+          data: [10, null, 1, undefined],
+          backgroundColor: '#ff0000',
+          borderColor: '#ff0000'
+        }
+      ]
+    },
+    options: {
+      skipNull: true,
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index efe6afa9d050451006f8dfb8fa3bae6b53d01f6f..cf9f96e998b6fcf7d25a5d0878a6cacc3d0a48d2 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: 2,
-                                       borderRadius: 5
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: false,
-                                       borderRadius: Number.MAX_VALUE
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#AAAAAA80',
-                                       borderColor: '#80808080',
-                                       borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  threshold: 0.01,
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: 2,
+          borderRadius: 5
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: false,
+          borderRadius: Number.MAX_VALUE
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      elements: {
+        bar: {
+          backgroundColor: '#AAAAAA80',
+          borderColor: '#80808080',
+          borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f8ad9d01a970a66f40e25de488185fa2b33b93dd..9a0e315c382bd006e5a9a8d28bbeb9304bfe43ca 100644 (file)
@@ -1,52 +1,52 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9ba3dbcfd889127aabd94b817f8cf7e114b531b1..4b541ac6df2c04f605ed169abab0d82d19be9c99 100644 (file)
@@ -1,53 +1,53 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          },
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b8981e681f484e32495c3244c15e144d0c658cbe..12cab8bab465132fb1fcf3e4e546b065f246695a 100644 (file)
@@ -1,38 +1,38 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#00ff00',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#00ff00',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index e9bddedef84ac07692e19ac5abe8ac17b942c7c5..66757821cc0c0358195a0059c6514c67a8687912 100644 (file)
@@ -1,53 +1,53 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: [
-                                               'top',
-                                               'top',
-                                               'right',
-                                               'right',
-                                               'bottom',
-                                               'left'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: 8,
-                                       borderSkipped: [
-                                               'bottom',
-                                               'bottom',
-                                               'left',
-                                               'left',
-                                               'top',
-                                               'right'
-                                       ]
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: [
+            'top',
+            'top',
+            'right',
+            'right',
+            'bottom',
+            'left'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: 8,
+          borderSkipped: [
+            'bottom',
+            'bottom',
+            'left',
+            'left',
+            'top',
+            'right'
+          ]
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3aa5a522248cbcd9109fd48a89e7f1473875d167..a4a71041ec2d2ee9ff885554bb8c9b2371512cc0 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? 'left'
-                                                       : value > 0 ? 'right'
-                                                       : value > -8 ? 'top'
-                                                       : 'bottom';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderSkipped: function(ctx) {
-                                               var index = ctx.dataIndex;
-                                               return index > 4 ? 'left'
-                                                       : index > 3 ? 'right'
-                                                       : index > 1 ? 'top'
-                                                       : 'bottom';
-                                       },
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? 'left'
+              : value > 0 ? 'right'
+              : value > -8 ? 'top'
+              : 'bottom';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderSkipped: function(ctx) {
+            var index = ctx.dataIndex;
+            return index > 4 ? 'left'
+              : index > 3 ? 'right'
+              : index > 1 ? 'top'
+              : 'bottom';
+          },
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3e0602eb99fb3c6d3440eaeb538df1305b879065..4227ab7aa0c8f9d304d99bb86a3755c0681a0d69 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, -10, null],
-                                       borderSkipped: 'top'
-                               },
-                               {
-                                       // option in dataset
-                                       data: [0, 5, -10, null],
-                                       borderSkipped: 'right'
-                               },
-                               {
-                                       // option in dataset
-                                       data: [0, 5, -10, null],
-                                       borderSkipped: 'bottom'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, -10, null],
-                               },
-                               {
-                                       // option in dataset
-                                       data: [0, 5, -10, null],
-                                       borderSkipped: false
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderSkipped: 'left',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, -10, null],
+          borderSkipped: 'top'
+        },
+        {
+          // option in dataset
+          data: [0, 5, -10, null],
+          borderSkipped: 'right'
+        },
+        {
+          // option in dataset
+          data: [0, 5, -10, null],
+          borderSkipped: 'bottom'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, -10, null],
+        },
+        {
+          // option in dataset
+          data: [0, 5, -10, null],
+          borderSkipped: false
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderSkipped: 'left',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6e7b6ad8447015867df38d6894f1d668c47c4ccf..1c1346f26f4ebcc7666e111ccda9bf57d0b53d55 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: false,
-                                       borderWidth: [
-                                               {},
-                                               {bottom: 1, left: 1, top: 1, right: 1},
-                                               {bottom: 1, left: 2, top: 1, right: 2},
-                                               {bottom: 1, left: 3, top: 1, right: 3},
-                                               {bottom: 1, left: 4, top: 1, right: 4},
-                                               {bottom: 1, left: 5, top: 1, right: 5}
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#80808080',
-                                       borderSkipped: false,
-                                       borderWidth: [
-                                               {bottom: 1, left: 5, top: 1, right: 5},
-                                               {bottom: 1, left: 4, top: 1, right: 4},
-                                               {bottom: 1, left: 3, top: 1, right: 3},
-                                               {bottom: 1, left: 2, top: 1, right: 2},
-                                               {bottom: 1, left: 1, top: 1, right: 1},
-                                               {}
-                                       ]
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: false,
+          borderWidth: [
+            {},
+            {bottom: 1, left: 1, top: 1, right: 1},
+            {bottom: 1, left: 2, top: 1, right: 2},
+            {bottom: 1, left: 3, top: 1, right: 3},
+            {bottom: 1, left: 4, top: 1, right: 4},
+            {bottom: 1, left: 5, top: 1, right: 5}
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#80808080',
+          borderSkipped: false,
+          borderWidth: [
+            {bottom: 1, left: 5, top: 1, right: 5},
+            {bottom: 1, left: 4, top: 1, right: 4},
+            {bottom: 1, left: 3, top: 1, right: 3},
+            {bottom: 1, left: 2, top: 1, right: 2},
+            {bottom: 1, left: 1, top: 1, right: 1},
+            {}
+          ]
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b6f87da594d179d960697356fc75727b84beb128..feb4ec34696537b21da429f224d1ccd3d2813090 100644 (file)
@@ -1,52 +1,52 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: [
-                                               0,
-                                               1,
-                                               2,
-                                               3,
-                                               4,
-                                               5
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: [
-                                               5,
-                                               4,
-                                               3,
-                                               2,
-                                               1,
-                                               0
-                                       ]
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: [
+            0,
+            1,
+            2,
+            3,
+            4,
+            5
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: [
+            5,
+            4,
+            3,
+            2,
+            1,
+            0
+          ]
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 39dc68fe5f0b6b5fd1863c71742b6a658fd071ae..84c2145df29f96bc84404f591624f114546405cd 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: -2
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               },
-                               {
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: {left: -5, top: -5, bottom: -5, right: -5},
-                                       borderSkipped: false
-                               },
-                               {
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: {}
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#888',
-                                       borderColor: '#f00',
-                                       borderWidth: -4
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: -2
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        },
+        {
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: {left: -5, top: -5, bottom: -5, right: -5},
+          borderSkipped: false
+        },
+        {
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: {}
+        },
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: '#888',
+          borderColor: '#f00',
+          borderWidth: -4
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index c69c6c53762e05609730b1c4a26c982f542ced42..0c24e0dfb24b1f401ddb5ebd03de2740fd420100 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: false,
-                                       borderWidth: {bottom: 1, left: 2, top: 3, right: 4}
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderSkipped: false,
-                                       borderWidth: {bottom: 4, left: 3, top: 2, right: 1}
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: false,
+          borderWidth: {bottom: 1, left: 2, top: 3, right: 4}
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderSkipped: false,
+          borderWidth: {bottom: 4, left: 3, top: 2, right: 1}
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a9a5154776cbd270b1592f38c6769e61032408a4..3db3e2b57b27445e9b39f8368e6fd08eafcf1b01 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: false,
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return {top: Math.abs(value)};
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#80808080',
-                                       borderSkipped: false,
-                                       borderWidth: function(ctx) {
-                                               return {left: ctx.dataIndex * 2};
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: false,
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return {top: Math.abs(value)};
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#80808080',
+          borderSkipped: false,
+          borderWidth: function(ctx) {
+            return {left: ctx.dataIndex * 2};
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f2492b96b20025ec0ebe193ef34617b16aeb30be..ed9e62dd1c803e8db034ec7dfd5d5527858e6d85 100644 (file)
@@ -1,46 +1,46 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return Math.abs(value);
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: function(ctx) {
-                                               return ctx.dataIndex * 2;
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return Math.abs(value);
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: function(ctx) {
+            return ctx.dataIndex * 2;
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index bfedc41ad72932dbb35a3a4fa97bc3c6239eb3da..d5e5dedf02242b14eea79270310761c0abbc3641 100644 (file)
@@ -1,38 +1,38 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: 2
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               bar: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: 4
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: 2
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        bar: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: 4
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ecd2c1b7d54aa2a8338e86f996f1c955b5036453..78b85ed0650f1335bf94152875267ed48f73a266 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 3, 4],
-                       datasets: [
-                               {
-                                       data: [5, 20, -5, -20],
-                                       borderColor: '#ff0000'
-                               }
-                       ]
-               },
-               options: {
-                       layout: {
-                               padding: {
-                                       left: 0,
-                                       right: 0,
-                                       top: 50,
-                                       bottom: 50
-                               }
-                       },
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false, min: -10, max: 10}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 3, 4],
+      datasets: [
+        {
+          data: [5, 20, -5, -20],
+          borderColor: '#ff0000'
+        }
+      ]
+    },
+    options: {
+      layout: {
+        padding: {
+          left: 0,
+          right: 0,
+          top: 50,
+          bottom: 50
+        }
+      },
+      elements: {
+        bar: {
+          backgroundColor: '#00ff00',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false, min: -10, max: 10}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index bba10f006cfb6cfa2beacbc2bbfb5a3d35d0f257..ae1cd0a58c3095ffc5679d7f956ce68a5b2a38e7 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: ['a', 'b', 'c'],
-                       datasets: [
-                               {
-                                       data: {a: 10, b: 2, c: -5},
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       data: {a: 8, b: 12, c: 5},
-                                       backgroundColor: '#00ff00'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: ['a', 'b', 'c'],
+      datasets: [
+        {
+          data: {a: 10, b: 2, c: -5},
+          backgroundColor: '#ff0000'
+        },
+        {
+          data: {a: 8, b: 12, c: 5},
+          backgroundColor: '#00ff00'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index adf3a67a6689ece2edf36f28bd58d0daa642a1f7..d4bdbb31402d7e513534fc7a42d6e80cdc7730a8 100644 (file)
@@ -1,44 +1,44 @@
 const data = [{x: 'Jan', net: 100, cogs: 50, gm: 50}, {x: 'Feb', net: 120, cogs: 55, gm: 75}];
 
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: ['Jan', 'Feb'],
-                       datasets: [{
-                               label: 'Net sales',
-                               backgroundColor: 'blue',
-                               data: data,
-                               parsing: {
-                                       yAxisKey: 'net'
-                               }
-                       }, {
-                               label: 'Cost of goods sold',
-                               backgroundColor: 'red',
-                               data: data,
-                               parsing: {
-                                       yAxisKey: 'cogs'
-                               }
-                       }, {
-                               label: 'Gross margin',
-                               backgroundColor: 'green',
-                               data: data,
-                               parsing: {
-                                       yAxisKey: 'gm'
-                               }
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: ['Jan', 'Feb'],
+      datasets: [{
+        label: 'Net sales',
+        backgroundColor: 'blue',
+        data: data,
+        parsing: {
+          yAxisKey: 'net'
+        }
+      }, {
+        label: 'Cost of goods sold',
+        backgroundColor: 'red',
+        data: data,
+        parsing: {
+          yAxisKey: 'cogs'
+        }
+      }, {
+        label: 'Gross margin',
+        backgroundColor: 'green',
+        data: data,
+        parsing: {
+          yAxisKey: 'gm'
+        }
+      }]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 16a67c438a67eb81718022066b8bc545eda7281f..8d6f373183dfd471b32bc20584b3e3eb50cdf418 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: ['a', 'b', 'c'],
-                       datasets: [
-                               {
-                                       data: [{y: 'b', x: [2, 8]}, {y: 'c', x: [2, 5]}],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       data: [{y: 'a', x: 10}, {y: 'c', x: [6, 10]}],
-                                       backgroundColor: '#00ff00'
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               x: {display: false, min: 0},
-                               y: {display: false, stacked: true}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: ['a', 'b', 'c'],
+      datasets: [
+        {
+          data: [{y: 'b', x: [2, 8]}, {y: 'c', x: [2, 5]}],
+          backgroundColor: '#ff0000'
+        },
+        {
+          data: [{y: 'a', x: 10}, {y: 'c', x: [6, 10]}],
+          backgroundColor: '#00ff00'
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        x: {display: false, min: 0},
+        y: {display: false, stacked: true}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9d6fd63cada11bd447790823e13a9750fbfde89c..42654bca24e3da5e8ee50b8b781d1c04a8459af8 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: ['a', 'b', 'c'],
-                       datasets: [
-                               {
-                                       data: [{x: 'b', y: [2, 8]}, {x: 'c', y: [2, 5]}],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       data: [{x: 'a', y: 10}, {x: 'c', y: [6, 10]}],
-                                       backgroundColor: '#00ff00'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false, stacked: true},
-                               y: {display: false, min: 0}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: ['a', 'b', 'c'],
+      datasets: [
+        {
+          data: [{x: 'b', y: [2, 8]}, {x: 'c', y: [2, 5]}],
+          backgroundColor: '#ff0000'
+        },
+        {
+          data: [{x: 'a', y: 10}, {x: 'c', y: [6, 10]}],
+          backgroundColor: '#00ff00'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false, stacked: true},
+        y: {display: false, min: 0}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 894d121e87017704fe1b4f59f1f2d2d670e18393..bcba2d89afb86ec15fc218467105fec1d3428d20 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderWidth: 2
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderSkipped: false
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#AAAAAA80',
-                                       borderColor: '#80808080',
-                                       borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  threshold: 0.01,
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderWidth: 2
+        },
+        {
+          // option in element (fallback)
+          data: [0, 5, 10, null, -10, -5],
+          borderSkipped: false
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      elements: {
+        bar: {
+          backgroundColor: '#AAAAAA80',
+          borderColor: '#80808080',
+          borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0d8feddb153dbae132f9d0670d43cb513abf10e6..85e6dba68e5c2e549e8c802cd1d177b6047cc52c 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       data: [0, -0.01, -30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               },
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          data: [0, -0.01, -30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        x: {
+          ticks: {
+            display: false
+          }
+        },
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index a76feb1079a3a2c71e9fc86ae836b132a48ad6d9..d12c91cf9d70412237db17e1c35d65c633717481 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       data: [0, 0.01, 30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               },
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          data: [0, 0.01, 30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        x: {
+          ticks: {
+            display: false
+          }
+        },
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 2535bcba503a74e844c886520617671e84ee4f15..ac320120c4cbff147deb8fe68af2e9b3e412a0ab 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4],
-                       datasets: [
-                               {
-                                       data: [0, -0.01, 0.01, 30, -30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               },
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4],
+      datasets: [
+        {
+          data: [0, -0.01, 0.01, 30, -30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        x: {
+          ticks: {
+            display: false
+          }
+        },
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 7ae3897b85719b0df37b68c49800f33ab9630e59..92f853f426f888a5b3627fd2471ab75faed8d68f 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       data: [0, -0.01, -30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          data: [0, -0.01, -30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 07a03c4fd7e118e3026bf1d8796c86e7d4f80a3e..cf0afa2b14b3edc14dd8c52da58db60efd6992cc 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       data: [0, 0.01, 30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          data: [0, 0.01, 30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index ff808c7b5672b90bbe5b673af835603c46797173..4a45513c53cdd9211322c553da40c1bf7683a268 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       labels: [0, 1, 2, 3, 4],
-                       datasets: [
-                               {
-                                       data: [0, -0.01, 0.01, 30, -30],
-                                       backgroundColor: '#00ff00',
-                                       borderWidth: 0,
-                                       minBarLength: 20
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      labels: [0, 1, 2, 3, 4],
+      datasets: [
+        {
+          data: [0, -0.01, 0.01, 30, -30],
+          backgroundColor: '#00ff00',
+          borderWidth: 0,
+          minBarLength: 20
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 43763f67acd608771861dd52c66cbe07474623b0..96d9e4ba387308e061608143bbab61f3ee4fe80f 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: ['10', '100', '10', '100'],
-                               backgroundColor: '#ff0000'
-                       }, {
-                               data: ['100', '10', '0', '100'],
-                               backgroundColor: '#00ff00'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               },
-               options: {
-                       datasets: {
-                               bar: {
-                                       barPercentage: 1,
-                               }
-                       },
-                       scales: {
-                               x: {
-                                       type: 'category',
-                                       display: false,
-                                       stacked: true,
-                               },
-                               y: {
-                                       type: 'logarithmic',
-                                       display: false,
-                                       stacked: true
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: ['10', '100', '10', '100'],
+        backgroundColor: '#ff0000'
+      }, {
+        data: ['100', '10', '0', '100'],
+        backgroundColor: '#00ff00'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    },
+    options: {
+      datasets: {
+        bar: {
+          barPercentage: 1,
+        }
+      },
+      scales: {
+        x: {
+          type: 'category',
+          display: false,
+          stacked: true,
+        },
+        y: {
+          type: 'logarithmic',
+          display: false,
+          stacked: true
+        }
+      }
+    }
+  }
 };
index a18911fed02a48add0bd54bf500b355d8c4cbb0d..ca56ff5f88d462755f207924dbb3b550e4c16075 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [10, 100, 10, 100],
-                               backgroundColor: '#ff0000'
-                       }, {
-                               data: [100, 10, 0, 100],
-                               backgroundColor: '#00ff00'
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               },
-               options: {
-                       datasets: {
-                               bar: {
-                                       barPercentage: 1,
-                               }
-                       },
-                       scales: {
-                               x: {
-                                       type: 'category',
-                                       display: false,
-                                       stacked: true,
-                               },
-                               y: {
-                                       type: 'logarithmic',
-                                       display: false,
-                                       stacked: true
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [10, 100, 10, 100],
+        backgroundColor: '#ff0000'
+      }, {
+        data: [100, 10, 0, 100],
+        backgroundColor: '#00ff00'
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    },
+    options: {
+      datasets: {
+        bar: {
+          barPercentage: 1,
+        }
+      },
+      scales: {
+        x: {
+          type: 'category',
+          display: false,
+          stacked: true,
+        },
+        y: {
+          type: 'logarithmic',
+          display: false,
+          stacked: true
+        }
+      }
+    }
+  }
 };
index 4a9d5090ea0ba3bb7afddebfd87a6bbe8014da69..cf403c972cf93d11ba45e1e60f0ae55306231d7e 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 5, 10, 15, 20, 25, 30, 50, 55, 60],
-                       datasets: [{
-                               data: [6, 11, 10, 10, 3, 22, 7, 24],
-                               type: 'bubble',
-                               label: 'test',
-                               borderColor: '#3e95cd',
-                               fill: false
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {ticks: {display: false}},
-                               y: {
-                                       min: 8,
-                                       max: 25,
-                                       beginAtZero: true,
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 5, 10, 15, 20, 25, 30, 50, 55, 60],
+      datasets: [{
+        data: [6, 11, 10, 10, 3, 22, 7, 24],
+        type: 'bubble',
+        label: 'test',
+        borderColor: '#3e95cd',
+        fill: false
+      }]
+    },
+    options: {
+      scales: {
+        x: {ticks: {display: false}},
+        y: {
+          min: 8,
+          max: 25,
+          beginAtZero: true,
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index b1da990c6a0135978f70418e4bb43f4770e0a265..bacd6a10f956a39b875f7ab3fa58ab5831cccbd3 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'bubble',
-               data: {
-                       datasets: [{
-                               data: [
-                                       {x: 0, y: 5, r: 1},
-                                       {x: 1, y: 4, r: 2},
-                                       {x: 2, y: 3, r: 6},
-                                       {x: 3, y: 2},
-                                       {x: 4, y: 1, r: 2},
-                                       {x: 5, y: 0, r: NaN},
-                                       {x: 6, y: -1, r: undefined},
-                                       {x: 7, y: -2, r: null},
-                                       {x: 8, y: -3, r: '4'},
-                                       {x: 9, y: -4, r: '4px'},
-                               ]
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       elements: {
-                               point: {
-                                       backgroundColor: '#444',
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: {
-                                       left: 24,
-                                       right: 24
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 128,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'bubble',
+    data: {
+      datasets: [{
+        data: [
+          {x: 0, y: 5, r: 1},
+          {x: 1, y: 4, r: 2},
+          {x: 2, y: 3, r: 6},
+          {x: 3, y: 2},
+          {x: 4, y: 1, r: 2},
+          {x: 5, y: 0, r: NaN},
+          {x: 6, y: -1, r: undefined},
+          {x: 7, y: -2, r: null},
+          {x: 8, y: -3, r: '4'},
+          {x: 9, y: -4, r: '4px'},
+        ]
+      }]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      elements: {
+        point: {
+          backgroundColor: '#444',
+          radius: 10
+        }
+      },
+      layout: {
+        padding: {
+          left: 24,
+          right: 24
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 128,
+      width: 256
+    }
+  }
 };
index 5706cb00d9d926d1cb11abb474ba4d7222b66663..4ceeac63fe6409183333f5235861c4c753025d8c 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'bubble',
-               data: {
-                       datasets: [{
-                               data: [
-                                       {x: 0, y: 0},
-                                       {x: 1, y: 0},
-                                       {x: 2, y: 0},
-                                       {x: 3, y: 0},
-                                       {x: 4, y: 0},
-                                       {x: 5, y: 0}
-                               ],
-                               radius: function(ctx) {
-                                       return ctx.dataset.data[ctx.dataIndex].x * 4;
-                               }
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       elements: {
-                               point: {
-                                       backgroundColor: '#444'
-                               }
-                       },
-                       layout: {
-                               padding: {
-                                       left: 24,
-                                       right: 24
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 128,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'bubble',
+    data: {
+      datasets: [{
+        data: [
+          {x: 0, y: 0},
+          {x: 1, y: 0},
+          {x: 2, y: 0},
+          {x: 3, y: 0},
+          {x: 4, y: 0},
+          {x: 5, y: 0}
+        ],
+        radius: function(ctx) {
+          return ctx.dataset.data[ctx.dataIndex].x * 4;
+        }
+      }]
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      elements: {
+        point: {
+          backgroundColor: '#444'
+        }
+      },
+      layout: {
+        padding: {
+          left: 24,
+          right: 24
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 128,
+      width: 256
+    }
+  }
 };
index 7399d7953270970005b3fc138b5ec94349995205..46a6de396c2ddf66622efd7da07670306b57d69d 100644 (file)
@@ -1,46 +1,46 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ]
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ]
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1083523346fc2f2092b9459160419c04d0b6b046..c431349d8e71ca02fdfbbf0397c940243f244c38 100644 (file)
@@ -1,44 +1,44 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3bf4d3e476dce87a3a014db5479f9c88954df84a..5e887f244176441abd4969ede88137345ee1fbe5 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: '#00ff00'
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: '#00ff00'
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 4f9d5572927cad9e5b48a77deccb746f07c557d1..3b8a79ba505db61c5924b537710782437fcfed49 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: [
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                       ],
-                                       borderColor: '#00ff00'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff0000',
-                                       borderWidth: 5,
-                                       borderAlign: [
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                       ]
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: [
+            'center',
+            'inner',
+            'center',
+            'inner',
+            'center',
+            'inner',
+          ],
+          borderColor: '#00ff00'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff0000',
+          borderWidth: 5,
+          borderAlign: [
+            'center',
+            'inner',
+            'center',
+            'inner',
+            'center',
+            'inner',
+          ]
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 81d14fba39e57b279c86e4b3bd0342a616ae7a5f..27ba4bc43bf1d654e0c29844b90996fbfbf837fe 100644 (file)
@@ -1,42 +1,42 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 'inner' : 'center';
-                                       },
-                                       borderColor: '#0000ff',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff00ff',
-                                       borderWidth: 8,
-                                       borderAlign: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 'center' : 'inner';
-                                       }
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 'inner' : 'center';
+          },
+          borderColor: '#0000ff',
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff00ff',
+          borderWidth: 8,
+          borderAlign: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 'center' : 'inner';
+          }
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6271ddbe9f82daa39a6462e407337fd546a91a58..31f71190ffbae58cb89649fb6f4c98b6e54e1461 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: 'inner',
-                                       borderColor: '#00ff00',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderAlign: 'center',
-                                       borderColor: '#0000ff',
-                                       borderWidth: 4,
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: 'inner',
+          borderColor: '#00ff00',
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderAlign: 'center',
+          borderColor: '#0000ff',
+          borderWidth: 4,
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2d6a8cddf3ce651880cc6a05b47999d18197be88..8035df7363d83b4993366b395677b812f1b17345 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       borderWidth: 8
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          borderWidth: 8
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0480889319bc4290f192a632ea4e7a4a194e1821..95cda7ad7cd0c5aa5c782bb9a9e11735905e80e0 100644 (file)
@@ -1,46 +1,46 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 6 ? '#0000ff'
-                                                       : value > 2 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       borderWidth: 8
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 6 ? '#0000ff'
+              : value > 2 ? '#ff0000'
+              : '#00ff00';
+          },
+          borderWidth: 8
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index fbe14eacbbd822677b22b4867656ce4e7d95120e..04c152f80d2040ac4faa173ff2d37eab9be7d547 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#00ff00',
-                                       borderWidth: 8
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#00ff00',
+          borderWidth: 8
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 04b546fc88ba6b7e5f8370a2b48497e06ff08510..10eb61d7a501c2262c59a1a3c0f6af0d0c720d97 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: [
-                                               0,
-                                               1,
-                                               2,
-                                               3,
-                                               4,
-                                               5
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: [
-                                               5,
-                                               4,
-                                               3,
-                                               2,
-                                               1,
-                                               0
-                                       ]
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: [
+            0,
+            1,
+            2,
+            3,
+            4,
+            5
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: [
+            5,
+            4,
+            3,
+            2,
+            1,
+            0
+          ]
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 41e6fca192695aa74b467030e60c06bc7de974b7..94147ae558226e2ec436a8bef450e3ee42e6f4f3 100644 (file)
@@ -1,39 +1,39 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return Math.abs(value);
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: function(ctx) {
-                                               return ctx.dataIndex * 2;
-                                       }
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return Math.abs(value);
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: function(ctx) {
+            return ctx.dataIndex * 2;
+          }
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ac4844370b565267d5d2991c2e8b8bbf8fbb84c2..52da58db22df5a49b13a83f10bc139a073a9337e 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: 2
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: 4
-                               }
-                       },
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: 2
+        },
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: 4
+        }
+      },
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0b137ebbe5aea5fdebd57a5a99ce498b7310269c..98361819e9d012beb7b70b0a7a047d8c4928c07a 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E'],
-                       datasets: [{
-                               data: [1, 5, 10, 50, 100],
-                               backgroundColor: [
-                                       'rgba(255, 99, 132, 0.8)',
-                                       'rgba(54, 162, 235, 0.8)',
-                                       'rgba(255, 206, 86, 0.8)',
-                                       'rgba(75, 192, 192, 0.8)',
-                                       'rgba(153, 102, 255, 0.8)'
-                               ],
-                               borderWidth: 1,
-                               borderColor: [
-                                       'rgb(255, 99, 132)',
-                                       'rgb(54, 162, 235)',
-                                       'rgb(255, 206, 86)',
-                                       'rgb(75, 192, 192)',
-                                       'rgb(153, 102, 255)'
-                               ],
-                               circumference: 180
-                       }]
-               },
-               options: {
-                       circumference: 57.32,
-                       responsive: false
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E'],
+      datasets: [{
+        data: [1, 5, 10, 50, 100],
+        backgroundColor: [
+          'rgba(255, 99, 132, 0.8)',
+          'rgba(54, 162, 235, 0.8)',
+          'rgba(255, 206, 86, 0.8)',
+          'rgba(75, 192, 192, 0.8)',
+          'rgba(153, 102, 255, 0.8)'
+        ],
+        borderWidth: 1,
+        borderColor: [
+          'rgb(255, 99, 132)',
+          'rgb(54, 162, 235)',
+          'rgb(255, 206, 86)',
+          'rgb(75, 192, 192)',
+          'rgb(153, 102, 255)'
+        ],
+        circumference: 180
+      }]
+    },
+    options: {
+      circumference: 57.32,
+      responsive: false
+    }
+  }
 };
index 9ba9879023077abfd12729ef4df08f3c295d3fe9..07d0f8aca14900efcd6e733c0f57012a67b0080d 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E'],
-                       datasets: [{
-                               data: [1, 5, 10, 50, 100],
-                               backgroundColor: [
-                                       'rgba(255, 99, 132, 0.8)',
-                                       'rgba(54, 162, 235, 0.8)',
-                                       'rgba(255, 206, 86, 0.8)',
-                                       'rgba(75, 192, 192, 0.8)',
-                                       'rgba(153, 102, 255, 0.8)'
-                               ],
-                               borderWidth: 4,
-                               borderColor: [
-                                       'rgb(255, 99, 132)',
-                                       'rgb(54, 162, 235)',
-                                       'rgb(255, 206, 86)',
-                                       'rgb(75, 192, 192)',
-                                       'rgb(153, 102, 255)'
-                               ]
-                       }]
-               },
-               options: {
-                       responsive: false,
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: false
-                       }
-               },
-               plugins: [{
-                       id: 'hide',
-                       afterInit(chart) {
-                               chart.toggleDataVisibility(4);
-                       }
-               }]
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E'],
+      datasets: [{
+        data: [1, 5, 10, 50, 100],
+        backgroundColor: [
+          'rgba(255, 99, 132, 0.8)',
+          'rgba(54, 162, 235, 0.8)',
+          'rgba(255, 206, 86, 0.8)',
+          'rgba(75, 192, 192, 0.8)',
+          'rgba(153, 102, 255, 0.8)'
+        ],
+        borderWidth: 4,
+        borderColor: [
+          'rgb(255, 99, 132)',
+          'rgb(54, 162, 235)',
+          'rgb(255, 206, 86)',
+          'rgb(75, 192, 192)',
+          'rgb(153, 102, 255)'
+        ]
+      }]
+    },
+    options: {
+      responsive: false,
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: false
+      }
+    },
+    plugins: [{
+      id: 'hide',
+      afterInit(chart) {
+        chart.toggleDataVisibility(4);
+      }
+    }]
+  }
 };
index 57f60e952213b10cae1cb532fbbcbb577fade4e9..7d604ca8c26226a1af8f1846813b199bece1bc06 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'doughnut',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E'],
-                       datasets: [{
-                               data: [1, 5, 10, 50, 100],
-                               backgroundColor: [
-                                       'rgba(255, 99, 132, 0.8)',
-                                       'rgba(54, 162, 235, 0.8)',
-                                       'rgba(255, 206, 86, 0.8)',
-                                       'rgba(75, 192, 192, 0.8)',
-                                       'rgba(153, 102, 255, 0.8)'
-                               ],
-                               borderWidth: 1,
-                               borderColor: [
-                                       'rgb(255, 99, 132)',
-                                       'rgb(54, 162, 235)',
-                                       'rgb(255, 206, 86)',
-                                       'rgb(75, 192, 192)',
-                                       'rgb(153, 102, 255)'
-                               ],
-                               rotation: -90
-                       }, {
-                               data: [1, 5, 10, 50, 100],
-                               backgroundColor: [
-                                       'rgba(255, 99, 132, 0.8)',
-                                       'rgba(54, 162, 235, 0.8)',
-                                       'rgba(255, 206, 86, 0.8)',
-                                       'rgba(75, 192, 192, 0.8)',
-                                       'rgba(153, 102, 255, 0.8)'
-                               ],
-                               borderWidth: 1,
-                               borderColor: [
-                                       'rgb(255, 99, 132)',
-                                       'rgb(54, 162, 235)',
-                                       'rgb(255, 206, 86)',
-                                       'rgb(75, 192, 192)',
-                                       'rgb(153, 102, 255)'
-                               ],
-                               rotation: 0
-                       }]
-               },
-               options: {
-                       circumference: 180,
-                       responsive: false
-               }
-       }
+  config: {
+    type: 'doughnut',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E'],
+      datasets: [{
+        data: [1, 5, 10, 50, 100],
+        backgroundColor: [
+          'rgba(255, 99, 132, 0.8)',
+          'rgba(54, 162, 235, 0.8)',
+          'rgba(255, 206, 86, 0.8)',
+          'rgba(75, 192, 192, 0.8)',
+          'rgba(153, 102, 255, 0.8)'
+        ],
+        borderWidth: 1,
+        borderColor: [
+          'rgb(255, 99, 132)',
+          'rgb(54, 162, 235)',
+          'rgb(255, 206, 86)',
+          'rgb(75, 192, 192)',
+          'rgb(153, 102, 255)'
+        ],
+        rotation: -90
+      }, {
+        data: [1, 5, 10, 50, 100],
+        backgroundColor: [
+          'rgba(255, 99, 132, 0.8)',
+          'rgba(54, 162, 235, 0.8)',
+          'rgba(255, 206, 86, 0.8)',
+          'rgba(75, 192, 192, 0.8)',
+          'rgba(153, 102, 255, 0.8)'
+        ],
+        borderWidth: 1,
+        borderColor: [
+          'rgb(255, 99, 132)',
+          'rgb(54, 162, 235)',
+          'rgb(255, 206, 86)',
+          'rgb(75, 192, 192)',
+          'rgb(153, 102, 255)'
+        ],
+        rotation: 0
+      }]
+    },
+    options: {
+      circumference: 180,
+      responsive: false
+    }
+  }
 };
index b02960ab7acda1fdc69597d2017375efbdb8d0dc..88dc039ab9ab283c0afaac905f94dff189723ed7 100644 (file)
@@ -1,63 +1,63 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [4, 5, 10, null, -10, -5],
-                                       backgroundColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true,
-                                       backgroundColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               point: {
-                                       backgroundColor: '#0000ff',
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [4, 5, 10, null, -10, -5],
+          backgroundColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [-4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true,
+          backgroundColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#ff00ff';
+          }
+        },
+        point: {
+          backgroundColor: '#0000ff',
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index adc20f9ef54a33001ba4076be1ba140cc2e75a2b..6a52e7b7e450383a35ade19db62e60d9089f7ec0 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true,
-                                       backgroundColor: '#00ff00'
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true,
+          backgroundColor: '#00ff00'
+        },
+        point: {
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index cb31c79d02568ec8a4af4bdc6740404f553621fd..6d76e2056a5824cc19a53676af08b317d9efd0de 100644 (file)
@@ -1,62 +1,62 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [null, 3, 3],
-                                       borderCapStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 2);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'square'
-                                                       : 'butt';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 2, 2],
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 1, 1],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderCapStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 3);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'square'
-                                                       : 'butt';
-                                       },
-                                       borderColor: '#ff0000',
-                                       borderWidth: 32,
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [null, 3, 3],
+          borderCapStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 2);
+            return index === 0 ? 'round'
+              : index === 1 ? 'square'
+              : 'butt';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [null, 2, 2],
+        },
+        {
+          // option in element (fallback)
+          data: [null, 1, 1],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderCapStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 3);
+            return index === 0 ? 'round'
+              : index === 1 ? 'square'
+              : 'butt';
+          },
+          borderColor: '#ff0000',
+          borderWidth: 32,
+          fill: false
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2f0e514bdb5f2b699e561fb86b4033d5bdc935a3..25e8135b5ebf588552959022e27041016daec38d 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [null, 3, 3],
-                                       borderCapStyle: 'round',
-                               },
-                               {
-                                       // option in dataset
-                                       data: [null, 2, 2],
-                                       borderCapStyle: 'square',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 1, 1],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderCapStyle: 'butt',
-                                       borderColor: '#00ff00',
-                                       borderWidth: 32,
-                                       fill: false,
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [null, 3, 3],
+          borderCapStyle: 'round',
+        },
+        {
+          // option in dataset
+          data: [null, 2, 2],
+          borderCapStyle: 'square',
+        },
+        {
+          // option in element (fallback)
+          data: [null, 1, 1],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderCapStyle: 'butt',
+          borderColor: '#00ff00',
+          borderWidth: 32,
+          fill: false,
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d87fd183a96333c0365867a1dfa2e72e3f394cff..e3052f232f80f5ac9eb5cfcf27b81d0a9e997a66 100644 (file)
@@ -1,59 +1,59 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [4, 5, 10, null, -10, -5],
-                                       borderColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#0000ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#0000ff';
-                                       },
-                                       borderWidth: 10,
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: 10,
-                                       radius: 16
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [4, 5, 10, null, -10, -5],
+          borderColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#0000ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [-4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#0000ff';
+          },
+          borderWidth: 10,
+          fill: false
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: 10,
+          radius: 16
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9f58e2427be789b005bab7bf6f9f78f0a4a0fcc9..7a269db5d5ae53c09ddd220998a9c6d7510281f9 100644 (file)
@@ -1,44 +1,44 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#0000ff',
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#0000ff',
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#0000ff',
+          fill: false,
+        },
+        point: {
+          borderColor: '#0000ff',
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 127414872f7fdec8fd939f27db2ed3dbbf8eb2e3..b6bf1010667b461b0c71c2f12ad1ebdac8ee4f87 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [4, 5, 10, null, -10, -5],
-                                       borderDash: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? [5] : [10];
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? [5] : [10];
-                                       }
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [4, 5, 10, null, -10, -5],
+          borderDash: function(ctx) {
+            return ctx.datasetIndex === 0 ? [5] : [10];
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [-4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: function(ctx) {
+            return ctx.datasetIndex === 0 ? [5] : [10];
+          }
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9d1f8a6eb247d99d861f4394a72b5a54a81054bf..3f4f01a6b129596d97770129a4c209abcfdac6b5 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#ff0000',
-                                       borderDash: [5]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [10],
-                                       fill: false,
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#ff0000',
+          borderDash: [5]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [10],
+          fill: false,
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 4e56559dbae39f9052385b0943bd983eacfacdfd..5dabacc6e96624cbba2d612901702d0c238cde7c 100644 (file)
@@ -1,51 +1,51 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [1, 1, 1, 1],
-                                       borderColor: '#ff0000',
-                                       borderDash: [20],
-                                       borderDashOffset: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 5.0 : 0.0;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 0, 0, 0]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [20],
-                                       borderDashOffset: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 5.0 : 0.0;
-                                       },
-                                       fill: false,
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [1, 1, 1, 1],
+          borderColor: '#ff0000',
+          borderDash: [20],
+          borderDashOffset: function(ctx) {
+            return ctx.datasetIndex === 0 ? 5.0 : 0.0;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 0, 0, 0]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [20],
+          borderDashOffset: function(ctx) {
+            return ctx.datasetIndex === 0 ? 5.0 : 0.0;
+          },
+          fill: false,
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 89718503a2f816c79bb386435872f8bff70fc2a8..b16b12bcbd108f4ff39094d168c20a8322f47ed8 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [1, 1, 1, 1, 1, 1],
-                                       borderColor: '#ff0000',
-                                       borderDash: [20],
-                                       borderDashOffset: 5.0
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 0, 0, 0, 0, 0]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [20],
-                                       borderDashOffset: 0.0, // default
-                                       fill: false,
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [1, 1, 1, 1, 1, 1],
+          borderColor: '#ff0000',
+          borderDash: [20],
+          borderDashOffset: 5.0
+        },
+        {
+          // option in element (fallback)
+          data: [0, 0, 0, 0, 0, 0]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [20],
+          borderDashOffset: 0.0, // default
+          fill: false,
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index fd80e765db29278fdab0680976873dc9e2410b1e..2fc77bc8e9996972e025d8c0d3cf79a07a5b8085 100644 (file)
@@ -1,59 +1,59 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [6, 18, 6],
-                                       borderColor: '#ff0000',
-                                       borderJoinStyle: function(ctx) {
-                                               var index = ctx.datasetIndex % 3;
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'miter'
-                                                       : 'bevel';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 14, 2],
-                                       borderColor: '#0000ff',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-2, 10, -2]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderJoinStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 3);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'miter'
-                                                       : 'bevel';
-                                       },
-                                       borderWidth: 25,
-                                       fill: false,
-                                       tension: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          // option in dataset
+          data: [6, 18, 6],
+          borderColor: '#ff0000',
+          borderJoinStyle: function(ctx) {
+            var index = ctx.datasetIndex % 3;
+            return index === 0 ? 'round'
+              : index === 1 ? 'miter'
+              : 'bevel';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [2, 14, 2],
+          borderColor: '#0000ff',
+        },
+        {
+          // option in element (fallback)
+          data: [-2, 10, -2]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderJoinStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 3);
+            return index === 0 ? 'round'
+              : index === 1 ? 'miter'
+              : 'bevel';
+          },
+          borderWidth: 25,
+          fill: false,
+          tension: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3175f0f3b578af187f7c25ef1a1d67f1b93d6e72..303c1a62a601488fe3bc1a4db439946be518b6dc 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [6, 18, 6],
-                                       borderColor: '#ff0000',
-                                       borderJoinStyle: 'round',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 14, 2],
-                                       borderColor: '#0000ff',
-                                       borderJoinStyle: 'bevel',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-2, 10, -2]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderJoinStyle: 'miter',
-                                       borderWidth: 25,
-                                       fill: false,
-                                       tension: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          // option in dataset
+          data: [6, 18, 6],
+          borderColor: '#ff0000',
+          borderJoinStyle: 'round',
+        },
+        {
+          // option in element (fallback)
+          data: [2, 14, 2],
+          borderColor: '#0000ff',
+          borderJoinStyle: 'bevel',
+        },
+        {
+          // option in element (fallback)
+          data: [-2, 10, -2]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderJoinStyle: 'miter',
+          borderWidth: 25,
+          fill: false,
+          tension: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index cef7246d6822119954690e6a15e8e88e24fa0b62..81925c9dcfcbfa5d1f31d4c83c7f1ea3083cf333 100644 (file)
@@ -1,57 +1,57 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [4, 5, 10, null, -10, -5],
-                                       borderColor: '#0000ff',
-                                       borderWidth: function(ctx) {
-                                               var index = ctx.index;
-                                               return index % 2 ? 10 : 20;
-                                       },
-                                       pointBorderColor: '#00ff00'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [-4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: function(ctx) {
-                                               var index = ctx.index;
-                                               return index % 2 ? 10 : 20;
-                                       },
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 5,
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [4, 5, 10, null, -10, -5],
+          borderColor: '#0000ff',
+          borderWidth: function(ctx) {
+            var index = ctx.index;
+            return index % 2 ? 10 : 20;
+          },
+          pointBorderColor: '#00ff00'
+        },
+        {
+          // option in element (fallback)
+          data: [-4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#ff0000',
+          borderWidth: function(ctx) {
+            var index = ctx.index;
+            return index % 2 ? 10 : 20;
+          },
+          fill: false,
+        },
+        point: {
+          borderColor: '#00ff00',
+          borderWidth: 5,
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 67bd66bb30f2cdf1be9e570c262d6a3fcdd2c34b..9c4889e7c3d5832b19a1ac6d2f83600515f12656 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#0000ff',
-                                       borderWidth: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 3,
-                                       fill: false,
-                               },
-                               point: {
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#0000ff',
+          borderWidth: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 3,
+          fill: false,
+        },
+        point: {
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b5b821dea8b2642aba3a0d2154be293d8a8d77dc..4d13be9da9809069ccdef9056026e17796b2afc6 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#0000ff',
-                                       borderColor: '#0000ff',
-                                       borderWidth: 0
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 3,
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 10,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#0000ff',
+          borderColor: '#0000ff',
+          borderWidth: 0
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 3,
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 10,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f01007630e13f4d2470c8ad00b2e053add38b061..8333490dddd0c38795486166642a210671a82524 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       borderColor: '#ff0000',
-                                       cubicInterpolationMode: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 'monotone' : 'default';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 6, 4, 8, 6, 10],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 20,
-                                       cubicInterpolationMode: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 'monotone' : 'default';
-                                       },
-                                       fill: false,
-                                       tension: 0.4
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 4, 2, 6, 4, 8],
+          borderColor: '#ff0000',
+          cubicInterpolationMode: function(ctx) {
+            return ctx.datasetIndex === 0 ? 'monotone' : 'default';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [2, 6, 4, 8, 6, 10],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 20,
+          cubicInterpolationMode: function(ctx) {
+            return ctx.datasetIndex === 0 ? 'monotone' : 'default';
+          },
+          fill: false,
+          tension: 0.4
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f0d9143893fb4fbbc1d6d9168957a8fab3b5c52f..2ae1a8abc687174bad64254e1bc78781e6629d74 100644 (file)
@@ -1,44 +1,44 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       borderColor: '#ff0000',
-                                       cubicInterpolationMode: 'monotone'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 6, 4, 8, 6, 10]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 20,
-                                       cubicInterpolationMode: 'default',
-                                       fill: false,
-                                       tension: 0.4
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 4, 2, 6, 4, 8],
+          borderColor: '#ff0000',
+          cubicInterpolationMode: 'monotone'
+        },
+        {
+          // option in element (fallback)
+          data: [2, 6, 4, 8, 6, 10]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 20,
+          cubicInterpolationMode: 'default',
+          fill: false,
+          tension: 0.4
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 4fdfda18c75386d0fe03089d03459cbf0a55f660..072acbbc0e49f31e66e0dec1bf7f2f80a4ac50e1 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [3, 1, 2, 0, 8, 1],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       backgroundColor: '#00ff00'
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true
-                               },
-                               point: {
-                                       radius: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [3, 1, 2, 0, 8, 1],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 4, 2, 6, 4, 8],
+          backgroundColor: '#00ff00'
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true
+        },
+        point: {
+          radius: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6a05ac9c0340b5873166cebeefd060e6fd216116..892043195ae932f38fff0757682d2a7900d5ee8b 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       data: [3, 1, 2, 0, 8, 1],
-                                       backgroundColor: '#ff0000',
-                                       order: 2
-                               },
-                               {
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       backgroundColor: '#00ff00',
-                                       order: 1
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true
-                               },
-                               point: {
-                                       radius: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          data: [3, 1, 2, 0, 8, 1],
+          backgroundColor: '#ff0000',
+          order: 2
+        },
+        {
+          data: [0, 4, 2, 6, 4, 8],
+          backgroundColor: '#00ff00',
+          order: 1
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true
+        },
+        point: {
+          radius: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index c6e82c95b562160f69c946026ee316d696b36ac2..61d946c857aba7bd06fea3e49b259abb8f53570f 100644 (file)
@@ -1,51 +1,51 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [-2, -6, -4, -8, -6, -10],
-                                       backgroundColor: '#ff0000',
-                                       fill: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? true : false;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 4, 2, 6, 4, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: '#00ff00',
-                                       fill: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? true : false;
-                                       }
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [-2, -6, -4, -8, -6, -10],
+          backgroundColor: '#ff0000',
+          fill: function(ctx) {
+            return ctx.datasetIndex === 0 ? true : false;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 4, 2, 6, 4, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: '#00ff00',
+          fill: function(ctx) {
+            return ctx.datasetIndex === 0 ? true : false;
+          }
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a10cc5205f6a45b51d4f412bf60cf4019cda277d..aebe9f244d615b3d26a4e36c8f9aae6d1035ce77 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [-2, -6, -4, -8, -6, -10],
-                                       backgroundColor: '#ff0000',
-                                       fill: false
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 4, 2, 6, 4, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: '#00ff00',
-                                       fill: true,
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [-2, -6, -4, -8, -6, -10],
+          backgroundColor: '#ff0000',
+          fill: false
+        },
+        {
+          // option in element (fallback)
+          data: [0, 4, 2, 6, 4, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: '#00ff00',
+          fill: true,
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a048f3c1917fb7035cdd4ea6d154496d955bfd45..26ef1ee5d2c6737ffeaf1a8d5b006df1088a7d75 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ba1200dbadec9c228ca71f529b6009265acf92f3..997a53bc7118ed62e525d70f1c0afecd8e6805fb 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          },
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ef5df3378f927690af87c133b8c4312c2314dfbb..0a8cbb579a6e516ddf1c938d82ea3a421501da4f 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3f3298682e5e584ac0227438941c5cfcce8f20a6..0b82fcc5d6c6ccaa9ff45bce22fc1cbb38434bf6 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 556be7c648463485368661b2331483e8b76c653c..29e338983e8af3e8fe2620e17851696e88bc7382 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          },
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1650b32c819278356f700c8586e0acd55a3c0427..cd203c80e71d1ae07a5ca6c9de23bb23a7383fd5 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#00ff00',
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0e819b255901f7adeb2b84c4a77f3ba3305e0d07..2da75b83e39fc6ffd27c49a6c2ae88d7faf96fe8 100644 (file)
@@ -1,46 +1,46 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#00ff00',
-                                       pointBorderWidth: [
-                                               1, 2, 3, 4, 5, 6
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: [
-                                               6, 5, 4, 3, 2, 1
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#00ff00',
+          pointBorderWidth: [
+            1, 2, 3, 4, 5, 6
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: [
+            6, 5, 4, 3, 2, 1
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d833281b4477d61adb6d6903846c8e8f8a0ca3eb..1e0b854ce930f0fd3f1ba6a3943e859124eaad57 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointBorderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 10
-                                                       : value > -4 ? 5
-                                                       : 2;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 2
-                                                       : value > -4 ? 5
-                                                       : 10;
-                                       },
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointBorderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 10
+              : value > -4 ? 5
+              : 2;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 2
+              : value > -4 ? 5
+              : 10;
+          },
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1327fd3a52f41a543c027bec5ae1bf61ac93821a..bad244c22d46523a7e213957d4bf855d30985370 100644 (file)
@@ -1,42 +1,42 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointBorderWidth: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 3,
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointBorderWidth: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#00ff00',
+          borderWidth: 3,
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 3029f8116546fcf822dce9c22798e19e39e6001f..852115c9a3a645d50ddfc956142e1e5041572156 100644 (file)
@@ -1,58 +1,58 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000',
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: [
-                                               'circle',
-                                               'cross',
-                                               'crossRot',
-                                               'dash',
-                                               'line',
-                                               'rect',
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#00ff00',
-                                       pointStyle: [
-                                               'line',
-                                               'rect',
-                                               'rectRounded',
-                                               'rectRot',
-                                               'star',
-                                               'triangle'
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000',
+          pointBorderColor: '#ff0000',
+          pointStyle: [
+            'circle',
+            'cross',
+            'crossRot',
+            'dash',
+            'line',
+            'rect',
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          borderColor: '#00ff00',
+          pointStyle: [
+            'line',
+            'rect',
+            'rectRounded',
+            'rectRot',
+            'star',
+            'triangle'
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index bd68344e50964a93efb4b030e542a25fa5b3ec8c..60d6b4ce15761975784e9c63f48477fada5b08e3 100644 (file)
@@ -1,59 +1,59 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000',
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? 'rect'
-                                                       : value > 0 ? 'star'
-                                                       : value > -8 ? 'cross'
-                                                       : 'triangle';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#0000ff',
-                                       borderColor: '#0000ff',
-                                       pointStyle: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? 'triangle'
-                                                       : value > 0 ? 'cross'
-                                                       : value > -8 ? 'star'
-                                                       : 'rect';
-                                       },
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000',
+          pointBorderColor: '#ff0000',
+          pointStyle: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? 'rect'
+              : value > 0 ? 'star'
+              : value > -8 ? 'cross'
+              : 'triangle';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#0000ff',
+          borderColor: '#0000ff',
+          pointStyle: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? 'triangle'
+              : value > 0 ? 'cross'
+              : value > -8 ? 'star'
+              : 'rect';
+          },
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 87f78d79d49fe0d3d5413f2f6fc44dddbcd7889d..945c25b8bc1da7d5e35b20768587ca5d5aefa8cf 100644 (file)
@@ -1,42 +1,42 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: 'star',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       pointStyle: 'rect',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#ff0000',
+          pointStyle: 'star',
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          pointStyle: 'rect',
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2c3ade90ccd75bc6a6103c1b8b0ee4889f6e97af..7024db7cb4991190a8c04d994f66cb4b10331e80 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#00ff00',
-                                       pointRadius: [
-                                               1, 2, 3, 4, 5, 6
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#ff0000',
-                                       radius: [
-                                               6, 5, 4, 3, 2, 1
-                                       ],
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#00ff00',
+          pointRadius: [
+            1, 2, 3, 4, 5, 6
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#ff0000',
+          radius: [
+            6, 5, 4, 3, 2, 1
+          ],
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index e08e919b028512797db008fb22444887626f4dc9..2d524999ef0b63a33ac613920dd8c72428626964 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#0000ff',
-                                       pointRadius: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 10
-                                                       : value > -4 ? 5
-                                                       : 2;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#ff0000',
-                                       radius: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 2
-                                                       : value > -4 ? 5
-                                                       : 10;
-                                       },
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#0000ff',
+          pointRadius: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 10
+              : value > -4 ? 5
+              : 2;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#ff0000',
+          radius: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 2
+              : value > -4 ? 5
+              : 10;
+          },
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 60a33c69bf5f4047a11f3bca88b3cf68febbc847..fccbe7fc72837a6ef59307cbfedf86dc80dc4034 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#0000ff',
-                                       pointRadius: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 3,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#0000ff',
+          pointRadius: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 3,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d3f33a05da65500c84d469505e0a4374e08b1667..6c7a86d8e8120867e11608c131db96eae5eb072d 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#00ff00',
-                                       pointRotation: [
-                                               0, 30, 60, 90, 120, 150
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: 10,
-                                       pointStyle: 'line',
-                                       rotation: [
-                                               150, 120, 90, 60, 30, 0
-                                       ],
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#00ff00',
+          pointRotation: [
+            0, 30, 60, 90, 120, 150
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: 10,
+          pointStyle: 'line',
+          rotation: [
+            150, 120, 90, 60, 30, 0
+          ],
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9cb5199d6eeaa1f94ad1b70c531ea71217cee092..d22b9d13b95ce645682648b56bbfa65ac4c08448 100644 (file)
@@ -1,56 +1,56 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointRotation: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 120
-                                                       : value > -4 ? 60
-                                                       : 0;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       rotation: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 0
-                                                       : value > -4 ? 60
-                                                       : 120;
-                                       },
-                                       pointStyle: 'line',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointRotation: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 120
+              : value > -4 ? 60
+              : 0;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          rotation: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 0
+              : value > -4 ? 60
+              : 120;
+          },
+          pointStyle: 'line',
+          radius: 10,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 00072267a612a773aaaef406117acab88bf9a592..d96e37d2682d9692ca05412e1e72edaa5dad8b0e 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointRotation: 90
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       pointStyle: 'line',
-                                       radius: 10,
-                                       rotation: 0,
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointRotation: 90
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#00ff00',
+          pointStyle: 'line',
+          radius: 10,
+          rotation: 0,
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2eee50599e8a4dfe32919b3c934ea83c53eda091..d8553d6086b5996075ccb9fd0588293e8dcb9287 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       description: 'should draw all elements except lines turned off per dataset',
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset1',
-                               borderColor: 'red',
-                               backgroundColor: 'green',
-                               showLine: false,
-                               fill: false
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               },
-               options: {
-                       showLine: true,
-                       scales: {
-                               x: {
-                                       display: false
-                               },
-                               y: {
-                                       display: false
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       width: 512,
-                       height: 512
-               }
-       }
+  description: 'should draw all elements except lines turned off per dataset',
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset1',
+        borderColor: 'red',
+        backgroundColor: 'green',
+        showLine: false,
+        fill: false
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    },
+    options: {
+      showLine: true,
+      scales: {
+        x: {
+          display: false
+        },
+        y: {
+          display: false
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      width: 512,
+      height: 512
+    }
+  }
 };
index 648ee8d06e267a5ef44ad154e60b575ea904f4ce..2457c2a8b84150350f48a32b76c16d11bb01472e 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       description: 'should draw all elements except lines',
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [10, 15, 0, -4],
-                               label: 'dataset1',
-                               borderColor: 'red',
-                               backgroundColor: 'green',
-                               fill: true
-                       }],
-                       labels: ['label1', 'label2', 'label3', 'label4']
-               },
-               options: {
-                       showLine: false,
-                       scales: {
-                               x: {
-                                       display: false
-                               },
-                               y: {
-                                       display: false
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       }
+  description: 'should draw all elements except lines',
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [10, 15, 0, -4],
+        label: 'dataset1',
+        borderColor: 'red',
+        backgroundColor: 'green',
+        fill: true
+      }],
+      labels: ['label1', 'label2', 'label3', 'label4']
+    },
+    options: {
+      showLine: false,
+      scales: {
+        x: {
+          display: false
+        },
+        y: {
+          display: false
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  }
 };
index 073afcda5b68e8b59f1845393882b12e5bb6814d..18c694f752134e41f5c9767152ceb8142a481684 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [3, 1, 2, 0, 8, 1],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       backgroundColor: '#00ff00'
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true
-                               },
-                               point: {
-                                       radius: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {stacked: true, display: false},
-                               y: {stacked: true, display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [3, 1, 2, 0, 8, 1],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [0, 4, 2, 6, 4, 8],
+          backgroundColor: '#00ff00'
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true
+        },
+        point: {
+          radius: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {stacked: true, display: false},
+        y: {stacked: true, display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 811496e30532ca84479943770f08f346f41f19b7..262988d8a370c5c8dc42f7714159fb73b303d6cb 100644 (file)
@@ -1,51 +1,51 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [3, 1, 2, 0, 8, 1],
-                                       backgroundColor: '#ff0000',
-                                       order: 2
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 4, 2, 6, 4, 8],
-                                       backgroundColor: '#00ff00',
-                                       order: 1
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: true
-                               },
-                               point: {
-                                       radius: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               x: {stacked: true, display: false},
-                               y: {stacked: true, display: false}
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [3, 1, 2, 0, 8, 1],
+          backgroundColor: '#ff0000',
+          order: 2
+        },
+        {
+          // option in element (fallback)
+          data: [0, 4, 2, 6, 4, 8],
+          backgroundColor: '#00ff00',
+          order: 1
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: true
+        },
+        point: {
+          radius: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        x: {stacked: true, display: false},
+        y: {stacked: true, display: false}
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a8085b629f3f97d14d87f30b07ae3f2cc4d397f0..00da2a77bd5c27b50159753c1c6d484e08d57436 100644 (file)
@@ -1,74 +1,74 @@
 module.exports = {
-       config: {
-               type: 'scatter',
-               data: {
-                       datasets: [{
-                               label: 'label1',
-                               data: [{
-                                       x: 0,
-                                       y: 30
-                               }, {
-                                       x: 5,
-                                       y: 35
-                               }, {
-                                       x: 10,
-                                       y: 20
-                               }],
-                               backgroundColor: '#42A8E4'
-                       },
-                       {
-                               label: 'label2',
-                               data: [{
-                                       x: 0,
-                                       y: 10
-                               }, {
-                                       x: 5,
-                                       y: 15
-                               }, {
-                                       x: 10,
-                                       y: 15
-                               }],
-                               backgroundColor: '#FC3F55'
-                       },
-                       {
-                               label: 'label3',
-                               data: [{
-                                       x: 0,
-                                       y: -15
-                               }, {
-                                       x: 5,
-                                       y: -10
-                               }, {
-                                       x: 10,
-                                       y: -20
-                               }],
-                               backgroundColor: '#FFBE3F'
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       display: false,
-                                       position: 'bottom',
-                               },
-                               y: {
-                                       stacked: true,
-                                       display: false,
-                                       position: 'left',
-                               },
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               },
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'scatter',
+    data: {
+      datasets: [{
+        label: 'label1',
+        data: [{
+          x: 0,
+          y: 30
+        }, {
+          x: 5,
+          y: 35
+        }, {
+          x: 10,
+          y: 20
+        }],
+        backgroundColor: '#42A8E4'
+      },
+      {
+        label: 'label2',
+        data: [{
+          x: 0,
+          y: 10
+        }, {
+          x: 5,
+          y: 15
+        }, {
+          x: 10,
+          y: 15
+        }],
+        backgroundColor: '#FC3F55'
+      },
+      {
+        label: 'label3',
+        data: [{
+          x: 0,
+          y: -15
+        }, {
+          x: 5,
+          y: -10
+        }, {
+          x: 10,
+          y: -20
+        }],
+        backgroundColor: '#FFBE3F'
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          display: false,
+          position: 'bottom',
+        },
+        y: {
+          stacked: true,
+          display: false,
+          position: 'left',
+        },
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    },
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ab4f654fe3751f260f427ffaf50ccf78b26fb082..1b92d096bae6b7bfd7c8ceda33068086568dcaa2 100644 (file)
@@ -1,35 +1,35 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                       ]
-               },
-               options: {
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+      ]
+    },
+    options: {
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 813d18274f2dc9313f7fdbffb637a1d16fddc5f9..fb3d4f42ce46efc2c53479e088c811e5b10996c3 100644 (file)
@@ -1,39 +1,39 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ]
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ]
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index e3754faf45f6dc429fac199a38ef6f3b46e29045..8d11108aadf01519c0bbc39d36e0ee4af85f9950 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                       ]
-               },
-               options: {
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+      ]
+    },
+    options: {
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index dd9651c4c6fc8d92b74b5f853786f588820ac317..36415025c2c67bd61367d8d601c675900da82599 100644 (file)
@@ -1,38 +1,38 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 5fe96ce475eaf6d0f28eae3681014934c2adeae5..b9be824a6f0fab9eb9557b5caaf5241049704c84 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       backgroundColor: '#ff0000'
-                               },
-                       ]
-               },
-               options: {
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          backgroundColor: '#ff0000'
+        },
+      ]
+    },
+    options: {
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1b6fef8e62ec19cb994562d0ebdd04031912c2ff..f68b70dbf09b534f895ddc000e2b4f7367ac83a9 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: '#00ff00'
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: '#00ff00'
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 5f121da5bd5bd34ab91db7aebeac50dc58788bd3..99b285d385f22f095f993b530fffb5514784a85e 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: [
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                       ],
-                                       borderColor: '#00ff00'
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff0000',
-                                       borderWidth: 5,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: [
+            'center',
+            'inner',
+            'center',
+            'inner',
+            'center',
+            'inner',
+          ],
+          borderColor: '#00ff00'
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff0000',
+          borderWidth: 5,
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 8a3cc5c94e8c54383a55358ba6511604abf04ac1..fcdb698d47d4bcf1ca1662b0c7fb1b9f91ab4c00 100644 (file)
@@ -1,42 +1,42 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff0000',
-                                       borderWidth: 5,
-                                       borderAlign: [
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                               'center',
-                                               'inner',
-                                       ]
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff0000',
+          borderWidth: 5,
+          borderAlign: [
+            'center',
+            'inner',
+            'center',
+            'inner',
+            'center',
+            'inner',
+          ]
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d86b4a924b08530f7e6edc422cdb3d3358349e39..6689e0841ac428048303e64779707b7ff8874eff 100644 (file)
@@ -1,39 +1,39 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 'inner' : 'center';
-                                       },
-                                       borderColor: '#0000ff',
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff00ff',
-                                       borderWidth: 8,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 'inner' : 'center';
+          },
+          borderColor: '#0000ff',
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff00ff',
+          borderWidth: 8,
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1cc9f41cea54f8d6133e03ba6c1c2ac02b240e30..4528cad8dc62ed0498cd20eeb3df4015bfbb1859 100644 (file)
@@ -1,38 +1,38 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#ff00ff',
-                                       borderWidth: 8,
-                                       borderAlign: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 'center' : 'inner';
-                                       }
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#ff00ff',
+          borderWidth: 8,
+          borderAlign: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 'center' : 'inner';
+          }
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 08c1a27b1a3d92262952fe4332fd97dd598b7c6b..c201cbfd9894de4cf215f56a17553d625a5bd6dd 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderAlign: 'inner',
-                                       borderColor: '#00ff00',
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#0000ff',
-                                       borderWidth: 4,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderAlign: 'inner',
+          borderColor: '#00ff00',
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#0000ff',
+          borderWidth: 4,
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index fff5d37e42ae7c5c439bf2adc9e5be903467e329..1f3ff0632e020b86eb529a905af57aecf7188eae 100644 (file)
@@ -1,35 +1,35 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderAlign: 'center',
-                                       borderColor: '#0000ff',
-                                       borderWidth: 4,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderAlign: 'center',
+          borderColor: '#0000ff',
+          borderWidth: 4,
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a9b8a49eed7e321412ea950907cc4770e862e22d..6d74af80c9ce94fa70b9abab439898e221d40262 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6a02f6b4d24b1b8b6995aa1a1f52a397debf4bd7..550ff4c6fc786f7b97f3b81f4b0dae12ebfb1886 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index e5639434643da3e8a2d94ff8ba5bbaea4e5d9aed..376cd4b951ae5ae040bcdc881c9e571611b574ee 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 6 ? '#00ff00'
-                                                       : value > 2 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 6 ? '#00ff00'
+              : value > 2 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 733b21933ba0eb0c3ebb9fa7de389b2652478a4c..985e868cca687728f1a8826a6433fec29a9d7145 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 6 ? '#0000ff'
-                                                       : value > 2 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 6 ? '#0000ff'
+              : value > 2 ? '#ff0000'
+              : '#00ff00';
+          },
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 925eddf2e7aae8f5c5fefdfd3fe22209bb999b75..d2d40f0c4ddeee0b2f5578fbd88b8afa09568e48 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderColor: '#ff0000'
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderColor: '#ff0000'
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b75ea24311fca215e11d8dadb407c1965ba73dbd..63b106aba93a924e533afe7b0f857dbcb1861c17 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#00ff00',
-                                       borderWidth: 8
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#00ff00',
+          borderWidth: 8
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 901612e1bc624b4c840ffd1007dd8dd468f7ff00..e968c2cd916d6a5470945b74054cbd25b63b5919 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: [
-                                               0,
-                                               1,
-                                               2,
-                                               3,
-                                               4,
-                                               5
-                                       ]
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: [
+            0,
+            1,
+            2,
+            3,
+            4,
+            5
+          ]
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 8b75cc985bf1c3365c2a1d5ccd0aafd2f30a923d..c18ce319546b7c0dd886841eb41d57307237fac0 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: [
-                                               5,
-                                               4,
-                                               3,
-                                               2,
-                                               1,
-                                               0
-                                       ]
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: [
+            5,
+            4,
+            3,
+            2,
+            1,
+            0
+          ]
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index bdd4b4e320419a6270e87947ee70152e22f6a2da..72801329928cd8e88f1942bfb574f29ee39d822e 100644 (file)
@@ -1,37 +1,37 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return Math.abs(value);
-                                       }
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return Math.abs(value);
+          }
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f57915eb827c68768191f68cb105d044ed2e7915..3bc685715be493efd5aa7d7004431578fb319c2d 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: function(ctx) {
-                                               return ctx.dataIndex * 2;
-                                       }
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: function(ctx) {
+            return ctx.dataIndex * 2;
+          }
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 0981b4e2beead8b1ff458a03fca48d7420ee6c89..019fa73c0f961b33dea14516d2f8f3aaf6994bae 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 2, 4, null, 6, 8],
-                                       borderWidth: 2
-                               },
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 2, 4, null, 6, 8],
+          borderWidth: 2
+        },
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 42d2a86be51bc67d772a90b97b1f2e50b0b31892..ce13ac48deaf06e0dd3fae26387d44c100b22f20 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'polarArea',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 2, 4, null, 6, 8],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               arc: {
-                                       backgroundColor: 'transparent',
-                                       borderColor: '#888',
-                                       borderWidth: 4
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'polarArea',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in element (fallback)
+          data: [0, 2, 4, null, 6, 8],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        arc: {
+          backgroundColor: 'transparent',
+          borderColor: '#888',
+          borderWidth: 4
+        }
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 54ccb5f1f2700d3b47ddfc1e3af5a70610b5cf15..8183eacb39f97da3ff8f55a5cd642e0af3874eba 100644 (file)
@@ -1,59 +1,59 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#ff00ff';
-                                       },
-                                       fill: true,
-                               },
-                               point: {
-                                       backgroundColor: '#0000ff',
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15,
-                               },
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#ff00ff';
+          },
+          fill: true,
+        },
+        point: {
+          backgroundColor: '#0000ff',
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15,
+        },
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 0c60841047dd7bc66475b1146d0147652fc2a364..6922182c66dd3f859cee962d8bd5fff96135c68e 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: '#00ff00',
-                                       fill: true,
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: '#00ff00',
+          fill: true,
+        },
+        point: {
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 0bd84298bbd381e95a2656e3fefb9edae340705f..420e994207dde0425b38dbc57d21a7aedbec3da8 100644 (file)
@@ -1,61 +1,61 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [null, 3, 3],
-                                       borderCapStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 2);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'square'
-                                                       : 'butt';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 2, 2]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 1, 1]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderCapStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 3);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'square'
-                                                       : 'butt';
-                                       },
-                                       borderColor: '#ff0000',
-                                       borderWidth: 32,
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          // option in dataset
+          data: [null, 3, 3],
+          borderCapStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 2);
+            return index === 0 ? 'round'
+              : index === 1 ? 'square'
+              : 'butt';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [null, 2, 2]
+        },
+        {
+          // option in element (fallback)
+          data: [null, 1, 1]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderCapStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 3);
+            return index === 0 ? 'round'
+              : index === 1 ? 'square'
+              : 'butt';
+          },
+          borderColor: '#ff0000',
+          borderWidth: 32,
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index c5b914f9ec41ad91668acd4977bc2d37270c5072..72fdcab17597b3c57a706932df9f9f45cf06719e 100644 (file)
@@ -1,52 +1,52 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [null, 3, 3],
-                                       borderCapStyle: 'round'
-                               },
-                               {
-                                       // option in dataset
-                                       data: [null, 2, 2],
-                                       borderCapStyle: 'square'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [null, 1, 1]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderCapStyle: 'butt',
-                                       borderColor: '#00ff00',
-                                       borderWidth: 32,
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2],
+      datasets: [
+        {
+          // option in dataset
+          data: [null, 3, 3],
+          borderCapStyle: 'round'
+        },
+        {
+          // option in dataset
+          data: [null, 2, 2],
+          borderCapStyle: 'square'
+        },
+        {
+          // option in element (fallback)
+          data: [null, 1, 1]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderCapStyle: 'butt',
+          borderColor: '#00ff00',
+          borderWidth: 32,
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index b301e2e9efec505f9a37f0873fcee137af07ec6f..14fa9fcb6b6d3498e500b93e0a4f021a630b27c8 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#0000ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: function(ctx) {
-                                               var index = ctx.index;
-                                               return index === 0 ? '#ff0000'
-                                                       : index === 1 ? '#00ff00'
-                                                       : '#0000ff';
-                                       },
-                                       borderWidth: 10,
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: 10,
-                                       radius: 16
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#0000ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: function(ctx) {
+            var index = ctx.index;
+            return index === 0 ? '#ff0000'
+              : index === 1 ? '#00ff00'
+              : '#0000ff';
+          },
+          borderWidth: 10,
+          fill: false
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: 10,
+          radius: 16
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index ce40c1d4f7b28dc570bab61378ba608bb0d97a3b..5e130c29df6608e72681cfc8e0bbc1893af992d1 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#0000ff',
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#0000ff',
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#0000ff',
+          fill: false
+        },
+        point: {
+          borderColor: '#0000ff',
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index a26873c11369708b8fb787eb761274b39f4d26c8..de31f9ddf9c0016378ce6d4de4d3f7ff0aee741d 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderDash: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? [5] : [10];
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? [5] : [10];
-                                       },
-                                       fill: true,
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderDash: function(ctx) {
+            return ctx.datasetIndex === 0 ? [5] : [10];
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: function(ctx) {
+            return ctx.datasetIndex === 0 ? [5] : [10];
+          },
+          fill: true,
+        },
+        point: {
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 3d19af8983929afc12f7cb8cb682bb97fd98d683..933b8b36a84a8c24f9f0e593fee9547ab89606b8 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#ff0000',
-                                       borderDash: [5]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [10],
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#ff0000',
+          borderDash: [5]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [10],
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 0aecff6d4091e54b91e55ee22aa1b61fb2ab46b0..4de8f892523a6758ff8f540e4cc37ebdffb99f60 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [1, 1, 1, 1],
-                                       borderColor: '#ff0000',
-                                       borderDash: [20],
-                                       borderDashOffset: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 5.0 : 0.0;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 0, 0, 0]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [20],
-                                       borderDashOffset: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? 5.0 : 0.0;
-                                       },
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -1
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [1, 1, 1, 1],
+          borderColor: '#ff0000',
+          borderDash: [20],
+          borderDashOffset: function(ctx) {
+            return ctx.datasetIndex === 0 ? 5.0 : 0.0;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [0, 0, 0, 0]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [20],
+          borderDashOffset: function(ctx) {
+            return ctx.datasetIndex === 0 ? 5.0 : 0.0;
+          },
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -1
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 18d0bcc478335ee499bc1bfe750bcfc63a32f747..d24cc4ff15d492e3e292a1741e6d89a3b9becb9c 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [1, 1, 1, 1, 1, 1],
-                                       borderColor: '#ff0000',
-                                       borderDash: [20],
-                                       borderDashOffset: 5.0
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [0, 0, 0, 0, 0, 0]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderDash: [20],
-                                       borderDashOffset: 0.0, // default
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -1
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [1, 1, 1, 1, 1, 1],
+          borderColor: '#ff0000',
+          borderDash: [20],
+          borderDashOffset: 5.0
+        },
+        {
+          // option in element (fallback)
+          data: [0, 0, 0, 0, 0, 0]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderDash: [20],
+          borderDashOffset: 0.0, // default
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -1
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index d36a3a0503541ff831411a4c6a96a078f475ed61..a1d73c48c2c651844db7c0ebfcd2eee21da7b66e 100644 (file)
@@ -1,61 +1,61 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [3, 3, null, 3],
-                                       borderColor: '#ff0000',
-                                       borderJoinStyle: function(ctx) {
-                                               var index = ctx.datasetIndex % 3;
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'miter'
-                                                       : 'bevel';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 2, null, 2],
-                                       borderColor: '#0000ff'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [1, 1, null, 1]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderJoinStyle: function(ctx) {
-                                               var index = (ctx.datasetIndex % 3);
-                                               return index === 0 ? 'round'
-                                                       : index === 1 ? 'miter'
-                                                       : 'bevel';
-                                       },
-                                       borderWidth: 25,
-                                       fill: false,
-                                       tension: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [3, 3, null, 3],
+          borderColor: '#ff0000',
+          borderJoinStyle: function(ctx) {
+            var index = ctx.datasetIndex % 3;
+            return index === 0 ? 'round'
+              : index === 1 ? 'miter'
+              : 'bevel';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [2, 2, null, 2],
+          borderColor: '#0000ff'
+        },
+        {
+          // option in element (fallback)
+          data: [1, 1, null, 1]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderJoinStyle: function(ctx) {
+            var index = (ctx.datasetIndex % 3);
+            return index === 0 ? 'round'
+              : index === 1 ? 'miter'
+              : 'bevel';
+          },
+          borderWidth: 25,
+          fill: false,
+          tension: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index fc05fb2515ad78f1919e4b4b479e6f3b4eb3a5b8..669fa561e1026a27a17c980dc4160a5d748c41df 100644 (file)
@@ -1,52 +1,52 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [3, 3, null, 3],
-                                       borderColor: '#ff0000',
-                                       borderJoinStyle: 'round'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [2, 2, null, 2],
-                                       borderColor: '#0000ff',
-                                       borderJoinStyle: 'bevel'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [1, 1, null, 1]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderJoinStyle: 'miter',
-                                       borderWidth: 25,
-                                       fill: false,
-                                       tension: 0
-                               }
-                       },
-                       layout: {
-                               padding: 32
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       beginAtZero: true
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3],
+      datasets: [
+        {
+          // option in dataset
+          data: [3, 3, null, 3],
+          borderColor: '#ff0000',
+          borderJoinStyle: 'round'
+        },
+        {
+          // option in element (fallback)
+          data: [2, 2, null, 2],
+          borderColor: '#0000ff',
+          borderJoinStyle: 'bevel'
+        },
+        {
+          // option in element (fallback)
+          data: [1, 1, null, 1]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderJoinStyle: 'miter',
+          borderWidth: 25,
+          fill: false,
+          tension: 0
+        }
+      },
+      layout: {
+        padding: 32
+      },
+      scales: {
+        r: {
+          display: false,
+          beginAtZero: true
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index dc0a8e0cf5f290fdcfddb278a97cc9fbaa79b3e5..2426ea2f127e82aac09b08cfe8970cf05a4ab12f 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#0000ff',
-                                       borderWidth: function(ctx) {
-                                               var index = ctx.index;
-                                               return index % 2 ? 10 : 20;
-                                       },
-                                       pointBorderColor: '#00ff00'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: function(ctx) {
-                                               var index = ctx.index;
-                                               return index % 2 ? 10 : 20;
-                                       },
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 5,
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#0000ff',
+          borderWidth: function(ctx) {
+            var index = ctx.index;
+            return index % 2 ? 10 : 20;
+          },
+          pointBorderColor: '#00ff00'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#ff0000',
+          borderWidth: function(ctx) {
+            var index = ctx.index;
+            return index % 2 ? 10 : 20;
+          },
+          fill: false
+        },
+        point: {
+          borderColor: '#00ff00',
+          borderWidth: 5,
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 91880c36eb5f8a19d146cdd2cce6097e9ff14ea9..58ee10d23bfdd3d657635794fd6d028c8c04bb61 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       borderColor: '#0000ff',
-                                       borderWidth: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 3,
-                                       fill: false
-                               },
-                               point: {
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          borderColor: '#0000ff',
+          borderWidth: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 3,
+          fill: false
+        },
+        point: {
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index c7110b9be7480e50003102bbde830cdc897acfca..a1c8a8c618d679a2e9a45eb50ff8d96428de3b85 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#0000ff',
-                                       borderColor: '#0000ff',
-                                       borderWidth: 0,
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 1,
-                                       fill: false
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#0000ff',
+          borderColor: '#0000ff',
+          borderWidth: 0,
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          borderColor: '#00ff00',
+          borderWidth: 1,
+          fill: false
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
 
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index b8d42b3ad78a754dee3c6c68f555c157cbebaf5e..7ef108dea8642f076c1e39828b4986a22187cd86 100644 (file)
@@ -1,50 +1,50 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000',
-                                       fill: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? true : false;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: '#00ff00',
-                                       fill: function(ctx) {
-                                               return ctx.datasetIndex === 0 ? true : false;
-                                       }
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000',
+          fill: function(ctx) {
+            return ctx.datasetIndex === 0 ? true : false;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: '#00ff00',
+          fill: function(ctx) {
+            return ctx.datasetIndex === 0 ? true : false;
+          }
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 8f72f59d92c9f85c4c439c51f5a32aafd88d58a1..55fe8e197aab2a678ef5b8e66a97f9262282dcc0 100644 (file)
@@ -1,46 +1,46 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000',
-                                       fill: false
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       backgroundColor: '#00ff00',
-                                       fill: true
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000',
+          fill: false
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          backgroundColor: '#00ff00',
+          fill: true
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 2bfb94caf403d3e801403a223414161ebf7658f8..2e456f6a2ec98c192035261b836d57138bfa162f 100644 (file)
@@ -1,56 +1,56 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       backgroundColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          backgroundColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 7adbd97f04e229ad0a1c9aa728be2899199a7fcf..91b687cf6b2b3ee55c4d7a79eb4b329b0d9825c4 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          },
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 66e1d416e60029066ef5377d4fd1f5438ea2fd0e..b10722e601345a3b91c6ac1f46436609a3153dab 100644 (file)
@@ -1,42 +1,42 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 13351597872d9d290ec498609b0a31e23ae0a371..0b16c30177a18169cf7c4749772cf9e09ad848f6 100644 (file)
@@ -1,57 +1,57 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: [
-                                               '#ff0000',
-                                               '#00ff00',
-                                               '#0000ff',
-                                               '#ffff00',
-                                               '#ff00ff',
-                                               '#000000'
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: [
-                                               '#ff88ff',
-                                               '#888888',
-                                               '#ff8800',
-                                               '#00ff88',
-                                               '#8800ff',
-                                               '#ffff88'
-                                       ],
-                                       borderWidth: 5,
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: [
+            '#ff0000',
+            '#00ff00',
+            '#0000ff',
+            '#ffff00',
+            '#ff00ff',
+            '#000000'
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: [
+            '#ff88ff',
+            '#888888',
+            '#ff8800',
+            '#00ff88',
+            '#8800ff',
+            '#ffff88'
+          ],
+          borderWidth: 5,
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 9e0cf8b8912fe8a30d07db32ed45351b15e5aa26..dcf5f75bf802c823118b275fe330f2f6dd3325c5 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff0000'
-                                                       : value > 0 ? '#00ff00'
-                                                       : value > -8 ? '#0000ff'
-                                                       : '#ff00ff';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? '#ff00ff'
-                                                       : value > 0 ? '#0000ff'
-                                                       : value > -8 ? '#ff0000'
-                                                       : '#00ff00';
-                                       },
-                                       borderWidth: 5,
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff0000'
+              : value > 0 ? '#00ff00'
+              : value > -8 ? '#0000ff'
+              : '#ff00ff';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? '#ff00ff'
+              : value > 0 ? '#0000ff'
+              : value > -8 ? '#ff0000'
+              : '#00ff00';
+          },
+          borderWidth: 5,
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index ef4fdbebf672a17873ad67a3bbfc5211b4dabe1d..a986abdf5228f10f290021962a2fb3cb2cfe45e7 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#ff0000'
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 5,
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#ff0000'
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: '#00ff00',
+          borderWidth: 5,
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 7accea2d0f54f43f9c42cfa782458ea19d6c1e76..a8e8838e1bc7f1217a3b61c60fc62564e02c4ce5 100644 (file)
@@ -1,48 +1,48 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#00ff00',
-                                       pointBorderWidth: [
-                                               1, 2, 3, 4, 5, 6
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: [
-                                               6, 5, 4, 3, 2, 1
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#00ff00',
+          pointBorderWidth: [
+            1, 2, 3, 4, 5, 6
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: [
+            6, 5, 4, 3, 2, 1
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 65bd8480d362ee42843be5dca361d9556a1125d2..adb76a66518b9b85e4c7f3c46ff1b56aed93a116 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointBorderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 10
-                                                       : value > -4 ? 5
-                                                       : 2;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 2
-                                                       : value > -4 ? 5
-                                                       : 10;
-                                       },
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointBorderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 10
+              : value > -4 ? 5
+              : 2;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 2
+              : value > -4 ? 5
+              : 10;
+          },
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 91555695d0a6592d162242ad7b70312587a44496..561ea121b4308ea592ef892fd33d9b19cc40f5c2 100644 (file)
@@ -1,44 +1,44 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointBorderWidth: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       borderWidth: 3,
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointBorderWidth: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false
+        },
+        point: {
+          borderColor: '#00ff00',
+          borderWidth: 3,
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index b9cf41dfa112d2cde4603c75d4b41c44c18f408a..65afe0be2489272fc7d597f2a20c202e3d94f715 100644 (file)
@@ -1,60 +1,60 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000',
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: [
-                                               'circle',
-                                               'cross',
-                                               'crossRot',
-                                               'dash',
-                                               'line',
-                                               'rect',
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#00ff00',
-                                       pointStyle: [
-                                               'line',
-                                               'rect',
-                                               'rectRounded',
-                                               'rectRot',
-                                               'star',
-                                               'triangle'
-                                       ],
-                                       radius: 10
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000',
+          pointBorderColor: '#ff0000',
+          pointStyle: [
+            'circle',
+            'cross',
+            'crossRot',
+            'dash',
+            'line',
+            'rect',
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          borderColor: '#00ff00',
+          pointStyle: [
+            'line',
+            'rect',
+            'rectRounded',
+            'rectRot',
+            'star',
+            'triangle'
+          ],
+          radius: 10
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index eac8628d08700e8194a3f18f8dc48880fa30f621..5a793cb1e7cd27ac7141b7c94e5274c7c0f88a1e 100644 (file)
@@ -1,58 +1,58 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#ff0000',
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? 'rect'
-                                                       : value > 0 ? 'star'
-                                                       : value > -8 ? 'cross'
-                                                       : 'triangle';
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#0000ff',
-                                       borderColor: '#0000ff',
-                                       pointStyle: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 8 ? 'triangle'
-                                                       : value > 0 ? 'cross'
-                                                       : value > -8 ? 'star'
-                                                       : 'rect';
-                                       },
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#ff0000',
+          pointBorderColor: '#ff0000',
+          pointStyle: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? 'rect'
+              : value > 0 ? 'star'
+              : value > -8 ? 'cross'
+              : 'triangle';
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#0000ff',
+          borderColor: '#0000ff',
+          pointStyle: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 8 ? 'triangle'
+              : value > 0 ? 'cross'
+              : value > -8 ? 'star'
+              : 'rect';
+          },
+          radius: 10,
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 7197528816e946edfa5f53cac7b65bcae6a53236..20b0bb48fd07a2ed29b9790e5097774e6bbd6ebb 100644 (file)
@@ -1,44 +1,44 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#ff0000',
-                                       pointStyle: 'star',
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       pointStyle: 'rect',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#ff0000',
+          pointStyle: 'star',
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          pointStyle: 'rect',
+          radius: 10,
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 9eb23f09177f45611fe8100e3b81d633884d3523..da639ea6624e3f3bb7344058aa368860eb10f65f 100644 (file)
@@ -1,47 +1,47 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#00ff00',
-                                       pointRadius: [
-                                               1, 2, 3, 4, 5, 6
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#ff0000',
-                                       radius: [
-                                               6, 5, 4, 3, 2, 1
-                                       ],
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#00ff00',
+          pointRadius: [
+            1, 2, 3, 4, 5, 6
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#ff0000',
+          radius: [
+            6, 5, 4, 3, 2, 1
+          ],
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index d5fc1a8145d8afab24d2e4639d2f00d5545e25be..5be5197ea1913400bc47ae9e4866eadd79bf99c0 100644 (file)
@@ -1,53 +1,53 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#0000ff',
-                                       pointRadius: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 10
-                                                       : value > -4 ? 5
-                                                       : 2;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#ff0000',
-                                       radius: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 2
-                                                       : value > -4 ? 5
-                                                       : 10;
-                                       },
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#0000ff',
+          pointRadius: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 10
+              : value > -4 ? 5
+              : 2;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#ff0000',
+          radius: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 2
+              : value > -4 ? 5
+              : 10;
+          },
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index d7bc6b8e07d81f621a78a02a5ab821fec3862ba3..92bb6acd3f9932107d604bd605cbf8b44f2b11d3 100644 (file)
@@ -1,43 +1,43 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBackgroundColor: '#0000ff',
-                                       pointRadius: 6
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       backgroundColor: '#00ff00',
-                                       radius: 3,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBackgroundColor: '#0000ff',
+          pointRadius: 6
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          backgroundColor: '#00ff00',
+          radius: 3,
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 8f22a396b351f44a31ba47653687dcffb8812927..a678634e2e6e045bdf0666654347749dbe1b4548 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#00ff00',
-                                       pointRotation: [
-                                               0, 30, 60, 90, 120, 150
-                                       ]
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       borderWidth: 10,
-                                       pointStyle: 'line',
-                                       rotation: [
-                                               150, 120, 90, 60, 30, 0
-                                       ],
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#00ff00',
+          pointRotation: [
+            0, 30, 60, 90, 120, 150
+          ]
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          borderWidth: 10,
+          pointStyle: 'line',
+          rotation: [
+            150, 120, 90, 60, 30, 0
+          ],
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 890e02c2ab049b494427e6295ada34490c027bcc..1ccb85c56a4ccf4f46c89da0526f758a793b34ad 100644 (file)
@@ -1,55 +1,55 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointRotation: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 120
-                                                       : value > -4 ? 60
-                                                       : 0;
-                                       }
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#ff0000',
-                                       rotation: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value > 4 ? 0
-                                                       : value > -4 ? 60
-                                                       : 120;
-                                       },
-                                       pointStyle: 'line',
-                                       radius: 10,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointRotation: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 120
+              : value > -4 ? 60
+              : 0;
+          }
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#ff0000',
+          rotation: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value > 4 ? 0
+              : value > -4 ? 60
+              : 120;
+          },
+          pointStyle: 'line',
+          radius: 10,
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 5a1959d668d85180d9daf93d6940bbca84a5aaf5..93306e88a1ef93600aa32cdc439f8e67f6231c68 100644 (file)
@@ -1,45 +1,45 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       pointBorderColor: '#0000ff',
-                                       pointRotation: 90
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5],
-                               }
-                       ]
-               },
-               options: {
-                       elements: {
-                               line: {
-                                       fill: false,
-                               },
-                               point: {
-                                       borderColor: '#00ff00',
-                                       pointStyle: 'line',
-                                       radius: 10,
-                                       rotation: 0,
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          pointBorderColor: '#0000ff',
+          pointRotation: 90
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5],
+        }
+      ]
+    },
+    options: {
+      elements: {
+        line: {
+          fill: false,
+        },
+        point: {
+          borderColor: '#00ff00',
+          pointStyle: 'line',
+          radius: 10,
+          rotation: 0,
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index c933450dd0664ce9185b83e7f65ab238a3e482fb..9182916f116ac07440da1db42b275ef6785077a9 100644 (file)
@@ -1,54 +1,54 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5],
-                       datasets: [
-                               {
-                                       // option in dataset
-                                       data: [0, 5, 10, null, -10, -5],
-                                       backgroundColor: '#ff0000',
-                                       fill: false,
-                                       showLine: true
-                               },
-                               {
-                                       // option in element (fallback)
-                                       data: [4, -5, -10, null, 10, 5]
-                               },
-                               {
-                                       data: [1, 1, 1, 1, 1, 1],
-                                       showLine: true,
-                                       backgroundColor: 'rgba(0,0,255,0.5)'
-                               }
-                       ]
-               },
-               options: {
-                       showLine: false,
-                       elements: {
-                               line: {
-                                       borderColor: '#ff0000',
-                                       backgroundColor: 'rgba(0,255,0,0.5)',
-                                       fill: true
-                               }
-                       },
-                       scales: {
-                               r: {
-                                       display: false,
-                                       min: -15
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false,
-                               filler: true
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5],
+      datasets: [
+        {
+          // option in dataset
+          data: [0, 5, 10, null, -10, -5],
+          backgroundColor: '#ff0000',
+          fill: false,
+          showLine: true
+        },
+        {
+          // option in element (fallback)
+          data: [4, -5, -10, null, 10, 5]
+        },
+        {
+          data: [1, 1, 1, 1, 1, 1],
+          showLine: true,
+          backgroundColor: 'rgba(0,0,255,0.5)'
+        }
+      ]
+    },
+    options: {
+      showLine: false,
+      elements: {
+        line: {
+          borderColor: '#ff0000',
+          backgroundColor: 'rgba(0,255,0,0.5)',
+          fill: true
+        }
+      },
+      scales: {
+        r: {
+          display: false,
+          min: -15
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false,
+        filler: true
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 7c8732acfa069d100d3447c9f7121efdb53efadd..34acd44c549ca0752dd2e48a87fa7d2d155aface 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       description: 'showLine option should draw a line if true',
-       config: {
-               type: 'scatter',
-               data: {
-                       datasets: [{
-                               data: [{x: 10, y: 15}, {x: 15, y: 10}],
-                               pointRadius: 10,
-                               backgroundColor: 'red',
-                               showLine: true,
-                               label: 'dataset1'
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       display: false
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       width: 256,
-                       height: 256
-               }
-       }
+  description: 'showLine option should draw a line if true',
+  config: {
+    type: 'scatter',
+    data: {
+      datasets: [{
+        data: [{x: 10, y: 15}, {x: 15, y: 10}],
+        pointRadius: 10,
+        backgroundColor: 'red',
+        showLine: true,
+        label: 'dataset1'
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          display: false
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      width: 256,
+      height: 256
+    }
+  }
 };
index de4cf7fe327094f54e72e7d2dc3c8848b6b15c6b..4a969ed6f773bc13375ff98a5300a57f442b92c4 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       description: 'showLine option should not draw a line if undefined',
-       config: {
-               type: 'scatter',
-               data: {
-                       datasets: [{
-                               data: [{x: 10, y: 15}, {x: 15, y: 10}],
-                               pointRadius: 10,
-                               backgroundColor: 'red',
-                               label: 'dataset1'
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       display: false
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       width: 256,
-                       height: 256
-               }
-       }
+  description: 'showLine option should not draw a line if undefined',
+  config: {
+    type: 'scatter',
+    data: {
+      datasets: [{
+        data: [{x: 10, y: 15}, {x: 15, y: 10}],
+        pointRadius: 10,
+        backgroundColor: 'red',
+        label: 'dataset1'
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          display: false
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      width: 256,
+      height: 256
+    }
+  }
 };
index 97afe9abfb4c99b03936af326370de0cac589c89..034207680c6e523755ee6689c6d4eaf4f625a248 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {data: [10, 5, 0, 25, 78, -10]}
-                       ],
-                       labels: ['tick1 is very long one', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6 is very long one']
-               },
-               options: {
-                       plugins: {
-                               legend: false
-                       },
-                       scales: {
-                               x: {
-                                       type: 'category',
-                                       ticks: {
-                                               maxRotation: 0,
-                                               autoSkip: false
-                                       }
-                               },
-                               y: {
-                                       type: 'linear',
-                                       position: 'right'
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 150,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {data: [10, 5, 0, 25, 78, -10]}
+      ],
+      labels: ['tick1 is very long one', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6 is very long one']
+    },
+    options: {
+      plugins: {
+        legend: false
+      },
+      scales: {
+        x: {
+          type: 'category',
+          ticks: {
+            maxRotation: 0,
+            autoSkip: false
+          }
+        },
+        y: {
+          type: 'linear',
+          position: 'right'
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 150,
+      width: 512
+    }
+  }
 };
index f31a6d4a999bf969855081fd19c3725c052ecb69..a541f94df74b0a3a053ba1cce3f7e7b5b1b90f23 100644 (file)
@@ -1,49 +1,49 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {data: [10, 5, 0, 25, 78, -10]}
-                       ],
-                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-               },
-               options: {
-                       layout: {
-                               padding: function(ctx) {
-                                       // 10% padding
-                                       const horizontalPadding = ctx.chart.width * 0.1;
-                                       const verticalPadding = ctx.chart.height * 0.1;
-                                       return {
-                                               top: verticalPadding,
-                                               right: horizontalPadding,
-                                               bottom: verticalPadding,
-                                               left: horizontalPadding
-                                       };
-                               }
-                       },
-                       plugins: {
-                               legend: false
-                       },
-                       scales: {
-                               x: {
-                                       type: 'category',
-                                       ticks: {
-                                               maxRotation: 0,
-                                               autoSkip: false
-                                       }
-                               },
-                               y: {
-                                       type: 'linear',
-                                       position: 'right'
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 150,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {data: [10, 5, 0, 25, 78, -10]}
+      ],
+      labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+    },
+    options: {
+      layout: {
+        padding: function(ctx) {
+          // 10% padding
+          const horizontalPadding = ctx.chart.width * 0.1;
+          const verticalPadding = ctx.chart.height * 0.1;
+          return {
+            top: verticalPadding,
+            right: horizontalPadding,
+            bottom: verticalPadding,
+            left: horizontalPadding
+          };
+        }
+      },
+      plugins: {
+        legend: false
+      },
+      scales: {
+        x: {
+          type: 'category',
+          ticks: {
+            maxRotation: 0,
+            autoSkip: false
+          }
+        },
+        y: {
+          type: 'linear',
+          position: 'right'
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 150,
+      width: 512
+    }
+  }
 };
index e98994242f80794ba86e0c21138cfab4464f8442..0aa42829a6a3081908ca5da084aaae8a469acf28 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               crossAlign: 'center',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            crossAlign: 'center',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d5cfee5b7a39981fd51b4e19947b1b79bd98775e..b0e5dc14a51bd310f606f2ed839e294b1b10ab97 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            crossAlign: 'far',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 659aa2c6a432f917fc2e4b556dcd0b277abeeb58..744a60a7a599f4f762f96ccd6b4f4c787abcbbec 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               crossAlign: 'near',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            crossAlign: 'near',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a2964b44f776aac494e83e4306fed060a911f071..dd62e7881da8cd72e6a30393e9efa864983abef2 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'left',
-                                       ticks: {
-                                               crossAlign: 'center',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'left',
+          ticks: {
+            crossAlign: 'center',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 27a936dce2caae0318fe880ee9e3701c6ffc060a..435cb64bcc09e5337d3bd031e3dd341683976e46 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'left',
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                                       afterFit: axis => {
-                                               axis.width = 64;
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'left',
+          ticks: {
+            crossAlign: 'far',
+          },
+          afterFit: axis => {
+            axis.width = 64;
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a2cdb723bcace4e2f5976673cc7864b3a28fee71..82a1ab8f23750fbfa281f64b50415b470927a813 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'left',
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'left',
+          ticks: {
+            crossAlign: 'far',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 69ea769d4f7111b5887e2c643bc2cb7fcd647ef6..75ca877b25596857fd26e0da48be5e0600653af2 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'left',
-                                       ticks: {
-                                               crossAlign: 'near',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'left',
+          ticks: {
+            crossAlign: 'near',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ab31fd4a42ad8df0cf4e3ff10c8a8d9519141bf9..94230cbe67040f4b479558457c7ffabd4cded6b2 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'right',
-                                       ticks: {
-                                               crossAlign: 'center',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'right',
+          ticks: {
+            crossAlign: 'center',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 893b293d4114e2f6d6a894f6f279dc4f18aff6c6..3bd14fff62af85947480fac841d0cd3b5f7381df 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'right',
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                                       afterFit: axis => {
-                                               axis.width = 64;
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       },
-       tolerance: 0.1
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'right',
+          ticks: {
+            crossAlign: 'far',
+          },
+          afterFit: axis => {
+            axis.width = 64;
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  },
+  tolerance: 0.1
 };
index dc2d1a16d51143da2342dd31201682845c338790..ccde8ff66b17fe8d0011d10fc8aa8f0c8eeec95e 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'right',
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'right',
+          ticks: {
+            crossAlign: 'far',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 7bcba8f86a85b8ff63d8f0cebfc754244dcadc40..0e94a47d13e710c7b9830f2fdc431a8e89b05eba 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Long long label 1', 'Label2', 'Label3']
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               y: {
-                                       position: 'right',
-                                       ticks: {
-                                               crossAlign: 'near',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Long long label 1', 'Label2', 'Label3']
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        y: {
+          position: 'right',
+          ticks: {
+            crossAlign: 'near',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 9096a4f37dece479f029441c0b7b418f86bd77d7..0f4ddc20ad88ff485a9c3f99079668d28f4f2f3f 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       position: 'top',
-                                       ticks: {
-                                               crossAlign: 'center',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          position: 'top',
+          ticks: {
+            crossAlign: 'center',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index e4d16b9773012849b256e443c1e3cdded5f21676..4232f0ff42aa560f220934cb7e02070750eacadf 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       position: 'top',
-                                       ticks: {
-                                               crossAlign: 'far',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          position: 'top',
+          ticks: {
+            crossAlign: 'far',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 707b3cc492b73b3b560c4343729d7a0e42e201ec..a8fa9e268bcdbc1c83c5f1b22458e9a50f47fabb 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       position: 'top',
-                                       ticks: {
-                                               crossAlign: 'near',
-                                       },
-                               },
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: [['Label1', 'line 2', 'line3'], 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          position: 'top',
+          ticks: {
+            crossAlign: 'near',
+          },
+        },
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1093cecd05aa8a03b073ab7523b68e3a5dda6a34..41adf1df602d6ae4fc7e8e6869fd5d458756f612 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Label1', 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               align: 'center',
-                                       },
-                               },
-                               y: {
-                                       ticks: {
-                                               align: 'center',
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Label1', 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            align: 'center',
+          },
+        },
+        y: {
+          ticks: {
+            align: 'center',
+          }
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b2b5bdf4eb34bba7fb8a6aa68cfcc850ec6c6b51..36aa984b0820a19fd0daf995526a55d09b5ee5a3 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Label1', 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               align: 'end',
-                                       },
-                               },
-                               y: {
-                                       ticks: {
-                                               align: 'end',
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Label1', 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            align: 'end',
+          },
+        },
+        y: {
+          ticks: {
+            align: 'end',
+          }
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f8d96d36e99e3872a506bc64a6efc181a6c2ac22..fa23a49cfa71075ddba1c4f51d44824ec3d3bb0a 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [1, 2, 3],
-                       }],
-                       labels: ['Label1', 'Label2', 'Label3']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       ticks: {
-                                               align: 'start',
-                                       },
-                               },
-                               y: {
-                                       ticks: {
-                                               align: 'start',
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [1, 2, 3],
+      }],
+      labels: ['Label1', 'Label2', 'Label3']
+    },
+    options: {
+      scales: {
+        x: {
+          ticks: {
+            align: 'start',
+          },
+        },
+        y: {
+          ticks: {
+            align: 'start',
+          }
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 1b55944ecfa49f288cbbc84941a4adc2c8d0e468..3fe92986d85e1e08109711813e81009bc8ca6a5e 100644 (file)
@@ -1,24 +1,24 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 80df30a6b7c66c65417df2e15b9fc7ef5adcd474..af52ef0f40f39aee9f3e0a6eb728cf5eed354f35 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 0, y: NaN}, {x: NaN, y: 0}, {x: NaN, y: -10}, {x: 19, y: NaN}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 0, y: NaN}, {x: NaN, y: 0}, {x: NaN, y: -10}, {x: 19, y: NaN}],
+          borderColor: 'red',
+          fill: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 7bd53d3eec299c1a6f5b90149ce92d6317b05d85..823807de189493f458a297e92edc3ad020cdd1a1 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: NaN, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       spanGaps: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: NaN, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          spanGaps: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2f3b8a8ccb4567a88ff4c66fea332e4313ed7d64..268434154b7e91362fddc3cf7f2474e10314e6ab 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: NaN, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: NaN, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 147d8252c6672ea905b70ff9d8d00fef9e7152c1..39a021902472067b3bb7914dbf04695538e5da83 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: NaN, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       spanGaps: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: NaN, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          spanGaps: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6f991a45c4dc6f80e9375bd33e96e4540de642fd..239a958a0ba8f4a4b7e4b96e5dcca5abea1cc563 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: NaN, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: NaN, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 94bb63716c24923db74a0d7d6d71bbf3b0afd9dc..8abfa4c34d892de6548673597d871829ff697555 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: NaN, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       spanGaps: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: NaN, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          spanGaps: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6773e75b50a41766cd25d450f7c32d3d26976b9d..af846270fe354467896c005f2df729d1771524a6 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: NaN, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: true,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 0, y: 10}, {x: 5, y: 0}, {x: NaN, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: true,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index b9c29556097f7c187939a6c0079a41b3481bc367..7dcd31aeafec418f50ff164895183d30b2e6f8ab 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 0,
-                                       stepped: 'after'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 0,
+          stepped: 'after'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index ee4fb6f6ea37f6ed03ae2c2abe1ae61f49838723..5046066bdd939a8331e0a4df01fc8ff6292e0c5b 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 0,
-                                       stepped: 'before'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 0,
+          stepped: 'before'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 18943ebfc1042bc889e9fb792f3d13a8cf6c50aa..6bbe05141475a04dbdcd7d5276f1b6f641ed554a 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 0,
-                                       stepped: true
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 0,
+          stepped: true
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 69ec1d0171d8eb6eaf9e55f036d7ed764eafd6d2..150928149291e998fab6dfb8ff8c317ac566d5bc 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 0,
-                                       stepped: 'middle'
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 0,
+          stepped: 'middle'
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index d858aa38022fd9fb21e542a74bae56f898959042..0f4f6203435f06416dfb2d44069f70b9df6252cc 100644 (file)
@@ -1,26 +1,26 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 83306599fbf0155e52acc446700b9a26675fe7db..9994e339ca4de2b346dff28e0725f549ef9cae84 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 1
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 1
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index f13a86c62d70d98eae080664a1fc61284cc95b4d..f251d5ed6069d692fc9aae9e076d8dc7bae8be09 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {
-                                       data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
-                                       borderColor: 'red',
-                                       fill: false,
-                                       tension: 0
-                               }
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {type: 'linear', display: false, min: 0, max: 20},
-                               y: {display: false, min: -15, max: 15}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {
+          data: [{x: 1, y: 10}, {x: 5, y: 0}, {x: 15, y: -10}, {x: 19, y: -5}],
+          borderColor: 'red',
+          fill: false,
+          tension: 0
+        }
+      ]
+    },
+    options: {
+      scales: {
+        x: {type: 'linear', display: false, min: 0, max: 20},
+        y: {display: false, min: -15, max: 15}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 6ac7a2a3dfe51c1a56f144acb811aa551caf2253..54eddf0da452596fe472cba6d49fdaa6f253f40f 100644 (file)
@@ -21,36 +21,36 @@ imageContext.closePath();
 imageContext.fill();
 
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       labels: [0, 1, 2, 3, 4, 5, 6, 7],
-                       datasets: [{
-                               data: [0, 0, 0, 0, 0, 0, 0, 0],
-                               showLine: false
-                       }]
-               },
-               options: {
-                       responsive: false,
-                       elements: {
-                               point: {
-                                       pointStyle: imageCanvas,
-                                       rotation: [0, 45, 90, 135, 180, 225, 270, 315]
-                               }
-                       },
-                       layout: {
-                               padding: 20
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      labels: [0, 1, 2, 3, 4, 5, 6, 7],
+      datasets: [{
+        data: [0, 0, 0, 0, 0, 0, 0, 0],
+        showLine: false
+      }]
+    },
+    options: {
+      responsive: false,
+      elements: {
+        point: {
+          pointStyle: imageCanvas,
+          rotation: [0, 45, 90, 135, 180, 225, 270, 315]
+        }
+      },
+      layout: {
+        padding: 20
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 2d2971d65fb1fcfbf873549a07f07907fa231962..6d2265e1ee237cbebb26184ca299c2b41e044ba8 100644 (file)
@@ -1,54 +1,54 @@
 var gradient;
 
 var datasets = ['circle', 'cross', 'crossRot', 'dash', 'line', 'rect', 'rectRounded', 'rectRot', 'star', 'triangle'].map(function(style, y) {
-       return {
-               pointStyle: style,
-               data: Array.apply(null, Array(17)).map(function(v, x) {
-                       return {x: x, y: 10 - y};
-               })
-       };
+  return {
+    pointStyle: style,
+    data: Array.apply(null, Array(17)).map(function(v, x) {
+      return {x: x, y: 10 - y};
+    })
+  };
 });
 
 var angles = Array.apply(null, Array(17)).map(function(v, i) {
-       return -180 + i * 22.5;
+  return -180 + i * 22.5;
 });
 
 module.exports = {
-       config: {
-               type: 'bubble',
-               data: {
-                       datasets: datasets
-               },
-               options: {
-                       responsive: false,
-                       elements: {
-                               point: {
-                                       rotation: angles,
-                                       radius: 10,
-                                       backgroundColor: function(context) {
-                                               if (!gradient) {
-                                                       gradient = context.chart.ctx.createLinearGradient(0, 0, 512, 256);
-                                                       gradient.addColorStop(0, '#ff0000');
-                                                       gradient.addColorStop(1, '#0000ff');
-                                               }
-                                               return gradient;
-                                       },
-                                       borderColor: '#cccccc'
-                               }
-                       },
-                       layout: {
-                               padding: 20
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'bubble',
+    data: {
+      datasets: datasets
+    },
+    options: {
+      responsive: false,
+      elements: {
+        point: {
+          rotation: angles,
+          radius: 10,
+          backgroundColor: function(context) {
+            if (!gradient) {
+              gradient = context.chart.ctx.createLinearGradient(0, 0, 512, 256);
+              gradient.addColorStop(0, '#ff0000');
+              gradient.addColorStop(1, '#0000ff');
+            }
+            return gradient;
+          },
+          borderColor: '#cccccc'
+        }
+      },
+      layout: {
+        padding: 20
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index a351b560f0ea78499c5e84f8837d2087c91aaa9b..f6bbfe8cb3e2e474a7599136e51299a634b0ea62 100644 (file)
@@ -1,39 +1,39 @@
 module.exports = {
-       config: {
-               data: {
-                       datasets: [
-                               {
-                                       type: 'line',
-                                       data: [6, 16, 3, 19],
-                                       borderColor: '#0000ff',
-                                       fill: false
-                               },
-                               {
-                                       type: 'bar',
-                                       data: [5, 20, 1, 10],
-                                       backgroundColor: '#00ff00',
-                                       borderColor: '#ff0000'
-                               }
-                       ]
-               },
-               options: {
-                       indexAxis: 'y',
-                       scales: {
-                               horz: {
-                                       position: 'top'
-                               },
-                               vert: {
-                                       axis: 'y',
-                                       labels: ['a', 'b', 'c', 'd']
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+  config: {
+    data: {
+      datasets: [
+        {
+          type: 'line',
+          data: [6, 16, 3, 19],
+          borderColor: '#0000ff',
+          fill: false
+        },
+        {
+          type: 'bar',
+          data: [5, 20, 1, 10],
+          backgroundColor: '#00ff00',
+          borderColor: '#ff0000'
+        }
+      ]
+    },
+    options: {
+      indexAxis: 'y',
+      scales: {
+        horz: {
+          position: 'top'
+        },
+        vert: {
+          axis: 'y',
+          labels: ['a', 'b', 'c', 'd']
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index c2cbc845ab3e8f80403d3a1d910d732f94cdff26..ff94edf538a33d4a1580373a94cb0c10d0abe351 100644 (file)
@@ -2,71 +2,71 @@ const data1 = [];
 const data2 = [];
 const data3 = [];
 for (let i = 0; i < 200; i++) {
-       const a = i / Math.PI / 10;
+  const a = i / Math.PI / 10;
 
-       data1.push({x: i, y: i < 86 || i > 104 && i < 178 ? Math.sin(a) : NaN});
+  data1.push({x: i, y: i < 86 || i > 104 && i < 178 ? Math.sin(a) : NaN});
 
-       if (i % 10 === 0) {
-               data2.push({x: i, y: Math.cos(a)});
-       }
+  if (i % 10 === 0) {
+    data2.push({x: i, y: Math.cos(a)});
+  }
 
-       if (i % 15 === 0) {
-               data3.push({x: i, y: Math.cos(a + Math.PI / 2)});
-       }
+  if (i % 15 === 0) {
+    data3.push({x: i, y: Math.cos(a + Math.PI / 2)});
+  }
 }
 
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               borderColor: 'rgba(255, 0, 0, 0.5)',
-                               backgroundColor: 'rgba(255, 0, 0, 0.25)',
-                               data: data1,
-                               fill: false,
-                       }, {
-                               borderColor: 'rgba(0, 0, 255, 0.5)',
-                               backgroundColor: 'rgba(0, 0, 255, 0.25)',
-                               data: data2,
-                               fill: 0,
-                       }, {
-                               borderColor: 'rgba(0, 255, 0, 0.5)',
-                               backgroundColor: 'rgba(0, 255, 0, 0.25)',
-                               data: data3,
-                               fill: 1,
-                       }]
-               },
-               options: {
-                       animation: false,
-                       responsive: false,
-                       datasets: {
-                               line: {
-                                       tension: 0.4,
-                                       borderWidth: 1,
-                                       pointRadius: 1.5,
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false
-                       },
-                       scales: {
-                               x: {
-                                       type: 'linear',
-                                       display: false
-                               },
-                               y: {
-                                       type: 'linear',
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               canvas: {
-                       height: 512,
-                       width: 512
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        borderColor: 'rgba(255, 0, 0, 0.5)',
+        backgroundColor: 'rgba(255, 0, 0, 0.25)',
+        data: data1,
+        fill: false,
+      }, {
+        borderColor: 'rgba(0, 0, 255, 0.5)',
+        backgroundColor: 'rgba(0, 0, 255, 0.25)',
+        data: data2,
+        fill: 0,
+      }, {
+        borderColor: 'rgba(0, 255, 0, 0.5)',
+        backgroundColor: 'rgba(0, 255, 0, 0.25)',
+        data: data3,
+        fill: 1,
+      }]
+    },
+    options: {
+      animation: false,
+      responsive: false,
+      datasets: {
+        line: {
+          tension: 0.4,
+          borderWidth: 1,
+          pointRadius: 1.5,
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false
+      },
+      scales: {
+        x: {
+          type: 'linear',
+          display: false
+        },
+        y: {
+          type: 'linear',
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    canvas: {
+      height: 512,
+      width: 512
+    }
+  }
 };
index 1e800486fcc25e3b16ee523bb777c3e31632054a..9747bb37594ea157e16626a8289bafcced2b07f4 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: ['English', 'Maths', 'Physics', 'Chemistry', 'Biology', 'History'],
-                       datasets: [
-                               {
-                                       order: 1,
-                                       borderColor: '#D50000',
-                                       backgroundColor: 'rgba(245, 205, 121,0.5)',
-                                       data: [65, 75, 70, 80, 60, 80]
-                               },
-                               {
-                                       order: 0,
-                                       backgroundColor: 'rgba(0, 168, 255,1)',
-                                       data: [54, 65, 60, 70, 70, 75]
-                               }
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false
-                       },
-                       scales: {
-                               r: {
-                                       display: false
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: ['English', 'Maths', 'Physics', 'Chemistry', 'Biology', 'History'],
+      datasets: [
+        {
+          order: 1,
+          borderColor: '#D50000',
+          backgroundColor: 'rgba(245, 205, 121,0.5)',
+          data: [65, 75, 70, 80, 60, 80]
+        },
+        {
+          order: 0,
+          backgroundColor: 'rgba(0, 168, 255,1)',
+          data: [54, 65, 60, 70, 70, 75]
+        }
+      ]
+    },
+    options: {
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false
+      },
+      scales: {
+        r: {
+          display: false
+        }
+      }
+    }
+  }
 };
index 487e86708ef974bafe24281250498353ffba897c..200b73ac58a2111dd5689b7017c9969f43716e5a 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'bottom',
-                                       align: 'center',
-                                       title: {
-                                               display: true,
-                                               position: 'center',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'bottom',
+          align: 'center',
+          title: {
+            display: true,
+            position: 'center',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 71c3e968039b61685998ba24da6bbb1e4bb7cd0c..f624512b755720c0e74ff0357a61c4751b142f3f 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'bottom',
-                                       align: 'end',
-                                       title: {
-                                               display: true,
-                                               position: 'end',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'bottom',
+          align: 'end',
+          title: {
+            display: true,
+            position: 'end',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 18f2d5a82d470a109be36dc46344a66388b0abcc..8f993e14041889ff1559420e9b5f7b3ddf08899a 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'bottom',
-                                       align: 'start',
-                                       title: {
-                                               display: true,
-                                               position: 'start',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'bottom',
+          align: 'start',
+          title: {
+            display: true,
+            position: 'start',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index f834ab67c74eb833377037e271c39796a5460021..b269670dee89a0880d1be854de2334bd49413a2a 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'left',
-                                       align: 'center',
-                                       title: {
-                                               display: true,
-                                               position: 'center',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'left',
+          align: 'center',
+          title: {
+            display: true,
+            position: 'center',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index ecb01b0dc21265299271f6c1bfdce337086236bc..c88b95d1cac3876efe4bc24e49bd9fcf271a814d 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'left',
-                                       align: 'end',
-                                       title: {
-                                               display: true,
-                                               position: 'end',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'left',
+          align: 'end',
+          title: {
+            display: true,
+            position: 'end',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index feb9bef66ddbae4e3c3fe5f22f284d9a4d2fc230..06decc309a398380933f4bf355c37c1515252616 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'left',
-                                       align: 'start',
-                                       title: {
-                                               display: true,
-                                               position: 'start',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'left',
+          align: 'start',
+          title: {
+            display: true,
+            position: 'start',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index bc35dccaccf4103731181ebd11b279bc26d60676..c9ba4aaf9e2992af6a0f1dc5054e05ed38c3c0c0 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'right',
-                                       align: 'center',
-                                       title: {
-                                               display: true,
-                                               position: 'center',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'right',
+          align: 'center',
+          title: {
+            display: true,
+            position: 'center',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 1dad12c10f2c79a400e3f724204f7423dbc5f1ea..4add990ea2a39f5bea1048fa4ec97c27d8de570f 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'right',
-                                       align: 'end',
-                                       title: {
-                                               display: true,
-                                               position: 'end',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'right',
+          align: 'end',
+          title: {
+            display: true,
+            position: 'end',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index fee2f38ef0a16e296b74d137a178aa66dd5fa331..43e9e00430fde01ef2e799a748c38751350e61ee 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'right',
-                                       align: 'start',
-                                       title: {
-                                               display: true,
-                                               position: 'start',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'right',
+          align: 'start',
+          title: {
+            display: true,
+            position: 'start',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 4ea2e46f027b6479c11b4adb165513d752f770f2..1f94799c10776c9a63131eadeac2188b191e9bb6 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'top',
-                                       align: 'center',
-                                       title: {
-                                               display: true,
-                                               position: 'center',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'top',
+          align: 'center',
+          title: {
+            display: true,
+            position: 'center',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index faa873985b78093fc282196904557a9a4c38bf8b..22210df59f90bb85a5ff20fba1163b1c8781aa02 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'top',
-                                       align: 'end',
-                                       title: {
-                                               display: true,
-                                               position: 'end',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'top',
+          align: 'end',
+          title: {
+            display: true,
+            position: 'end',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 9a893fbaf8bfbf0e4604394ba3cc3fa734059758..38430746acbf910ca94eb80611f2542a4246bf22 100644 (file)
@@ -1,36 +1,36 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [
-                               {label: 'a', data: []},
-                               {label: 'b', data: []},
-                               {label: 'c', data: []}
-                       ]
-               },
-               options: {
-                       plugins: {
-                               legend: {
-                                       position: 'top',
-                                       align: 'start',
-                                       title: {
-                                               display: true,
-                                               position: 'start',
-                                               text: 'title'
-                                       }
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {
-                       height: 256,
-                       width: 256
-               }
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [
+        {label: 'a', data: []},
+        {label: 'b', data: []},
+        {label: 'c', data: []}
+      ]
+    },
+    options: {
+      plugins: {
+        legend: {
+          position: 'top',
+          align: 'start',
+          title: {
+            display: true,
+            position: 'start',
+            text: 'title'
+          }
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {
+      height: 256,
+      width: 256
+    }
+  }
 };
index 3fef618f00667fc3ce54fd65d504be8ddab5ba0b..4726fb832c703c88b63c4194630a0028201eced1 100644 (file)
@@ -13,94 +13,94 @@ var pattern = patternContext.createPattern(patternCanvas, 'repeat');
 var gradient;
 
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8],
-                               pointBorderColor: '#ff0000',
-                               pointBackgroundColor: '#00ff00',
-                               showLine: false
-                       }, {
-                               label: '',
-                               data: [4, 4, 4, 4, 4, 5, 3, 4, 4, 4, 4],
-                               pointBorderColor: pattern,
-                               pointBackgroundColor: pattern,
-                               showLine: false
-                       }, {
-                               label: '',
-                               data: [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
-                               showLine: false
-                       }],
-                       labels: ['', '', '', '', '', '', '', '', '', '', '']
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       elements: {
-                               line: {
-                                       fill: false
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               filler: false
-                       },
-                       tooltips: {
-                               mode: 'nearest',
-                               intersect: false,
-                               callbacks: {
-                                       label: function() {
-                                               return '\u200b';
-                                       }
-                               }
-                       },
-                       layout: {
-                               padding: 15
-                       }
-               },
-               plugins: [{
-                       beforeDatasetsUpdate: function(chart) {
-                               if (!gradient) {
-                                       gradient = chart.ctx.createLinearGradient(0, 0, 512, 256);
-                                       gradient.addColorStop(0, '#ff0000');
-                                       gradient.addColorStop(1, '#0000ff');
-                               }
-                               chart.config.data.datasets[2].pointBorderColor = gradient;
-                               chart.config.data.datasets[2].pointBackgroundColor = gradient;
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8],
+        pointBorderColor: '#ff0000',
+        pointBackgroundColor: '#00ff00',
+        showLine: false
+      }, {
+        label: '',
+        data: [4, 4, 4, 4, 4, 5, 3, 4, 4, 4, 4],
+        pointBorderColor: pattern,
+        pointBackgroundColor: pattern,
+        showLine: false
+      }, {
+        label: '',
+        data: [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
+        showLine: false
+      }],
+      labels: ['', '', '', '', '', '', '', '', '', '', '']
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      elements: {
+        line: {
+          fill: false
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        filler: false
+      },
+      tooltips: {
+        mode: 'nearest',
+        intersect: false,
+        callbacks: {
+          label: function() {
+            return '\u200b';
+          }
+        }
+      },
+      layout: {
+        padding: 15
+      }
+    },
+    plugins: [{
+      beforeDatasetsUpdate: function(chart) {
+        if (!gradient) {
+          gradient = chart.ctx.createLinearGradient(0, 0, 512, 256);
+          gradient.addColorStop(0, '#ff0000');
+          gradient.addColorStop(1, '#0000ff');
+        }
+        chart.config.data.datasets[2].pointBorderColor = gradient;
+        chart.config.data.datasets[2].pointBackgroundColor = gradient;
 
-                               return true;
-                       },
-                       afterDraw: function(chart) {
-                               var canvas = chart.canvas;
-                               var rect = canvas.getBoundingClientRect();
-                               var point, event;
+        return true;
+      },
+      afterDraw: function(chart) {
+        var canvas = chart.canvas;
+        var rect = canvas.getBoundingClientRect();
+        var point, event;
 
-                               for (var i = 0; i < 3; ++i) {
-                                       for (var j = 0; j < 11; ++j) {
-                                               point = chart.getDatasetMeta(i).data[j];
-                                               event = {
-                                                       type: 'mousemove',
-                                                       target: canvas,
-                                                       clientX: rect.left + point.x,
-                                                       clientY: rect.top + point.y
-                                               };
-                                               chart._handleEvent(event);
-                                               chart.tooltip.handleEvent(event);
-                                               chart.tooltip.opacity = j / 10;
-                                               chart.tooltip.draw(chart.ctx);
-                                       }
-                               }
-                       }
-               }]
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+        for (var i = 0; i < 3; ++i) {
+          for (var j = 0; j < 11; ++j) {
+            point = chart.getDatasetMeta(i).data[j];
+            event = {
+              type: 'mousemove',
+              target: canvas,
+              clientX: rect.left + point.x,
+              clientY: rect.top + point.y
+            };
+            chart._handleEvent(event);
+            chart.tooltip.handleEvent(event);
+            chart.tooltip.opacity = j / 10;
+            chart.tooltip.draw(chart.ctx);
+          }
+        }
+      }
+    }]
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index de60be92ff566d33fabdd80ceae55d2f71650459..f14dc83b5f07dbfd3d074950a79066d1034e0981 100644 (file)
@@ -1,76 +1,76 @@
 const pointStyles = ['circle', 'cross', 'crossRot', 'dash', 'line', 'rect', 'rectRounded', 'rectRot', 'star', 'triangle'];
 
 function newDataset(pointStyle, i) {
-       return {
-               label: '',
-               data: pointStyles.map(() => i),
-               pointStyle: pointStyle,
-               pointBackgroundColor: '#0000ff',
-               pointBorderColor: '#00ff00',
-               showLine: false
-       };
+  return {
+    label: '',
+    data: pointStyles.map(() => i),
+    pointStyle: pointStyle,
+    pointBackgroundColor: '#0000ff',
+    pointBorderColor: '#00ff00',
+    showLine: false
+  };
 }
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: pointStyles.map((pointStyle, i) => newDataset(pointStyle, i)),
-                       labels: pointStyles.map(() => '')
-               },
-               options: {
-                       scales: {
-                               x: {display: false},
-                               y: {display: false}
-                       },
-                       elements: {
-                               line: {
-                                       fill: false
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               filler: false
-                       },
-                       tooltips: {
-                               mode: 'nearest',
-                               intersect: false,
-                               usePointStyle: true,
-                               callbacks: {
-                                       label: function() {
-                                               return '\u200b';
-                                       }
-                               }
-                       },
-                       layout: {
-                               padding: 15
-                       }
-               },
-               plugins: [{
-                       afterDraw: function(chart) {
-                               var canvas = chart.canvas;
-                               var rect = canvas.getBoundingClientRect();
-                               var point, event;
+  config: {
+    type: 'line',
+    data: {
+      datasets: pointStyles.map((pointStyle, i) => newDataset(pointStyle, i)),
+      labels: pointStyles.map(() => '')
+    },
+    options: {
+      scales: {
+        x: {display: false},
+        y: {display: false}
+      },
+      elements: {
+        line: {
+          fill: false
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        filler: false
+      },
+      tooltips: {
+        mode: 'nearest',
+        intersect: false,
+        usePointStyle: true,
+        callbacks: {
+          label: function() {
+            return '\u200b';
+          }
+        }
+      },
+      layout: {
+        padding: 15
+      }
+    },
+    plugins: [{
+      afterDraw: function(chart) {
+        var canvas = chart.canvas;
+        var rect = canvas.getBoundingClientRect();
+        var point, event;
 
-                               for (var i = 0; i < pointStyles.length; ++i) {
-                                       point = chart.getDatasetMeta(i).data[i];
-                                       event = {
-                                               type: 'mousemove',
-                                               target: canvas,
-                                               clientX: rect.left + point.x,
-                                               clientY: rect.top + point.y
-                                       };
-                                       chart._handleEvent(event);
-                                       chart.tooltip.handleEvent(event);
-                                       chart.tooltip.draw(chart.ctx);
-                               }
-                       }
-               }]
-       },
-       options: {
-               canvas: {
-                       height: 256,
-                       width: 512
-               }
-       }
+        for (var i = 0; i < pointStyles.length; ++i) {
+          point = chart.getDatasetMeta(i).data[i];
+          event = {
+            type: 'mousemove',
+            target: canvas,
+            clientX: rect.left + point.x,
+            clientY: rect.top + point.y
+          };
+          chart._handleEvent(event);
+          chart.tooltip.handleEvent(event);
+          chart.tooltip.draw(chart.ctx);
+        }
+      }
+    }]
+  },
+  options: {
+    canvas: {
+      height: 256,
+      width: 512
+    }
+  }
 };
index 61da56d3b34089a658cae50de27ca131a468711c..d002927420d1255e34c146c001c4579e7cf2a9b9 100644 (file)
@@ -1,29 +1,29 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               data: [10, 5, 0, 25, 78]
-                       }],
-                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
-               },
-               options: {
-                       indexAxis: 'y',
-                       elements: {
-                               bar: {
-                                       backgroundColor: '#AAAAAA80',
-                                       borderColor: '#80808080',
-                                       borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
-                               }
-                       },
-                       scales: {
-                               x: {display: false},
-                               y: {display: true}
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        data: [10, 5, 0, 25, 78]
+      }],
+      labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
+    },
+    options: {
+      indexAxis: 'y',
+      elements: {
+        bar: {
+          backgroundColor: '#AAAAAA80',
+          borderColor: '#80808080',
+          borderWidth: {bottom: 6, left: 15, top: 6, right: 15}
+        }
+      },
+      scales: {
+        x: {display: false},
+        y: {display: true}
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 63c720e68ada8a0b1a1bea963205a6d3657c2c2d..65ddbbfdfd65f6f94848673ea19b5e150524f6f1 100644 (file)
@@ -1,18 +1,18 @@
 // Should generate max and min that are not equal when data contains values that are very close to each other
 
 module.exports = {
-       config: {
-               type: 'scatter',
-               data: {
-                       datasets: [{
-                               data: [
-                                       {x: 1, y: 1.8548483304974972},
-                                       {x: 2, y: 1.8548483304974974},
-                               ]
-                       }],
-               },
-       },
-       options: {
-               spriteText: true
-       }
+  config: {
+    type: 'scatter',
+    data: {
+      datasets: [{
+        data: [
+          {x: 1, y: 1.8548483304974972},
+          {x: 2, y: 1.8548483304974974},
+        ]
+      }],
+    },
+  },
+  options: {
+    spriteText: true
+  }
 };
index 2d0b6cb52d6b78b6868fa915cd2748e63ce3b085..df62588bdf7cad799552735bf0c45cca94afc521 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E']
-               },
-               options: {
-                       responsive: false,
-                       scales: {
-                               r: {
-                                       gridLines: {
-                                               display: true,
-                                       },
-                                       angleLines: {
-                                               color: ['red', 'green'],
-                                               lineWidth: [1, 5]
-                                       },
-                                       pointLabels: {
-                                               display: false
-                                       },
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E']
+    },
+    options: {
+      responsive: false,
+      scales: {
+        r: {
+          gridLines: {
+            display: true,
+          },
+          angleLines: {
+            color: ['red', 'green'],
+            lineWidth: [1, 5]
+          },
+          pointLabels: {
+            display: false
+          },
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  }
 };
index 96f117103bc45af9e8f1a36304971664526aff93..a3d97d1038bbba239261efe76ea34b030c2c24dc 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E']
-               },
-               options: {
-                       responsive: false,
-                       scales: {
-                               r: {
-                                       gridLines: {
-                                               display: true,
-                                       },
-                                       angleLines: {
-                                               color: function(context) {
-                                                       return context.index % 2 === 0 ? 'red' : 'green';
-                                               },
-                                               lineWidth: function(context) {
-                                                       return context.index % 2 === 0 ? 1 : 5;
-                                               },
-                                       },
-                                       pointLabels: {
-                                               display: false
-                                       },
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E']
+    },
+    options: {
+      responsive: false,
+      scales: {
+        r: {
+          gridLines: {
+            display: true,
+          },
+          angleLines: {
+            color: function(context) {
+              return context.index % 2 === 0 ? 'red' : 'green';
+            },
+            lineWidth: function(context) {
+              return context.index % 2 === 0 ? 1 : 5;
+            },
+          },
+          pointLabels: {
+            display: false
+          },
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  }
 };
index 280875c1e6ab59da6556eee9ecb20db5c79e82dd..fb1dcd527e4bb8a36ab23fb6c5625aa861764d04 100644 (file)
@@ -1,34 +1,34 @@
 module.exports = {
-       config: {
-               type: 'radar',
-               data: {
-                       labels: ['A', 'B', 'C', 'D', 'E']
-               },
-               options: {
-                       responsive: false,
-                       scales: {
-                               r: {
-                                       gridLines: {
-                                               display: true,
-                                               color: function(context) {
-                                                       return context.index % 2 === 0 ? 'red' : 'green';
-                                               },
-                                               lineWidth: function(context) {
-                                                       return context.index % 2 === 0 ? 1 : 5;
-                                               },
-                                       },
-                                       angleLines: {
-                                               color: 'rgba(255, 255, 255, 0.5)',
-                                               lineWidth: 2
-                                       },
-                                       pointLabels: {
-                                               display: false
-                                       },
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       }
-               }
-       }
+  config: {
+    type: 'radar',
+    data: {
+      labels: ['A', 'B', 'C', 'D', 'E']
+    },
+    options: {
+      responsive: false,
+      scales: {
+        r: {
+          gridLines: {
+            display: true,
+            color: function(context) {
+              return context.index % 2 === 0 ? 'red' : 'green';
+            },
+            lineWidth: function(context) {
+              return context.index % 2 === 0 ? 1 : 5;
+            },
+          },
+          angleLines: {
+            color: 'rgba(255, 255, 255, 0.5)',
+            lineWidth: 2
+          },
+          pointLabels: {
+            display: false
+          },
+          ticks: {
+            display: false
+          }
+        }
+      }
+    }
+  }
 };
index f09f27a436e2f07b7bf2f631c81d804f15f41db8..e207d697c383a915614d08e7bf5e04f127ea8a96 100644 (file)
@@ -1,41 +1,41 @@
 var date = moment('Jan 01 1990', 'MMM DD YYYY');
 var data = [];
 for (var i = 0; i < 60; i++) {
-       data.push({x: date.valueOf(), y: i});
-       date = date.clone().add(1, 'month');
+  data.push({x: date.valueOf(), y: i});
+  date = date.clone().add(1, 'month');
 }
 
 module.exports = {
-       threshold: 0.05,
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               xAxisID: 'x',
-                               data: data,
-                               fill: false
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       ticks: {
-                                               major: {
-                                                       enabled: true
-                                               },
-                                               source: 'data',
-                                               autoSkip: true,
-                                               maxRotation: 0
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.05,
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        xAxisID: 'x',
+        data: data,
+        fill: false
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          ticks: {
+            major: {
+              enabled: true
+            },
+            source: 'data',
+            autoSkip: true,
+            maxRotation: 0
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 1b1654cae5b43cfd320a0ef328456f04f8e53878..5d13b07ded3cc2d78da269f84ba03704c4589140 100644 (file)
@@ -1,56 +1,56 @@
 var date = moment('May 24 2020', 'MMM DD YYYY');
 
 module.exports = {
-       threshold: 0.05,
-       config: {
-               type: 'bar',
-               data: {
-                       datasets: [{
-                               backgroundColor: 'rgba(255, 0, 0, 0.5)',
-                               data: [
-                                       {
-                                               x: date.clone().add(-2, 'day'),
-                                               y: 20,
-                                       },
-                                       {
-                                               x: date.clone().add(-1, 'day'),
-                                               y: 30,
-                                       },
-                                       {
-                                               x: date,
-                                               y: 40,
-                                       },
-                                       {
-                                               x: date.clone().add(1, 'day'),
-                                               y: 50,
-                                       },
-                                       {
-                                               x: date.clone().add(7, 'day'),
-                                               y: 10,
-                                       }
-                               ]
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       display: false,
-                                       type: 'time',
-                                       distribution: 'linear',
-                                       ticks: {
-                                               source: 'auto'
-                                       },
-                                       time: {
-                                               unit: 'day'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.05,
+  config: {
+    type: 'bar',
+    data: {
+      datasets: [{
+        backgroundColor: 'rgba(255, 0, 0, 0.5)',
+        data: [
+          {
+            x: date.clone().add(-2, 'day'),
+            y: 20,
+          },
+          {
+            x: date.clone().add(-1, 'day'),
+            y: 30,
+          },
+          {
+            x: date,
+            y: 40,
+          },
+          {
+            x: date.clone().add(1, 'day'),
+            y: 50,
+          },
+          {
+            x: date.clone().add(7, 'day'),
+            y: 10,
+          }
+        ]
+      }]
+    },
+    options: {
+      scales: {
+        x: {
+          display: false,
+          type: 'time',
+          distribution: 'linear',
+          ticks: {
+            source: 'auto'
+          },
+          time: {
+            unit: 'day'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index c34193dbd361fc646b97be9ed6f9d277ead0ddb9..e3496e04f62e03eb276e4beb13911640c8a499af 100644 (file)
@@ -1,40 +1,40 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['foo', 'bar'],
-                       datasets: [{
-                               data: [0, 1],
-                               fill: false
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       position: 'bottom',
-                                       time: {
-                                               unit: 'day',
-                                               round: true,
-                                               parser: function(label) {
-                                                       return label === 'foo' ?
-                                                               moment('2000/01/02', 'YYYY/MM/DD') :
-                                                               moment('2016/05/08', 'YYYY/MM/DD');
-                                               }
-                                       },
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 256, height: 128}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['foo', 'bar'],
+      datasets: [{
+        data: [0, 1],
+        fill: false
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          position: 'bottom',
+          time: {
+            unit: 'day',
+            round: true,
+            parser: function(label) {
+              return label === 'foo' ?
+                moment('2000/01/02', 'YYYY/MM/DD') :
+                moment('2016/05/08', 'YYYY/MM/DD');
+            }
+          },
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 256, height: 128}
+  }
 };
index 507a4fc80e7a554758e0e736956a1dda036c47ac..5565c3e0d338ac58003a569f54689f3f03a0338b 100644 (file)
@@ -1,58 +1,58 @@
 function newDateFromRef(days) {
-       return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
+  return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
 }
 
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [{
-                                       t: newDateFromRef(0),
-                                       y: 1
-                               }, {
-                                       t: newDateFromRef(1),
-                                       y: 10
-                               }, {
-                                       t: newDateFromRef(2),
-                                       y: 0
-                               }, {
-                                       t: newDateFromRef(4),
-                                       y: 5
-                               }, {
-                                       t: newDateFromRef(6),
-                                       y: 77
-                               }, {
-                                       t: newDateFromRef(7),
-                                       y: 9
-                               }, {
-                                       t: newDateFromRef(9),
-                                       y: 5
-                               }],
-                               fill: false,
-                               parsing: {
-                                       xAxisKey: 't'
-                               }
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       position: 'bottom',
-                                       ticks: {
-                                               maxRotation: 0
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 800, height: 200}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [{
+          t: newDateFromRef(0),
+          y: 1
+        }, {
+          t: newDateFromRef(1),
+          y: 10
+        }, {
+          t: newDateFromRef(2),
+          y: 0
+        }, {
+          t: newDateFromRef(4),
+          y: 5
+        }, {
+          t: newDateFromRef(6),
+          y: 77
+        }, {
+          t: newDateFromRef(7),
+          y: 9
+        }, {
+          t: newDateFromRef(9),
+          y: 5
+        }],
+        fill: false,
+        parsing: {
+          xAxisKey: 't'
+        }
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          position: 'bottom',
+          ticks: {
+            maxRotation: 0
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 800, height: 200}
+  }
 };
index 7230312b5ae0e9b7c41d7552fbb7ee91127c2442..4e582a2977cc3e95ba7782b68c3b92deabe7b64f 100644 (file)
@@ -1,55 +1,55 @@
 function newDateFromRef(days) {
-       return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
+  return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
 }
 
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               data: [{
-                                       x: newDateFromRef(0),
-                                       y: 1
-                               }, {
-                                       x: newDateFromRef(1),
-                                       y: 10
-                               }, {
-                                       x: newDateFromRef(2),
-                                       y: 0
-                               }, {
-                                       x: newDateFromRef(4),
-                                       y: 5
-                               }, {
-                                       x: newDateFromRef(6),
-                                       y: 77
-                               }, {
-                                       x: newDateFromRef(7),
-                                       y: 9
-                               }, {
-                                       x: newDateFromRef(9),
-                                       y: 5
-                               }],
-                               fill: false
-                       }],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       position: 'bottom',
-                                       ticks: {
-                                               maxRotation: 0
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 800, height: 200}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        data: [{
+          x: newDateFromRef(0),
+          y: 1
+        }, {
+          x: newDateFromRef(1),
+          y: 10
+        }, {
+          x: newDateFromRef(2),
+          y: 0
+        }, {
+          x: newDateFromRef(4),
+          y: 5
+        }, {
+          x: newDateFromRef(6),
+          y: 77
+        }, {
+          x: newDateFromRef(7),
+          y: 9
+        }, {
+          x: newDateFromRef(9),
+          y: 5
+        }],
+        fill: false
+      }],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          position: 'bottom',
+          ticks: {
+            maxRotation: 0
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 800, height: 200}
+  }
 };
index 9bd82329725df7ddddfc92d887538750a913a698..2a79b6fa26b37709816a313809b0f7082c888c8d 100644 (file)
@@ -1,28 +1,28 @@
 function newDateFromRef(days) {
-       return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
+  return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
 }
 
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: [newDateFromRef(0), newDateFromRef(1), newDateFromRef(2), newDateFromRef(4), newDateFromRef(6), newDateFromRef(7), newDateFromRef(9)],
-                       fill: false
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 1000, height: 200}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: [newDateFromRef(0), newDateFromRef(1), newDateFromRef(2), newDateFromRef(4), newDateFromRef(6), newDateFromRef(7), newDateFromRef(9)],
+      fill: false
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 1000, height: 200}
+  }
 };
index 28b92b239b368897739a382cc6aa3c1346b01760..c9e83075c4d9da34bbfda8625bad1025b1c650e6 100644 (file)
@@ -1,23 +1,23 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2015-01-01T12:00:00', '2015-01-02T21:00:00', '2015-01-03T22:00:00', '2015-01-05T23:00:00', '2015-01-07T03:00', '2015-01-08T10:00', '2015-01-10T12:00']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 1000, height: 200}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2015-01-01T12:00:00', '2015-01-02T21:00:00', '2015-01-03T22:00:00', '2015-01-05T23:00:00', '2015-01-07T03:00', '2015-01-08T10:00', '2015-01-10T12:00']
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 1000, height: 200}
+  }
 };
index 071b6ec008e4f71ef02a9d56b2fddd66caa5b6cb..6f63c191d1aed42a31e998163ff9c09ea106aba8 100644 (file)
@@ -1,46 +1,46 @@
 var timeOpts = {
-       parser: 'YYYY',
-       unit: 'year',
-       displayFormats: {
-               year: 'YYYY'
-       }
+  parser: 'YYYY',
+  unit: 'year',
+  displayFormats: {
+    year: 'YYYY'
+  }
 };
 
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['1975', '1976', '1977'],
-                       xLabels: ['1985', '1986', '1987'],
-                       yLabels: ['1995', '1996', '1997']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       labels: ['2015', '2016', '2017'],
-                                       time: timeOpts
-                               },
-                               x2: {
-                                       type: 'time',
-                                       position: 'bottom',
-                                       time: timeOpts
-                               },
-                               y: {
-                                       type: 'time',
-                                       time: timeOpts
-                               },
-                               y2: {
-                                       position: 'left',
-                                       type: 'time',
-                                       labels: ['2005', '2006', '2007'],
-                                       time: timeOpts
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['1975', '1976', '1977'],
+      xLabels: ['1985', '1986', '1987'],
+      yLabels: ['1995', '1996', '1997']
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          labels: ['2015', '2016', '2017'],
+          time: timeOpts
+        },
+        x2: {
+          type: 'time',
+          position: 'bottom',
+          time: timeOpts
+        },
+        y: {
+          type: 'time',
+          time: timeOpts
+        },
+        y2: {
+          position: 'left',
+          type: 'time',
+          labels: ['2005', '2006', '2007'],
+          time: timeOpts
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index f48ecf1d6e9bcd9c0626ecdd4ead4cbef1389f4f..9b3e80d13fd9e9556d2b649ff63c1417c5437868 100644 (file)
@@ -1,41 +1,41 @@
 module.exports = {
-       config: {
-               type: 'line',
-               data: {
-                       datasets: [{
-                               fill: true,
-                               backgroundColor: 'red',
-                               data: [
-                                       {x: -1000000, y: 1},
-                                       {x: 1000000000, y: 2}
-                               ]
-                       }]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               unit: 'day'
-                                       },
-                                       ticks: {
-                                               display: false
-                                       }
-                               },
-                               y: {
-                                       ticks: {
-                                               display: false
-                                       }
-                               }
-                       },
-                       plugins: {
-                               legend: false,
-                               title: false,
-                               tooltip: false
-                       }
-               }
-       },
-       options: {
-               canvas: {width: 1000, height: 200}
-       }
+  config: {
+    type: 'line',
+    data: {
+      datasets: [{
+        fill: true,
+        backgroundColor: 'red',
+        data: [
+          {x: -1000000, y: 1},
+          {x: 1000000000, y: 2}
+        ]
+      }]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            unit: 'day'
+          },
+          ticks: {
+            display: false
+          }
+        },
+        y: {
+          ticks: {
+            display: false
+          }
+        }
+      },
+      plugins: {
+        legend: false,
+        title: false,
+        tooltip: false
+      }
+    }
+  },
+  options: {
+    canvas: {width: 1000, height: 200}
+  }
 };
index cc6e961eded5d1e07a7519eb093b7c806179296d..16fb09fbe0f7b82e6527546306b2352a0dc38d4d 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'auto'
-                                       },
-                                       distribution: 'linear'
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'auto'
+          },
+          distribution: 'linear'
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 3133979ab483ff06796f71d20df64e099ff384fb..3e4a671a46415f9e4fe16409de1d44ebcd0b894a 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'data'
-                                       },
-                                       distribution: 'linear'
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'data'
+          },
+          distribution: 'linear'
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 3420dca5c6b50a625cee4ac9381d41b731e040af..6bd09ce783bf995e8287330296dd1cfb38b85d44 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       min: '2012',
-                                       max: '2051',
-                                       offset: true,
-                                       time: {
-                                               parser: 'YYYY',
-                                       },
-                                       ticks: {
-                                               source: 'labels'
-                                       },
-                                       distribution: 'linear'
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          min: '2012',
+          max: '2051',
+          offset: true,
+          time: {
+            parser: 'YYYY',
+          },
+          ticks: {
+            source: 'labels'
+          },
+          distribution: 'linear'
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 2eb1f145ef503f68f1f8c14461099d2c2d41d9ab..7a0a8303ae242b9bc1ab92d560bdfc2d1daf1757 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'labels'
-                                       },
-                                       distribution: 'linear'
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'labels'
+          },
+          distribution: 'linear'
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 67961f39b6063159cef34e6ae5531264e3229cb9..8cc6200dcfa4ae2ef91b1b4ce4af6f8ae550549b 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: [
-                               '2012-01-01', '2013-01-01', '2014-01-01', '2015-01-01',
-                               '2016-01-01', '2017-01-01', '2018-01-01', '2019-01-01'
-                       ]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               unit: 'year'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: [
+        '2012-01-01', '2013-01-01', '2014-01-01', '2015-01-01',
+        '2016-01-01', '2017-01-01', '2018-01-01', '2019-01-01'
+      ]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            unit: 'year'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index b3892361d87ff36d79d78d33ac72de64c2451776..05b9595f5a1e5704c4fa7b8d1de994fd7c5b6433 100644 (file)
@@ -1,27 +1,27 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       bounds: 'ticks',
-                                       time: {
-                                               minUnit: 'day'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 256, height: 128}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          bounds: 'ticks',
+          time: {
+            minUnit: 'day'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 256, height: 128}
+  }
 };
index 9d716e57c1bb27f2939704f4f21c708a5d089ecc..99f2d1c1cd55cff63c324657fee85f2f87bd39ca 100644 (file)
@@ -1,33 +1,33 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       min: '2012',
-                                       max: '2050',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       distribution: 'linear',
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          min: '2012',
+          max: '2050',
+          time: {
+            parser: 'YYYY'
+          },
+          distribution: 'linear',
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 54651cb2281f5782af49fd57c3be8aba36675ea9..cf2a804eaff7ebee101f761b905179d5983b122e 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       distribution: 'linear',
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4, 5], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            parser: 'YYYY'
+          },
+          distribution: 'linear',
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index c8e5d49aabf9542f970193379ace423e242021b2..7975115c5a4cb6c9fdc2cd144bf0a84ec231ad30 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2021'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       reverse: true,
-                                       offset: true,
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'labels',
-                                       },
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2021'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          reverse: true,
+          offset: true,
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'labels',
+          },
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 0a28ab06a7e08b39c47a0c2d305ccdab714031f6..fd8daab718de42190933d7e0ad4e643497f1876c 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2021'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       reverse: true,
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'labels',
-                                       },
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2021'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          reverse: true,
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'labels',
+          },
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 86ed3d763449a278b4bf213f578230c2e1b748f3..92a09bd7ce1ce4d4840c81274614a298bb911c0c 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       threshold: 0.05,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2015-01-01T20:00:00', '2015-02-02T21:00:00', '2015-02-21T01:00:00']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       bounds: 'ticks',
-                                       time: {
-                                               unit: 'week',
-                                               round: 'week'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 512, height: 256}
-       }
+  threshold: 0.05,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2015-01-01T20:00:00', '2015-02-02T21:00:00', '2015-02-21T01:00:00']
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          bounds: 'ticks',
+          time: {
+            unit: 'week',
+            round: 'week'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 512, height: 256}
+  }
 };
index 2cf92675d648fc20eba2b27965ad50822bf5b2da..dd5f2e3a3793ecc964f031d1f0e81fea6b3f55ac 100644 (file)
@@ -1,28 +1,28 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2015-01-01T20:00:00', '2015-01-01T21:00:00']
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       bounds: 'ticks',
-                                       time: {
-                                               unit: 'hour',
-                                               stepSize: 2
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 512, height: 128}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2015-01-01T20:00:00', '2015-01-01T21:00:00']
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          bounds: 'ticks',
+          time: {
+            unit: 'hour',
+            stepSize: 2
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 512, height: 128}
+  }
 };
index 3cd7a8c322862dfc1cf5ebb88aa8830579a1c096..b725c5ff1bfaf5333d985ba36c091d4a40521efd 100644 (file)
@@ -1,26 +1,26 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'],
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'time',
-                                       time: {
-                                               unit: 'hour',
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true,
-               canvas: {width: 1200, height: 200}
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00'],
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'time',
+          time: {
+            unit: 'hour',
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true,
+    canvas: {width: 1200, height: 200}
+  }
 };
index 49ef34654b8d62d0e6760a8317222c7a8a7810c3..66adfcfd8345708941a91192eaabb30e65e0fbd8 100644 (file)
@@ -1,58 +1,58 @@
 const data = [{x: 631180800000, y: 31.80}, {x: 631267200000, y: 30.20}, {x: 631353600000, y: 29.84}, {x: 631440000000, y: 29.72}, {x: 631526400000, y: 28.91}, {x: 631785600000, y: 29.55}, {x: 631872000000, y: 30.39}, {x: 631958400000, y: 29.54}, {x: 632044800000, y: 28.86}, {x: 632131200000, y: 30.75}, {x: 632390400000, y: 31.86}, {x: 632476800000, y: 33.59}, {x: 632563200000, y: 31.22}, {x: 632649600000, y: 30.12}, {x: 632736000000, y: 30.68}, {x: 632995200000, y: 31.46}, {x: 633081600000, y: 30.77}, {x: 633168000000, y: 30.27}, {x: 633254400000, y: 29.64}, {x: 633340800000, y: 30.53}, {x: 633600000000, y: 30.79}, {x: 633686400000, y: 30.27}, {x: 633772800000, y: 30.18}, {x: 633859200000, y: 27.72}, {x: 633945600000, y: 27.83}, {x: 634204800000, y: 27.82}, {x: 634291200000, y: 29.10}, {x: 634377600000, y: 28.34}, {x: 634464000000, y: 29.52}, {x: 634550400000, y: 28.69}, {x: 634809600000, y: 28.23}, {x: 634896000000, y: 27.45}, {x: 634982400000, y: 27.40}, {x: 635068800000, y: 28.39}, {x: 635155200000, y: 30.03}, {x: 635414400000, y: 31.19}, {x: 635500800000, y: 32.30}, {x: 635587200000, y: 33.84}, {x: 635673600000, y: 32.34}, {x: 635760000000, y: 31.96}, {x: 636019200000, y: 31.95}, {x: 636105600000, y: 32.84}, {x: 636192000000, y: 30.80}, {x: 636278400000, y: 31.54}, {x: 636364800000, y: 30.81}, {x: 636624000000, y: 32.99}, {x: 636710400000, y: 32.25}, {x: 636796800000, y: 33.87}, {x: 636883200000, y: 35.75}, {x: 636969600000, y: 35.71}, {x: 637228800000, y: 36.60}, {x: 637315200000, y: 35.65}, {x: 637401600000, y: 34.36}, {x: 637488000000, y: 33.61}, {x: 637574400000, y: 34.24}, {x: 637833600000, y: 32.79}, {x: 637920000000, y: 34.41}, {x: 638006400000, y: 34.11}, {x: 638092800000, y: 33.91}, {x: 638179200000, y: 33.33}, {x: 638438400000, y: 32.99}, {x: 638524800000, y: 34.17}, {x: 638611200000, y: 33.50}, {x: 638697600000, y: 35.64}, {x: 638784000000, y: 35.50}, {x: 639039600000, y: 33.11}, {x: 639126000000, y: 34.08}, {x: 639212400000, y: 35.69}, {x: 639298800000, y: 38.24}, {x: 639385200000, y: 40.86}, {x: 639644400000, y: 41.99}, {x: 639730800000, y: 44.45}, {x: 639817200000, y: 45.06}, {x: 639903600000, y: 44.32}, {x: 639990000000, y: 43.70}, {x: 640249200000, y: 44.97}, {x: 640335600000, y: 44.92}, {x: 640422000000, y: 44.11}, {x: 640508400000, y: 44.42}, {x: 640594800000, y: 43.90}, {x: 640854000000, y: 41.91}, {x: 640940400000, y: 41.60}, {x: 641026800000, y: 41.84}, {x: 641113200000, y: 42.55}, {x: 641199600000, y: 40.56}, {x: 641458800000, y: 39.99}, {x: 641545200000, y: 43.51}, {x: 641631600000, y: 43.17}, {x: 641718000000, y: 40.52}, {x: 641804400000, y: 41.06}, {x: 642063600000, y: 40.15}, {x: 642150000000, y: 43.82}, {x: 642236400000, y: 43.19}, {x: 642322800000, y: 40.99}, {x: 642409200000, y: 41.16}, {x: 642668400000, y: 41.02}, {x: 642754800000, y: 40.03}, {x: 642841200000, y: 36.46}, {x: 642927600000, y: 39.11}, {x: 643014000000, y: 41.10}, {x: 643273200000, y: 41.15}, {x: 643359600000, y: 39.01}, {x: 643446000000, y: 39.48}, {x: 643532400000, y: 41.89}, {x: 643618800000, y: 40.74}, {x: 643878000000, y: 38.88}, {x: 643964400000, y: 38.11}, {x: 644050800000, y: 40.39}, {x: 644137200000, y: 38.28}, {x: 644223600000, y: 39.96}, {x: 644482800000, y: 39.37}, {x: 644569200000, y: 39.39}, {x: 644655600000, y: 39.62}, {x: 644742000000, y: 38.99}, {x: 644828400000, y: 40.25}, {x: 645087600000, y: 42.85}, {x: 645174000000, y: 45.91}, {x: 645260400000, y: 46.66}, {x: 645346800000, y: 48.08}, {x: 645433200000, y: 51.00}, {x: 645692400000, y: 50.61}, {x: 645778800000, y: 54.55}, {x: 645865200000, y: 53.59}, {x: 645951600000, y: 53.39}, {x: 646038000000, y: 54.61}, {x: 646297200000, y: 55.02}, {x: 646383600000, y: 57.35}, {x: 646470000000, y: 56.95}, {x: 646556400000, y: 60.08}, {x: 646642800000, y: 59.80}, {x: 646902000000, y: 61.29}, {x: 646988400000, y: 63.45}, {x: 647074800000, y: 62.07}, {x: 647161200000, y: 59.01}, {x: 647247600000, y: 59.76}, {x: 647506800000, y: 60.08}, {x: 647593200000, y: 60.96}, {x: 647679600000, y: 60.56}, {x: 647766000000, y: 58.60}, {x: 647852400000, y: 57.40}, {x: 648111600000, y: 59.86}, {x: 648198000000, y: 58.76}, {x: 648284400000, y: 57.54}, {x: 648370800000, y: 57.78}, {x: 648457200000, y: 54.33}, {x: 648716400000, y: 54.57}, {x: 648802800000, y: 53.69}, {x: 648889200000, y: 57.02}, {x: 648975600000, y: 52.30}, {x: 649062000000, y: 49.79}, {x: 649321200000, y: 47.40}, {x: 649407600000, y: 45.44}, {x: 649494000000, y: 46.75}, {x: 649580400000, y: 44.19}, {x: 649666800000, y: 43.05}, {x: 649926000000, y: 43.99}, {x: 650012400000, y: 45.99}, {x: 650098800000, y: 42.15}, {x: 650185200000, y: 41.84}, {x: 650271600000, y: 43.30}, {x: 650530800000, y: 41.57}, {x: 650617200000, y: 42.13}, {x: 650703600000, y: 43.29}, {x: 650790000000, y: 43.98}, {x: 650876400000, y: 44.51}, {x: 651135600000, y: 45.50}, {x: 651222000000, y: 43.63}, {x: 651308400000, y: 41.93}, {x: 651394800000, y: 38.41}, {x: 651481200000, y: 41.01}, {x: 651740400000, y: 38.17}, {x: 651826800000, y: 38.32}, {x: 651913200000, y: 38.27}, {x: 651999600000, y: 36.10}, {x: 652086000000, y: 34.62}, {x: 652345200000, y: 33.91}, {x: 652431600000, y: 34.25}, {x: 652518000000, y: 33.97}, {x: 652604400000, y: 35.11}, {x: 652690800000, y: 35.05}, {x: 652950000000, y: 36.37}, {x: 653036400000, y: 35.54}, {x: 653122800000, y: 35.80}, {x: 653209200000, y: 36.75}, {x: 653295600000, y: 35.48}, {x: 653554800000, y: 36.78}, {x: 653641200000, y: 34.35}, {x: 653727600000, y: 32.62}, {x: 653814000000, y: 32.66}, {x: 653900400000, y: 31.45}, {x: 654159600000, y: 29.29}, {x: 654246000000, y: 31.18}, {x: 654332400000, y: 29.47}, {x: 654418800000, y: 28.40}, {x: 654505200000, y: 28.21}, {x: 654764400000, y: 27.73}, {x: 654850800000, y: 27.08}, {x: 654937200000, y: 25.32}, {x: 655023600000, y: 25.69}, {x: 655110000000, y: 27.28}, {x: 655369200000, y: 28.53}, {x: 655455600000, y: 27.88}, {x: 655542000000, y: 28.17}, {x: 655628400000, y: 26.22}, {x: 655714800000, y: 26.07}, {x: 655974000000, y: 28.42}, {x: 656060400000, y: 28.27}, {x: 656146800000, y: 29.76}, {x: 656233200000, y: 29.58}, {x: 656319600000, y: 29.41}, {x: 656578800000, y: 29.34}, {x: 656665200000, y: 29.45}, {x: 656751600000, y: 27.93}, {x: 656838000000, y: 27.68}, {x: 656924400000, y: 27.42}, {x: 657187200000, y: 25.79}, {x: 657273600000, y: 25.84}, {x: 657360000000, y: 26.00}, {x: 657446400000, y: 26.57}, {x: 657532800000, y: 26.66}, {x: 657792000000, y: 26.40}, {x: 657878400000, y: 28.06}, {x: 657964800000, y: 27.58}, {x: 658051200000, y: 27.18}, {x: 658137600000, y: 27.71}, {x: 658396800000, y: 26.37}, {x: 658483200000, y: 26.53}, {x: 658569600000, y: 26.19}, {x: 658656000000, y: 25.29}, {x: 658742400000, y: 27.33}, {x: 659001600000, y: 26.08}, {x: 659088000000, y: 26.26}, {x: 659174400000, y: 26.35}, {x: 659260800000, y: 24.88}, {x: 659347200000, y: 23.71}, {x: 659606400000, y: 25.77}, {x: 659692800000, y: 26.03}, {x: 659779200000, y: 27.38}, {x: 659865600000, y: 27.82}, {x: 659952000000, y: 27.61}, {x: 660211200000, y: 26.15}, {x: 660297600000, y: 26.79}, {x: 660384000000, y: 26.78}, {x: 660470400000, y: 28.69}, {x: 660556800000, y: 29.38}, {x: 660816000000, y: 30.16}, {x: 660902400000, y: 29.42}, {x: 660988800000, y: 29.06}, {x: 661075200000, y: 28.05}, {x: 661161600000, y: 29.48}, {x: 661420800000, y: 28.48}, {x: 661507200000, y: 28.67}, {x: 661593600000, y: 28.27}, {x: 661680000000, y: 27.29}, {x: 661766400000, y: 26.88}, {x: 662025600000, y: 27.12}, {x: 662112000000, y: 27.02}, {x: 662198400000, y: 27.08}, {x: 662284800000, y: 24.53}, {x: 662371200000, y: 25.19}, {x: 662630400000, y: 26.70}, {x: 662716800000, y: 27.23}, {x: 662803200000, y: 26.26}, {x: 662889600000, y: 26.46}, {x: 662976000000, y: 25.38}, {x: 663235200000, y: 25.23}, {x: 663321600000, y: 25.53}, {x: 663408000000, y: 25.71}, {x: 663494400000, y: 25.39}, {x: 663580800000, y: 24.35}, {x: 663840000000, y: 23.64}, {x: 663926400000, y: 22.98}, {x: 664012800000, y: 22.75}, {x: 664099200000, y: 22.70}, {x: 664185600000, y: 21.56}, {x: 664444800000, y: 22.65}, {x: 664531200000, y: 21.54}, {x: 664617600000, y: 20.68}, {x: 664704000000, y: 21.37}, {x: 664790400000, y: 22.44}, {x: 665049600000, y: 23.89}, {x: 665136000000, y: 25.02}, {x: 665222400000, y: 26.84}, {x: 665308800000, y: 26.11}, {x: 665395200000, y: 25.91}, {x: 665654400000, y: 27.21}, {x: 665740800000, y: 26.37}, {x: 665827200000, y: 26.81}, {x: 665913600000, y: 26.42}, {x: 666000000000, y: 26.73}, {x: 666259200000, y: 27.25}, {x: 666345600000, y: 25.01}, {x: 666432000000, y: 24.55}, {x: 666518400000, y: 25.34}, {x: 666604800000, y: 25.37}, {x: 666864000000, y: 27.51}, {x: 666950400000, y: 27.51}, {x: 667036800000, y: 28.65}, {x: 667123200000, y: 28.90}, {x: 667209600000, y: 29.22}, {x: 667468800000, y: 29.77}, {x: 667555200000, y: 29.21}, {x: 667641600000, y: 29.81}, {x: 667728000000, y: 27.75}, {x: 667814400000, y: 28.56}, {x: 668073600000, y: 28.06}, {x: 668160000000, y: 26.70}, {x: 668246400000, y: 26.39}, {x: 668332800000, y: 26.42}, {x: 668419200000, y: 29.05}, {x: 668678400000, y: 27.84}, {x: 668764800000, y: 27.67}, {x: 668851200000, y: 26.75}, {x: 668937600000, y: 26.20}, {x: 669024000000, y: 27.33}, {x: 669283200000, y: 27.55}, {x: 669369600000, y: 26.79}, {x: 669456000000, y: 25.29}, {x: 669542400000, y: 25.17}, {x: 669628800000, y: 25.55}, {x: 669888000000, y: 23.87}, {x: 669974400000, y: 22.92}, {x: 670060800000, y: 23.80}, {x: 670147200000, y: 24.18}, {x: 670233600000, y: 22.56}, {x: 670492800000, y: 21.93}, {x: 670579200000, y: 20.96}, {x: 670665600000, y: 21.94}, {x: 670752000000, y: 21.48}, {x: 670838400000, y: 22.17}, {x: 671094000000, y: 22.68}, {x: 671180400000, y: 20.56}, {x: 671266800000, y: 18.98}, {x: 671353200000, y: 19.93}, {x: 671439600000, y: 19.53}, {x: 671698800000, y: 18.93}, {x: 671785200000, y: 19.41}, {x: 671871600000, y: 18.61}, {x: 671958000000, y: 18.88}, {x: 672044400000, y: 18.70}, {x: 672303600000, y: 18.80}, {x: 672390000000, y: 17.72}, {x: 672476400000, y: 17.65}, {x: 672562800000, y: 17.99}, {x: 672649200000, y: 17.01}, {x: 672908400000, y: 17.05}, {x: 672994800000, y: 16.39}, {x: 673081200000, y: 15.96}, {x: 673167600000, y: 15.82}, {x: 673254000000, y: 16.26}, {x: 673513200000, y: 16.33}, {x: 673599600000, y: 15.73}, {x: 673686000000, y: 15.02}, {x: 673772400000, y: 14.51}, {x: 673858800000, y: 14.71}, {x: 674118000000, y: 15.29}, {x: 674204400000, y: 15.46}, {x: 674290800000, y: 15.30}, {x: 674377200000, y: 14.14}, {x: 674463600000, y: 13.94}, {x: 674722800000, y: 13.01}, {x: 674809200000, y: 13.59}, {x: 674895600000, y: 13.67}, {x: 674982000000, y: 13.28}, {x: 675068400000, y: 13.11}, {x: 675327600000, y: 13.52}, {x: 675414000000, y: 14.02}, {x: 675500400000, y: 14.53}, {x: 675586800000, y: 14.61}, {x: 675673200000, y: 14.53}, {x: 675932400000, y: 14.29}, {x: 676018800000, y: 14.46}, {x: 676105200000, y: 14.07}, {x: 676191600000, y: 13.91}, {x: 676278000000, y: 14.08}, {x: 676537200000, y: 13.63}, {x: 676623600000, y: 14.38}, {x: 676710000000, y: 14.86}, {x: 676796400000, y: 14.82}, {x: 676882800000, y: 14.04}, {x: 677142000000, y: 14.63}, {x: 677228400000, y: 14.83}, {x: 677314800000, y: 15.33}, {x: 677401200000, y: 14.67}, {x: 677487600000, y: 14.18}, {x: 677746800000, y: 14.40}, {x: 677833200000, y: 14.45}, {x: 677919600000, y: 14.78}, {x: 678006000000, y: 14.93}, {x: 678092400000, y: 14.09}, {x: 678351600000, y: 13.56}, {x: 678438000000, y: 14.26}, {x: 678524400000, y: 14.36}, {x: 678610800000, y: 14.82}, {x: 678697200000, y: 15.96}, {x: 678956400000, y: 15.83}, {x: 679042800000, y: 15.92}, {x: 679129200000, y: 15.29}, {x: 679215600000, y: 16.29}, {x: 679302000000, y: 15.31}, {x: 679561200000, y: 15.13}, {x: 679647600000, y: 15.59}, {x: 679734000000, y: 14.97}, {x: 679820400000, y: 15.81}, {x: 679906800000, y: 15.59}, {x: 680166000000, y: 14.83}, {x: 680252400000, y: 14.57}, {x: 680338800000, y: 14.24}, {x: 680425200000, y: 14.49}, {x: 680511600000, y: 13.80}, {x: 680770800000, y: 14.17}, {x: 680857200000, y: 14.40}, {x: 680943600000, y: 14.31}, {x: 681030000000, y: 13.89}, {x: 681116400000, y: 13.59}, {x: 681375600000, y: 13.36}, {x: 681462000000, y: 13.33}, {x: 681548400000, y: 13.26}, {x: 681634800000, y: 13.71}, {x: 681721200000, y: 13.67}, {x: 681980400000, y: 12.87}, {x: 682066800000, y: 14.03}, {x: 682153200000, y: 13.95}, {x: 682239600000, y: 13.11}, {x: 682326000000, y: 14.05}, {x: 682585200000, y: 14.47}, {x: 682671600000, y: 14.45}, {x: 682758000000, y: 15.14}, {x: 682844400000, y: 15.65}, {x: 682930800000, y: 15.15}, {x: 683190000000, y: 15.22}, {x: 683276400000, y: 15.38}, {x: 683362800000, y: 16.42}, {x: 683449200000, y: 16.26}, {x: 683535600000, y: 16.51}, {x: 683794800000, y: 15.66}, {x: 683881200000, y: 15.88}, {x: 683967600000, y: 16.36}, {x: 684054000000, y: 15.87}, {x: 684140400000, y: 15.61}, {x: 684399600000, y: 16.63}, {x: 684486000000, y: 15.88}, {x: 684572400000, y: 17.21}, {x: 684658800000, y: 18.46}, {x: 684745200000, y: 18.76}, {x: 685004400000, y: 18.39}, {x: 685090800000, y: 18.14}, {x: 685177200000, y: 17.31}, {x: 685263600000, y: 17.21}, {x: 685350000000, y: 17.17}, {x: 685609200000, y: 17.21}, {x: 685695600000, y: 16.86}, {x: 685782000000, y: 17.17}, {x: 685868400000, y: 16.20}, {x: 685954800000, y: 15.14}, {x: 686214000000, y: 15.05}, {x: 686300400000, y: 16.09}, {x: 686386800000, y: 16.40}, {x: 686473200000, y: 15.83}, {x: 686559600000, y: 16.53}, {x: 686818800000, y: 16.32}, {x: 686905200000, y: 16.47}, {x: 686991600000, y: 16.59}, {x: 687078000000, y: 16.51}, {x: 687164400000, y: 17.41}, {x: 687423600000, y: 18.17}, {x: 687510000000, y: 17.63}, {x: 687596400000, y: 17.62}, {x: 687682800000, y: 17.69}, {x: 687769200000, y: 17.54}, {x: 688028400000, y: 16.56}, {x: 688114800000, y: 16.83}, {x: 688201200000, y: 15.98}, {x: 688287600000, y: 16.52}, {x: 688374000000, y: 17.08}, {x: 688636800000, y: 17.27}, {x: 688723200000, y: 18.18}, {x: 688809600000, y: 18.67}, {x: 688896000000, y: 18.97}, {x: 688982400000, y: 20.31}, {x: 689241600000, y: 21.30}, {x: 689328000000, y: 20.96}, {x: 689414400000, y: 20.01}, {x: 689500800000, y: 21.13}, {x: 689587200000, y: 21.52}, {x: 689846400000, y: 22.08}, {x: 689932800000, y: 21.88}, {x: 690019200000, y: 21.18}, {x: 690105600000, y: 22.79}, {x: 690192000000, y: 22.51}, {x: 690451200000, y: 23.66}, {x: 690537600000, y: 23.43}, {x: 690624000000, y: 24.08}, {x: 690710400000, y: 24.83}, {x: 690796800000, y: 23.49}, {x: 691056000000, y: 23.43}, {x: 691142400000, y: 23.98}, {x: 691228800000, y: 24.52}, {x: 691315200000, y: 23.32}, {x: 691401600000, y: 23.63}, {x: 691660800000, y: 21.74}, {x: 691747200000, y: 20.03}, {x: 691833600000, y: 20.37}, {x: 691920000000, y: 21.09}, {x: 692006400000, y: 21.33}, {x: 692265600000, y: 20.48}, {x: 692352000000, y: 20.15}, {x: 692438400000, y: 20.33}, {x: 692524800000, y: 19.53}, {x: 692611200000, y: 19.34}, {x: 692870400000, y: 18.63}, {x: 692956800000, y: 18.42}, {x: 693043200000, y: 19.49}, {x: 693129600000, y: 18.75}, {x: 693216000000, y: 18.11}, {x: 693475200000, y: 17.40}, {x: 693561600000, y: 17.40}, {x: 693648000000, y: 17.73}, {x: 693734400000, y: 18.36}, {x: 693820800000, y: 18.14}, {x: 694080000000, y: 18.71}, {x: 694166400000, y: 17.97}, {x: 694252800000, y: 18.90}, {x: 694339200000, y: 18.31}, {x: 694425600000, y: 18.67}, {x: 694684800000, y: 18.78}, {x: 694771200000, y: 19.53}, {x: 694857600000, y: 19.41}, {x: 694944000000, y: 19.42}, {x: 695030400000, y: 20.29}, {x: 695289600000, y: 21.08}, {x: 695376000000, y: 20.69}, {x: 695462400000, y: 21.37}, {x: 695548800000, y: 20.67}, {x: 695635200000, y: 20.79}, {x: 695894400000, y: 20.39}, {x: 695980800000, y: 19.98}, {x: 696067200000, y: 19.35}, {x: 696153600000, y: 18.60}, {x: 696240000000, y: 18.67}, {x: 696499200000, y: 19.41}, {x: 696585600000, y: 20.62}, {x: 696672000000, y: 21.09}, {x: 696758400000, y: 21.43}, {x: 696844800000, y: 20.31}, {x: 697104000000, y: 19.40}, {x: 697190400000, y: 19.82}, {x: 697276800000, y: 19.55}, {x: 697363200000, y: 19.77}, {x: 697449600000, y: 19.33}, {x: 697708800000, y: 18.75}, {x: 697795200000, y: 18.50}, {x: 697881600000, y: 18.39}, {x: 697968000000, y: 19.19}, {x: 698054400000, y: 19.93}, {x: 698313600000, y: 20.15}, {x: 698400000000, y: 22.09}, {x: 698486400000, y: 20.29}, {x: 698572800000, y: 20.37}, {x: 698659200000, y: 19.06}, {x: 698918400000, y: 20.51}, {x: 699004800000, y: 20.06}, {x: 699091200000, y: 19.54}, {x: 699177600000, y: 17.89}, {x: 699264000000, y: 17.57}, {x: 699523200000, y: 16.88}, {x: 699609600000, y: 17.26}, {x: 699696000000, y: 17.15}, {x: 699782400000, y: 15.73}, {x: 699868800000, y: 15.08}, {x: 700128000000, y: 14.73}, {x: 700214400000, y: 14.58}, {x: 700300800000, y: 14.33}, {x: 700387200000, y: 14.76}, {x: 700473600000, y: 15.44}, {x: 700732800000, y: 16.63}, {x: 700819200000, y: 15.63}, {x: 700905600000, y: 15.61}, {x: 700992000000, y: 16.88}, {x: 701078400000, y: 16.26}, {x: 701337600000, y: 15.95}, {x: 701424000000, y: 15.41}, {x: 701510400000, y: 16.14}, {x: 701596800000, y: 15.77}, {x: 701683200000, y: 15.84}, {x: 701942400000, y: 14.41}, {x: 702028800000, y: 15.62}, {x: 702115200000, y: 15.62}, {x: 702201600000, y: 15.85}, {x: 702288000000, y: 17.18}, {x: 702543600000, y: 17.58}, {x: 702630000000, y: 19.25}, {x: 702716400000, y: 19.77}, {x: 702802800000, y: 20.66}, {x: 702889200000, y: 19.70}, {x: 703148400000, y: 20.01}, {x: 703234800000, y: 19.93}, {x: 703321200000, y: 19.94}, {x: 703407600000, y: 19.77}, {x: 703494000000, y: 19.83}];
 
 module.exports = {
-       threshold: 0.01,
-       config: {
-               data: {
-                       datasets: [{
-                               data,
-                               type: 'line',
-                               pointRadius: 0,
-                               fill: false,
-                               tension: 0,
-                               borderWidth: 2
-                       }]
-               },
-               options: {
-                       animation: {
-                               duration: 0
-                       },
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       offset: true,
-                                       ticks: {
-                                               major: {
-                                                       enabled: true,
-                                               },
-                                               font: function(context) {
-                                                       return context.tick && context.tick.major ? {style: 'bold'} : undefined;
-                                               },
-                                               source: 'data',
-                                               autoSkip: true,
-                                               autoSkipPadding: 75,
-                                               maxRotation: 0,
-                                               sampleSize: 100
-                                       },
-                                       // manually set major ticks so that test passes in all time zones with moment adapter
-                                       afterBuildTicks: function(scale) {
-                                               const major = [0, 12, 24];
-                                               const ticks = scale.ticks;
-                                               for (let i = 0; i < ticks.length; i++) {
-                                                       ticks[i].major = major.indexOf(i) >= 0;
-                                               }
-                                       }
-                               },
-                               y: {
-                                       type: 'linear',
-                                       gridLines: {
-                                               drawBorder: false
-                                       }
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    data: {
+      datasets: [{
+        data,
+        type: 'line',
+        pointRadius: 0,
+        fill: false,
+        tension: 0,
+        borderWidth: 2
+      }]
+    },
+    options: {
+      animation: {
+        duration: 0
+      },
+      scales: {
+        x: {
+          type: 'timeseries',
+          offset: true,
+          ticks: {
+            major: {
+              enabled: true,
+            },
+            font: function(context) {
+              return context.tick && context.tick.major ? {style: 'bold'} : undefined;
+            },
+            source: 'data',
+            autoSkip: true,
+            autoSkipPadding: 75,
+            maxRotation: 0,
+            sampleSize: 100
+          },
+          // manually set major ticks so that test passes in all time zones with moment adapter
+          afterBuildTicks: function(scale) {
+            const major = [0, 12, 24];
+            const ticks = scale.ticks;
+            for (let i = 0; i < ticks.length; i++) {
+              ticks[i].major = major.indexOf(i) >= 0;
+            }
+          }
+        },
+        y: {
+          type: 'linear',
+          gridLines: {
+            drawBorder: false
+          }
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index ee67a5b64d9fb8d48302d8df28d65a777378f1da..e53922bb4fb80bcbd77ebae14257ec34989fb337 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'auto'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'auto'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index d82a8dd0b4cdf1bce4fa6003487345b621911e07..e63b5dc5e768fd36720cfb1506522e3597bb2616 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       min: '2012',
-                                       max: '2051',
-                                       offset: true,
-                                       time: {
-                                               parser: 'YYYY',
-                                       },
-                                       ticks: {
-                                               source: 'data'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          min: '2012',
+          max: '2051',
+          offset: true,
+          time: {
+            parser: 'YYYY',
+          },
+          ticks: {
+            source: 'data'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index b835cd90bee20c12fd1b8152f907b4d3fcb4a884..2601cb35130a25cc9b5d4d33b10423a01a95157b 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'data'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'data'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 58dabaa1a56f3d43f05a0d597360690198135441..9c71c65571107138315b157ccd72156c9dc45feb 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       min: '2012',
-                                       max: '2051',
-                                       offset: true,
-                                       time: {
-                                               parser: 'YYYY',
-                                       },
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          min: '2012',
+          max: '2051',
+          offset: true,
+          time: {
+            parser: 'YYYY',
+          },
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 8b2de21fff1b5f41319a18f00ce3f9486ab6cdbe..0087f4a568364b54b7b598a5fc6701336597314c 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2018', '2019', '2020', '2025'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       time: {
-                                               parser: 'YYYY',
-                                               unit: 'year'
-                                       },
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2018', '2019', '2020', '2025'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          time: {
+            parser: 'YYYY',
+            unit: 'year'
+          },
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 41d10fc31daf399eb269621ba130df028ea35262..727770969e44656ec45da10362fd3b8966317395 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       max: '2050',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          max: '2050',
+          time: {
+            parser: 'YYYY'
+          },
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 9a9a74e2cbece2b9450fb11b43b43f1d853b152b..4d892b650082d5a50519afbecadd0fd63dff3635 100644 (file)
@@ -1,32 +1,32 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       min: '2012',
-                                       max: '2050',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          min: '2012',
+          max: '2050',
+          time: {
+            parser: 'YYYY'
+          },
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index c1a7c72f1995bd7be43b2c701e069ded24a829a6..39f7fe05f826e0081f825f2613eadc966dcbff3d 100644 (file)
@@ -1,31 +1,31 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       min: '2012',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          min: '2012',
+          time: {
+            parser: 'YYYY'
+          },
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 46e75e1ddcd3998fe4b816d7b7569e9e4e369263..237b473d7b61cae1fff4e151a9c5e51373c80fb1 100644 (file)
@@ -1,30 +1,30 @@
 module.exports = {
-       threshold: 0.01,
-       config: {
-               type: 'line',
-               data: {
-                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                       datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
-               },
-               options: {
-                       scales: {
-                               x: {
-                                       type: 'timeseries',
-                                       time: {
-                                               parser: 'YYYY'
-                                       },
-                                       reverse: true,
-                                       ticks: {
-                                               source: 'labels'
-                                       }
-                               },
-                               y: {
-                                       display: false
-                               }
-                       }
-               }
-       },
-       options: {
-               spriteText: true
-       }
+  threshold: 0.01,
+  config: {
+    type: 'line',
+    data: {
+      labels: ['2017', '2019', '2020', '2025', '2042'],
+      datasets: [{data: [0, 1, 2, 3, 4], fill: false}]
+    },
+    options: {
+      scales: {
+        x: {
+          type: 'timeseries',
+          time: {
+            parser: 'YYYY'
+          },
+          reverse: true,
+          ticks: {
+            source: 'labels'
+          }
+        },
+        y: {
+          display: false
+        }
+      }
+    }
+  },
+  options: {
+    spriteText: true
+  }
 };
index 0a764c3db42763db2331869167094d132a3eadc9..489fca0a797dd30dcf15f72de2e533bbcece5f97 100644 (file)
@@ -13,15 +13,15 @@ window.createMockContext = createMockContext;
 injectWrapperCSS();
 
 jasmine.fixture = {
-       specs: specsFromFixtures
+  specs: specsFromFixtures
 };
 
 jasmine.triggerMouseEvent = triggerMouseEvent;
 
 beforeEach(function() {
-       addMatchers();
+  addMatchers();
 });
 
 afterEach(function() {
-       releaseCharts();
+  releaseCharts();
 });
index f73944814c1884ce0cf4f4091791ca3f76fd9069..b991c6cc445c8eba85e3a17226b7ef4b58b95cb0 100644 (file)
 describe('Chart.controllers.bar', function() {
-       describe('auto', jasmine.fixture.specs('controller.bar'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.bar).toBe('function');
-       });
-
-       it('should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.type).toEqual('bar');
-               expect(meta.data).toEqual([]);
-               expect(meta.hidden).toBe(null);
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(1);
-               expect(meta.xAxisID).not.toBe(null);
-               expect(meta.yAxisID).not.toBe(null);
-
-               meta.controller.updateIndex(0);
-               expect(meta.controller.index).toBe(0);
-       });
-
-       it('should use the first scale IDs if the dataset does not specify them', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.xAxisID).toBe('x');
-               expect(meta.yAxisID).toBe('y');
-       });
-
-       it('should correctly count the number of stacks ignoring datasets of other types and hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], type: 'line'},
-                                       {data: [], hidden: true},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackCount()).toBe(2);
-       });
-
-       it('should correctly count the number of stacks when a group is not specified', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackCount()).toBe(4);
-       });
-
-       it('should correctly count the number of stacks when a group is not specified and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackCount()).toBe(1);
-       });
-
-       it('should correctly count the number of stacks when a group is not specified and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackCount()).toBe(4);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for some', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(3);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for some and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(2);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for some and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(4);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for all', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(2);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for all and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(2);
-       });
-
-       it('should correctly count the number of stacks when a group is specified for all and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(3);
-               expect(meta.controller._getStackCount()).toBe(4);
-       });
-
-       it('should correctly get the stack index accounting for datasets of other types and hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: [], hidden: true},
-                                       {data: [], type: 'line'},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(3)).toBe(1);
-       });
-
-       it('should correctly get the stack index when a group is not specified', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(1);
-               expect(meta.controller._getStackIndex(2)).toBe(2);
-               expect(meta.controller._getStackIndex(3)).toBe(3);
-       });
-
-       it('should correctly get the stack index when a group is not specified and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(0);
-               expect(meta.controller._getStackIndex(2)).toBe(0);
-               expect(meta.controller._getStackIndex(3)).toBe(0);
-       });
-
-       it('should correctly get the stack index when a group is not specified and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(1);
-               expect(meta.controller._getStackIndex(2)).toBe(2);
-               expect(meta.controller._getStackIndex(3)).toBe(3);
-       });
-
-       it('should correctly get the stack index when a group is specified for some', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(0);
-               expect(meta.controller._getStackIndex(2)).toBe(1);
-               expect(meta.controller._getStackIndex(3)).toBe(2);
-       });
-
-       it('should correctly get the stack index when a group is specified for some and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(0);
-               expect(meta.controller._getStackIndex(2)).toBe(1);
-               expect(meta.controller._getStackIndex(3)).toBe(1);
-       });
-
-       it('should correctly get the stack index when a group is specified for some and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(1);
-               expect(meta.controller._getStackIndex(2)).toBe(2);
-               expect(meta.controller._getStackIndex(3)).toBe(3);
-       });
-
-       it('should correctly get the stack index when a group is specified for all', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(0);
-               expect(meta.controller._getStackIndex(2)).toBe(1);
-               expect(meta.controller._getStackIndex(3)).toBe(1);
-       });
-
-       it('should correctly get the stack index when a group is specified for all and the scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(0);
-               expect(meta.controller._getStackIndex(2)).toBe(1);
-               expect(meta.controller._getStackIndex(3)).toBe(1);
-       });
-
-       it('should correctly get the stack index when a group is specified for all and the scale is not stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack1'},
-                                       {data: [], stack: 'stack2'},
-                                       {data: [], stack: 'stack2'}
-                               ],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: false
-                                       },
-                                       y: {
-                                               stacked: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller._getStackIndex(0)).toBe(0);
-               expect(meta.controller._getStackIndex(1)).toBe(1);
-               expect(meta.controller._getStackIndex(2)).toBe(2);
-               expect(meta.controller._getStackIndex(3)).toBe(3);
-       });
-
-       it('should create bar elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: [10, 15, 0, -4]}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.data.length).toBe(4); // 4 bars created
-               expect(meta.data[0] instanceof Chart.elements.BarElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.BarElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.BarElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.BarElement).toBe(true);
-       });
-
-       it('should update elements when modifying data', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2',
-                                       borderColor: 'blue'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               elements: {
-                                       bar: {
-                                               backgroundColor: 'red',
-                                               borderSkipped: 'top',
-                                               borderColor: 'green',
-                                               borderWidth: 2,
-                                       }
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.data.length).toBe(4);
-
-               chart.data.datasets[1].data = [1, 2]; // remove 2 items
-               chart.data.datasets[1].borderWidth = 1;
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-               expect(meta._parsed.length).toBe(2);
-
-               [
-                       {x: 89, y: 512},
-                       {x: 217, y: 0}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].base).toBeCloseToPixel(1024);
-                       expect(meta.data[i].width).toBeCloseToPixel(46);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'red',
-                               borderSkipped: 'top',
-                               borderColor: 'blue',
-                               borderWidth: 1
-                       }));
-               });
-
-               chart.data.datasets[1].data = [1, 2, 3]; // add 1 items
-               chart.update();
-
-               expect(meta.data.length).toBe(3); // should add a new meta data item
-       });
-
-       it('should get the correct bar points when datasets of different types exist', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2],
-                                       label: 'dataset1'
-                               }, {
-                                       type: 'line',
-                                       data: [4, 6],
-                                       label: 'dataset2'
-                               }, {
-                                       data: [8, 10],
-                                       label: 'dataset3'
-                               }],
-                               labels: ['label1', 'label2']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(2);
-               expect(meta.data.length).toBe(2);
-
-               var bar1 = meta.data[0];
-               var bar2 = meta.data[1];
-
-               expect(bar1.x).toBeCloseToPixel(179);
-               expect(bar1.y).toBeCloseToPixel(114);
-               expect(bar2.x).toBeCloseToPixel(435);
-               expect(bar2.y).toBeCloseToPixel(0);
-       });
-
-       it('should get the bar points for hidden dataset', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2],
-                                       label: 'dataset1',
-                                       hidden: true
-                               }],
-                               labels: ['label1', 'label2']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               min: 0,
-                                               max: 2,
-                                               display: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(2);
-
-               var bar1 = meta.data[0];
-               var bar2 = meta.data[1];
-
-               expect(bar1.x).toBeCloseToPixel(128);
-               expect(bar1.y).toBeCloseToPixel(256);
-               expect(bar2.x).toBeCloseToPixel(384);
-               expect(bar2.y).toBeCloseToPixel(0);
-       });
-
-
-       it('should update elements when the scales are stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [10, -10, 10, -10],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {b: 293, w: 92 / 2, x: 38, y: 146},
-                       {b: 293, w: 92 / 2, x: 166, y: 439},
-                       {b: 293, w: 92 / 2, x: 295, y: 146},
-                       {b: 293, w: 92 / 2, x: 422, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta0.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {b: 146, w: 92 / 2, x: 89, y: 0},
-                       {b: 293, w: 92 / 2, x: 217, y: 73},
-                       {b: 146, w: 92 / 2, x: 345, y: 146},
-                       {b: 439, w: 92 / 2, x: 473, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta1.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should update elements when the scales are stacked and the y axis has a user defined minimum', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [50, 20, 10, 100],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [50, 80, 90, 0],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true,
-                                               min: 50,
-                                               max: 100
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {b: 1024, w: 92 / 2, x: 38, y: 512},
-                       {b: 1024, w: 92 / 2, x: 166, y: 819},
-                       {b: 1024, w: 92 / 2, x: 294, y: 922},
-                       {b: 1024, w: 92 / 2, x: 422.5, y: 0}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta0.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {b: 512, w: 92 / 2, x: 89, y: 0},
-                       {b: 819.2, w: 92 / 2, x: 217, y: 0},
-                       {b: 921.6, w: 92 / 2, x: 345, y: 0},
-                       {b: 0, w: 92 / 2, x: 473.5, y: 0}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta1.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should update elements when only the category scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [20, -10, 10, -10],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [10, 15, 0, -14],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false,
-                                               stacked: true
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {b: 293, w: 92, x: 64, y: 0},
-                       {b: 293, w: 92, x: 192, y: 439},
-                       {b: 293, w: 92, x: 320, y: 146},
-                       {b: 293, w: 92, x: 448, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta0.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {b: 293, w: 92, x: 64, y: 146},
-                       {b: 293, w: 92, x: 192, y: 73},
-                       {b: 293, w: 92, x: 320, y: 293},
-                       {b: 293, w: 92, x: 448, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta1.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should update elements when the scales are stacked and data is strings', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: ['10', '-10', '10', '-10'],
-                                       label: 'dataset1'
-                               }, {
-                                       data: ['10', '15', '0', '-4'],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {b: 293, w: 92 / 2, x: 38, y: 146},
-                       {b: 293, w: 92 / 2, x: 166, y: 439},
-                       {b: 293, w: 92 / 2, x: 295, y: 146},
-                       {b: 293, w: 92 / 2, x: 422, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta0.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {b: 146, w: 92 / 2, x: 89, y: 0},
-                       {b: 293, w: 92 / 2, x: 217, y: 73},
-                       {b: 146, w: 92 / 2, x: 345, y: 146},
-                       {b: 439, w: 92 / 2, x: 473, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta1.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should get the correct bar points for grouped stacked chart if the group name is same', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [10, -10, 10, -10],
-                                       label: 'dataset1',
-                                       stack: 'stack1'
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2',
-                                       stack: 'stack1'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {b: 293, w: 92, x: 64, y: 146},
-                       {b: 293, w: 92, x: 192, y: 439},
-                       {b: 293, w: 92, x: 320, y: 146},
-                       {b: 293, w: 92, x: 448, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta0.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta = chart.getDatasetMeta(1);
-
-               [
-                       {b: 146, w: 92, x: 64, y: 0},
-                       {b: 293, w: 92, x: 192, y: 73},
-                       {b: 146, w: 92, x: 320, y: 146},
-                       {b: 439, w: 92, x: 448, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta.data[i].width).toBeCloseToPixel(values.w);
-                       expect(meta.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should get the correct bar points for grouped stacked chart if the group name is different', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2],
-                                       stack: 'stack1'
-                               }, {
-                                       data: [1, 2],
-                                       stack: 'stack2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true,
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-
-               [
-                       {x: 89, y: 256},
-                       {x: 217, y: 0}
-               ].forEach(function(values, i) {
-                       expect(meta.data[i].base).toBeCloseToPixel(512);
-                       expect(meta.data[i].width).toBeCloseToPixel(46);
-                       expect(meta.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should get the correct bar points for grouped stacked chart', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2],
-                                       stack: 'stack1'
-                               }, {
-                                       data: [0.5, 1],
-                                       stack: 'stack2'
-                               }, {
-                                       data: [0.5, 1],
-                                       stack: 'stack2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(2);
-
-               [
-                       {b: 384, x: 89, y: 256},
-                       {b: 256, x: 217, y: 0}
-               ].forEach(function(values, i) {
-                       expect(meta.data[i].base).toBeCloseToPixel(values.b);
-                       expect(meta.data[i].width).toBeCloseToPixel(46);
-                       expect(meta.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(values.y);
-               });
-       });
-
-       it('should draw all bars', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [],
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should set hover styles on bars', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [],
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               elements: {
-                                       bar: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               var bar = meta.data[0];
-
-               meta.controller.setHoverStyle(bar, 1, 0);
-               expect(bar.options.backgroundColor).toBe('#E60000');
-               expect(bar.options.borderColor).toBe('#0000E6');
-               expect(bar.options.borderWidth).toBe(2);
-
-               // Set a dataset style
-               chart.data.datasets[1].hoverBackgroundColor = 'rgb(128, 128, 128)';
-               chart.data.datasets[1].hoverBorderColor = 'rgb(0, 0, 0)';
-               chart.data.datasets[1].hoverBorderWidth = 5;
-               chart.update();
-
-               meta.controller.setHoverStyle(bar, 1, 0);
-               expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
-               expect(bar.options.borderColor).toBe('rgb(0, 0, 0)');
-               expect(bar.options.borderWidth).toBe(5);
-
-               // Should work with array styles so that we can set per bar
-               chart.data.datasets[1].hoverBackgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
-               chart.data.datasets[1].hoverBorderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
-               chart.data.datasets[1].hoverBorderWidth = [2.5, 5];
-               chart.update();
-
-               meta.controller.setHoverStyle(bar, 1, 0);
-               expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
-               expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
-               expect(bar.options.borderWidth).toBe(2.5);
-       });
-
-       it('should remove a hover style from a bar', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [],
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               elements: {
-                                       bar: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2,
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               var bar = meta.data[0];
-               var helpers = window.Chart.helpers;
-
-               // Change default
-               chart.options.elements.bar.backgroundColor = 'rgb(128, 128, 128)';
-               chart.options.elements.bar.borderColor = 'rgb(15, 15, 15)';
-               chart.options.elements.bar.borderWidth = 3.14;
-
-               chart.update();
-               expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
-               expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
-               expect(bar.options.borderWidth).toBe(3.14);
-               meta.controller.setHoverStyle(bar, 1, 0);
-               expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(128, 128, 128)'));
-               expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(15, 15, 15)'));
-               expect(bar.options.borderWidth).toBe(3.14);
-               meta.controller.removeHoverStyle(bar);
-               expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
-               expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
-               expect(bar.options.borderWidth).toBe(3.14);
-
-               // Should work with array styles so that we can set per bar
-               chart.data.datasets[1].backgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
-               chart.data.datasets[1].borderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
-               chart.data.datasets[1].borderWidth = [2.5, 5];
-
-               chart.update();
-               expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
-               expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
-               expect(bar.options.borderWidth).toBe(2.5);
-               meta.controller.setHoverStyle(bar, 1, 0);
-               expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(255, 255, 255)'));
-               expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(9, 9, 9)'));
-               expect(bar.options.borderWidth).toBe(2.5);
-               meta.controller.removeHoverStyle(bar);
-               expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
-               expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
-               expect(bar.options.borderWidth).toBe(2.5);
-       });
-
-       describe('Bar width', function() {
-               beforeEach(function() {
-                       // 2 datasets
-                       this.data = {
-                               labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
-                               datasets: [{
-                                       data: [10, 20, 30, 40, 50, 60, 70],
-                               }, {
-                                       data: [10, 20, 30, 40, 50, 60, 70],
-                               }]
-                       };
-               });
-
-               afterEach(function() {
-                       var chart = window.acquireChart(this.config);
-                       var meta = chart.getDatasetMeta(0);
-                       var xScale = chart.scales[meta.xAxisID];
-                       var options = Chart.defaults.controllers.bar.datasets;
-
-                       var categoryPercentage = options.categoryPercentage;
-                       var barPercentage = options.barPercentage;
-                       var stacked = xScale.options.stacked;
-
-                       var totalBarWidth = 0;
-                       for (var i = 0; i < chart.data.datasets.length; i++) {
-                               var bars = chart.getDatasetMeta(i).data;
-                               for (var j = xScale.min; j <= xScale.max; j++) {
-                                       totalBarWidth += bars[j].width;
-                               }
-                               if (stacked) {
-                                       break;
-                               }
-                       }
-
-                       var actualValue = totalBarWidth;
-                       var expectedValue = xScale.width * categoryPercentage * barPercentage;
-                       expect(actualValue).toBeCloseToPixel(expectedValue);
-
-               });
-
-               it('should correctly set bar width when min and max option is set.', function() {
-                       this.config = {
-                               type: 'bar',
-                               data: this.data,
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       min: 'March',
-                                                       max: 'May',
-                                               }
-                                       }
-                               }
-                       };
-               });
-
-               it('should correctly set bar width when scale are stacked with min and max options.', function() {
-                       this.config = {
-                               type: 'bar',
-                               data: this.data,
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       min: 'March',
-                                                       max: 'May',
-                                               },
-                                               y: {
-                                                       stacked: true
-                                               }
-                                       }
-                               }
-                       };
-               });
-       });
-
-       describe('Bar height (horizontal type)', function() {
-               beforeEach(function() {
-                       // 2 datasets
-                       this.data = {
-                               labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
-                               datasets: [{
-                                       data: [10, 20, 30, 40, 50, 60, 70],
-                               }, {
-                                       data: [10, 20, 30, 40, 50, 60, 70],
-                               }]
-                       };
-               });
-
-               afterEach(function() {
-                       var chart = window.acquireChart(this.config);
-                       var meta = chart.getDatasetMeta(0);
-                       var yScale = chart.scales[meta.yAxisID];
-
-                       var config = meta.controller._config;
-                       var categoryPercentage = config.categoryPercentage;
-                       var barPercentage = config.barPercentage;
-                       var stacked = yScale.options.stacked;
-
-                       var totalBarHeight = 0;
-                       for (var i = 0; i < chart.data.datasets.length; i++) {
-                               var bars = chart.getDatasetMeta(i).data;
-                               for (var j = yScale.min; j <= yScale.max; j++) {
-                                       totalBarHeight += bars[j].height;
-                               }
-                               if (stacked) {
-                                       break;
-                               }
-                       }
-
-                       var actualValue = totalBarHeight;
-                       var expectedValue = yScale.height * categoryPercentage * barPercentage;
-                       expect(actualValue).toBeCloseToPixel(expectedValue);
-
-               });
-
-               it('should correctly set bar height when min and max option is set.', function() {
-                       this.config = {
-                               type: 'bar',
-                               data: this.data,
-                               options: {
-                                       indexAxis: 'y',
-                                       scales: {
-                                               y: {
-                                                       min: 'March',
-                                                       max: 'May',
-                                               }
-                                       }
-                               }
-                       };
-               });
-
-               it('should correctly set bar height when scale are stacked with min and max options.', function() {
-                       this.config = {
-                               type: 'bar',
-                               data: this.data,
-                               options: {
-                                       indexAxis: 'y',
-                                       scales: {
-                                               x: {
-                                                       stacked: true
-                                               },
-                                               y: {
-                                                       min: 'March',
-                                                       max: 'May',
-                                               }
-                                       }
-                               }
-                       };
-               });
-       });
-
-       describe('Bar thickness with a category scale', function() {
-               [undefined, 20].forEach(function(barThickness) {
-                       describe('When barThickness is ' + barThickness, function() {
-                               beforeEach(function() {
-                                       this.chart = window.acquireChart({
-                                               type: 'bar',
-                                               data: {
-                                                       datasets: [{
-                                                               data: [1, 2]
-                                                       }, {
-                                                               data: [1, 2]
-                                                       }],
-                                                       labels: ['label1', 'label2', 'label3']
-                                               },
-                                               options: {
-                                                       legend: false,
-                                                       title: false,
-                                                       datasets: {
-                                                               bar: {
-                                                                       barThickness: barThickness
-                                                               }
-                                                       },
-                                                       scales: {
-                                                               x: {
-                                                                       id: 'x',
-                                                                       type: 'category',
-                                                               },
-                                                               y: {
-                                                                       type: 'linear',
-                                                               }
-                                                       }
-                                               }
-                                       });
-                               });
-
-                               it('should correctly set bar width', function() {
-                                       var chart = this.chart;
-                                       var expected, i, ilen, meta;
-
-                                       if (barThickness) {
-                                               expected = barThickness;
-                                       } else {
-                                               var scale = chart.scales.x;
-                                               var options = Chart.defaults.controllers.bar.datasets;
-                                               var categoryPercentage = options.categoryPercentage;
-                                               var barPercentage = options.barPercentage;
-                                               var tickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
-
-                                               expected = tickInterval * categoryPercentage / 2 * barPercentage;
-                                       }
-
-                                       for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
-                                               meta = chart.getDatasetMeta(i);
-                                               expect(meta.data[0].width).toBeCloseToPixel(expected);
-                                               expect(meta.data[1].width).toBeCloseToPixel(expected);
-                                       }
-                               });
-
-                               it('should correctly set bar width if maxBarThickness is specified', function() {
-                                       var chart = this.chart;
-                                       var i, ilen, meta;
-
-                                       chart.data.datasets[0].maxBarThickness = 10;
-                                       chart.data.datasets[1].maxBarThickness = 10;
-                                       chart.update();
-
-                                       for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
-                                               meta = chart.getDatasetMeta(i);
-                                               expect(meta.data[0].width).toBeCloseToPixel(10);
-                                               expect(meta.data[1].width).toBeCloseToPixel(10);
-                                       }
-                               });
-                       });
-               });
-       });
-
-       it('minBarLength settings should be used on Y axis on bar chart', function() {
-               var minBarLength = 4;
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       minBarLength: minBarLength,
-                                       data: [0.05, -0.05, 10, 15, 20, 25, 30, 35]
-                               }]
-                       }
-               });
-
-               var data = chart.getDatasetMeta(0).data;
-
-               expect(data[0].base - minBarLength).toEqual(data[0].y);
-               expect(data[1].base + minBarLength).toEqual(data[1].y);
-       });
-
-       it('minBarLength settings should be used on X axis on horizontal bar chart', function() {
-               var minBarLength = 4;
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       indexAxis: 'y',
-                                       minBarLength: minBarLength,
-                                       data: [0.05, -0.05, 10, 15, 20, 25, 30, 35]
-                               }]
-                       }
-               });
-
-               var data = chart.getDatasetMeta(0).data;
-
-               expect(data[0].base + minBarLength).toEqual(data[0].x);
-               expect(data[1].base - minBarLength).toEqual(data[1].x);
-       });
-
-       it('should respect the data visibility settings', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2, 3, 4]
-                               }],
-                               labels: ['A', 'B', 'C', 'D']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false,
-                                       }
-                               }
-                       }
-               });
-
-               var data = chart.getDatasetMeta(0).data;
-               expect(data[0].base).toBeCloseToPixel(512);
-               expect(data[0].y).toBeCloseToPixel(384);
-
-               chart.toggleDataVisibility(0);
-               chart.update();
-
-               data = chart.getDatasetMeta(0).data;
-               expect(data[0].base).toBeCloseToPixel(512);
-               expect(data[0].y).toBeCloseToPixel(512);
-       });
-
-       describe('Float bar', function() {
-               it('Should return correct values from getMinMax', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       labels: ['a'],
-                                       datasets: [{
-                                               data: [[10, -10]]
-                                       }]
-                               }
-                       });
-
-                       expect(chart.scales.y.getMinMax()).toEqual({min: -10, max: 10});
-               });
-       });
+  describe('auto', jasmine.fixture.specs('controller.bar'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.bar).toBe('function');
+  });
+
+  it('should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.type).toEqual('bar');
+    expect(meta.data).toEqual([]);
+    expect(meta.hidden).toBe(null);
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(1);
+    expect(meta.xAxisID).not.toBe(null);
+    expect(meta.yAxisID).not.toBe(null);
+
+    meta.controller.updateIndex(0);
+    expect(meta.controller.index).toBe(0);
+  });
+
+  it('should use the first scale IDs if the dataset does not specify them', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.xAxisID).toBe('x');
+    expect(meta.yAxisID).toBe('y');
+  });
+
+  it('should correctly count the number of stacks ignoring datasets of other types and hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], type: 'line'},
+          {data: [], hidden: true},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackCount()).toBe(2);
+  });
+
+  it('should correctly count the number of stacks when a group is not specified', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackCount()).toBe(4);
+  });
+
+  it('should correctly count the number of stacks when a group is not specified and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackCount()).toBe(1);
+  });
+
+  it('should correctly count the number of stacks when a group is not specified and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackCount()).toBe(4);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for some', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(3);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for some and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(2);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for some and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(4);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for all', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(2);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for all and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(2);
+  });
+
+  it('should correctly count the number of stacks when a group is specified for all and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(3);
+    expect(meta.controller._getStackCount()).toBe(4);
+  });
+
+  it('should correctly get the stack index accounting for datasets of other types and hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: [], hidden: true},
+          {data: [], type: 'line'},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(3)).toBe(1);
+  });
+
+  it('should correctly get the stack index when a group is not specified', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(1);
+    expect(meta.controller._getStackIndex(2)).toBe(2);
+    expect(meta.controller._getStackIndex(3)).toBe(3);
+  });
+
+  it('should correctly get the stack index when a group is not specified and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(0);
+    expect(meta.controller._getStackIndex(2)).toBe(0);
+    expect(meta.controller._getStackIndex(3)).toBe(0);
+  });
+
+  it('should correctly get the stack index when a group is not specified and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(1);
+    expect(meta.controller._getStackIndex(2)).toBe(2);
+    expect(meta.controller._getStackIndex(3)).toBe(3);
+  });
+
+  it('should correctly get the stack index when a group is specified for some', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(0);
+    expect(meta.controller._getStackIndex(2)).toBe(1);
+    expect(meta.controller._getStackIndex(3)).toBe(2);
+  });
+
+  it('should correctly get the stack index when a group is specified for some and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(0);
+    expect(meta.controller._getStackIndex(2)).toBe(1);
+    expect(meta.controller._getStackIndex(3)).toBe(1);
+  });
+
+  it('should correctly get the stack index when a group is specified for some and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(1);
+    expect(meta.controller._getStackIndex(2)).toBe(2);
+    expect(meta.controller._getStackIndex(3)).toBe(3);
+  });
+
+  it('should correctly get the stack index when a group is specified for all', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(0);
+    expect(meta.controller._getStackIndex(2)).toBe(1);
+    expect(meta.controller._getStackIndex(3)).toBe(1);
+  });
+
+  it('should correctly get the stack index when a group is specified for all and the scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(0);
+    expect(meta.controller._getStackIndex(2)).toBe(1);
+    expect(meta.controller._getStackIndex(3)).toBe(1);
+  });
+
+  it('should correctly get the stack index when a group is specified for all and the scale is not stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack1'},
+          {data: [], stack: 'stack2'},
+          {data: [], stack: 'stack2'}
+        ],
+        labels: []
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: false
+          },
+          y: {
+            stacked: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.controller._getStackIndex(0)).toBe(0);
+    expect(meta.controller._getStackIndex(1)).toBe(1);
+    expect(meta.controller._getStackIndex(2)).toBe(2);
+    expect(meta.controller._getStackIndex(3)).toBe(3);
+  });
+
+  it('should create bar elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: []},
+          {data: [10, 15, 0, -4]}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.data.length).toBe(4); // 4 bars created
+    expect(meta.data[0] instanceof Chart.elements.BarElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.BarElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.BarElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.BarElement).toBe(true);
+  });
+
+  it('should update elements when modifying data', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2],
+          label: 'dataset1'
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2',
+          borderColor: 'blue'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        elements: {
+          bar: {
+            backgroundColor: 'red',
+            borderSkipped: 'top',
+            borderColor: 'green',
+            borderWidth: 2,
+          }
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.data.length).toBe(4);
+
+    chart.data.datasets[1].data = [1, 2]; // remove 2 items
+    chart.data.datasets[1].borderWidth = 1;
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+    expect(meta._parsed.length).toBe(2);
+
+    [
+      {x: 89, y: 512},
+      {x: 217, y: 0}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].base).toBeCloseToPixel(1024);
+      expect(meta.data[i].width).toBeCloseToPixel(46);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'red',
+        borderSkipped: 'top',
+        borderColor: 'blue',
+        borderWidth: 1
+      }));
+    });
+
+    chart.data.datasets[1].data = [1, 2, 3]; // add 1 items
+    chart.update();
+
+    expect(meta.data.length).toBe(3); // should add a new meta data item
+  });
+
+  it('should get the correct bar points when datasets of different types exist', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2],
+          label: 'dataset1'
+        }, {
+          type: 'line',
+          data: [4, 6],
+          label: 'dataset2'
+        }, {
+          data: [8, 10],
+          label: 'dataset3'
+        }],
+        labels: ['label1', 'label2']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(2);
+    expect(meta.data.length).toBe(2);
+
+    var bar1 = meta.data[0];
+    var bar2 = meta.data[1];
+
+    expect(bar1.x).toBeCloseToPixel(179);
+    expect(bar1.y).toBeCloseToPixel(114);
+    expect(bar2.x).toBeCloseToPixel(435);
+    expect(bar2.y).toBeCloseToPixel(0);
+  });
+
+  it('should get the bar points for hidden dataset', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2],
+          label: 'dataset1',
+          hidden: true
+        }],
+        labels: ['label1', 'label2']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            min: 0,
+            max: 2,
+            display: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(2);
+
+    var bar1 = meta.data[0];
+    var bar2 = meta.data[1];
+
+    expect(bar1.x).toBeCloseToPixel(128);
+    expect(bar1.y).toBeCloseToPixel(256);
+    expect(bar2.x).toBeCloseToPixel(384);
+    expect(bar2.y).toBeCloseToPixel(0);
+  });
+
+
+  it('should update elements when the scales are stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [10, -10, 10, -10],
+          label: 'dataset1'
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {b: 293, w: 92 / 2, x: 38, y: 146},
+      {b: 293, w: 92 / 2, x: 166, y: 439},
+      {b: 293, w: 92 / 2, x: 295, y: 146},
+      {b: 293, w: 92 / 2, x: 422, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta0.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {b: 146, w: 92 / 2, x: 89, y: 0},
+      {b: 293, w: 92 / 2, x: 217, y: 73},
+      {b: 146, w: 92 / 2, x: 345, y: 146},
+      {b: 439, w: 92 / 2, x: 473, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta1.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should update elements when the scales are stacked and the y axis has a user defined minimum', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [50, 20, 10, 100],
+          label: 'dataset1'
+        }, {
+          data: [50, 80, 90, 0],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true,
+            min: 50,
+            max: 100
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {b: 1024, w: 92 / 2, x: 38, y: 512},
+      {b: 1024, w: 92 / 2, x: 166, y: 819},
+      {b: 1024, w: 92 / 2, x: 294, y: 922},
+      {b: 1024, w: 92 / 2, x: 422.5, y: 0}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta0.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {b: 512, w: 92 / 2, x: 89, y: 0},
+      {b: 819.2, w: 92 / 2, x: 217, y: 0},
+      {b: 921.6, w: 92 / 2, x: 345, y: 0},
+      {b: 0, w: 92 / 2, x: 473.5, y: 0}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta1.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should update elements when only the category scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [20, -10, 10, -10],
+          label: 'dataset1'
+        }, {
+          data: [10, 15, 0, -14],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false,
+            stacked: true
+          },
+          y: {
+            type: 'linear',
+            display: false
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {b: 293, w: 92, x: 64, y: 0},
+      {b: 293, w: 92, x: 192, y: 439},
+      {b: 293, w: 92, x: 320, y: 146},
+      {b: 293, w: 92, x: 448, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta0.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {b: 293, w: 92, x: 64, y: 146},
+      {b: 293, w: 92, x: 192, y: 73},
+      {b: 293, w: 92, x: 320, y: 293},
+      {b: 293, w: 92, x: 448, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta1.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should update elements when the scales are stacked and data is strings', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: ['10', '-10', '10', '-10'],
+          label: 'dataset1'
+        }, {
+          data: ['10', '15', '0', '-4'],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {b: 293, w: 92 / 2, x: 38, y: 146},
+      {b: 293, w: 92 / 2, x: 166, y: 439},
+      {b: 293, w: 92 / 2, x: 295, y: 146},
+      {b: 293, w: 92 / 2, x: 422, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta0.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {b: 146, w: 92 / 2, x: 89, y: 0},
+      {b: 293, w: 92 / 2, x: 217, y: 73},
+      {b: 146, w: 92 / 2, x: 345, y: 146},
+      {b: 439, w: 92 / 2, x: 473, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta1.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should get the correct bar points for grouped stacked chart if the group name is same', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [10, -10, 10, -10],
+          label: 'dataset1',
+          stack: 'stack1'
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2',
+          stack: 'stack1'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {b: 293, w: 92, x: 64, y: 146},
+      {b: 293, w: 92, x: 192, y: 439},
+      {b: 293, w: 92, x: 320, y: 146},
+      {b: 293, w: 92, x: 448, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta0.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta = chart.getDatasetMeta(1);
+
+    [
+      {b: 146, w: 92, x: 64, y: 0},
+      {b: 293, w: 92, x: 192, y: 73},
+      {b: 146, w: 92, x: 320, y: 146},
+      {b: 439, w: 92, x: 448, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta.data[i].width).toBeCloseToPixel(values.w);
+      expect(meta.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should get the correct bar points for grouped stacked chart if the group name is different', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2],
+          stack: 'stack1'
+        }, {
+          data: [1, 2],
+          stack: 'stack2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true,
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+
+    [
+      {x: 89, y: 256},
+      {x: 217, y: 0}
+    ].forEach(function(values, i) {
+      expect(meta.data[i].base).toBeCloseToPixel(512);
+      expect(meta.data[i].width).toBeCloseToPixel(46);
+      expect(meta.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should get the correct bar points for grouped stacked chart', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2],
+          stack: 'stack1'
+        }, {
+          data: [0.5, 1],
+          stack: 'stack2'
+        }, {
+          data: [0.5, 1],
+          stack: 'stack2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(2);
+
+    [
+      {b: 384, x: 89, y: 256},
+      {b: 256, x: 217, y: 0}
+    ].forEach(function(values, i) {
+      expect(meta.data[i].base).toBeCloseToPixel(values.b);
+      expect(meta.data[i].width).toBeCloseToPixel(46);
+      expect(meta.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta.data[i].y).toBeCloseToPixel(values.y);
+    });
+  });
+
+  it('should draw all bars', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [],
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should set hover styles on bars', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [],
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        elements: {
+          bar: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    var bar = meta.data[0];
+
+    meta.controller.setHoverStyle(bar, 1, 0);
+    expect(bar.options.backgroundColor).toBe('#E60000');
+    expect(bar.options.borderColor).toBe('#0000E6');
+    expect(bar.options.borderWidth).toBe(2);
+
+    // Set a dataset style
+    chart.data.datasets[1].hoverBackgroundColor = 'rgb(128, 128, 128)';
+    chart.data.datasets[1].hoverBorderColor = 'rgb(0, 0, 0)';
+    chart.data.datasets[1].hoverBorderWidth = 5;
+    chart.update();
+
+    meta.controller.setHoverStyle(bar, 1, 0);
+    expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
+    expect(bar.options.borderColor).toBe('rgb(0, 0, 0)');
+    expect(bar.options.borderWidth).toBe(5);
+
+    // Should work with array styles so that we can set per bar
+    chart.data.datasets[1].hoverBackgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
+    chart.data.datasets[1].hoverBorderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
+    chart.data.datasets[1].hoverBorderWidth = [2.5, 5];
+    chart.update();
+
+    meta.controller.setHoverStyle(bar, 1, 0);
+    expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
+    expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
+    expect(bar.options.borderWidth).toBe(2.5);
+  });
+
+  it('should remove a hover style from a bar', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [],
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        elements: {
+          bar: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2,
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    var bar = meta.data[0];
+    var helpers = window.Chart.helpers;
+
+    // Change default
+    chart.options.elements.bar.backgroundColor = 'rgb(128, 128, 128)';
+    chart.options.elements.bar.borderColor = 'rgb(15, 15, 15)';
+    chart.options.elements.bar.borderWidth = 3.14;
+
+    chart.update();
+    expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
+    expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
+    expect(bar.options.borderWidth).toBe(3.14);
+    meta.controller.setHoverStyle(bar, 1, 0);
+    expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(128, 128, 128)'));
+    expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(15, 15, 15)'));
+    expect(bar.options.borderWidth).toBe(3.14);
+    meta.controller.removeHoverStyle(bar);
+    expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
+    expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
+    expect(bar.options.borderWidth).toBe(3.14);
+
+    // Should work with array styles so that we can set per bar
+    chart.data.datasets[1].backgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
+    chart.data.datasets[1].borderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
+    chart.data.datasets[1].borderWidth = [2.5, 5];
+
+    chart.update();
+    expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
+    expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
+    expect(bar.options.borderWidth).toBe(2.5);
+    meta.controller.setHoverStyle(bar, 1, 0);
+    expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(255, 255, 255)'));
+    expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(9, 9, 9)'));
+    expect(bar.options.borderWidth).toBe(2.5);
+    meta.controller.removeHoverStyle(bar);
+    expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
+    expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
+    expect(bar.options.borderWidth).toBe(2.5);
+  });
+
+  describe('Bar width', function() {
+    beforeEach(function() {
+      // 2 datasets
+      this.data = {
+        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+        datasets: [{
+          data: [10, 20, 30, 40, 50, 60, 70],
+        }, {
+          data: [10, 20, 30, 40, 50, 60, 70],
+        }]
+      };
+    });
+
+    afterEach(function() {
+      var chart = window.acquireChart(this.config);
+      var meta = chart.getDatasetMeta(0);
+      var xScale = chart.scales[meta.xAxisID];
+      var options = Chart.defaults.controllers.bar.datasets;
+
+      var categoryPercentage = options.categoryPercentage;
+      var barPercentage = options.barPercentage;
+      var stacked = xScale.options.stacked;
+
+      var totalBarWidth = 0;
+      for (var i = 0; i < chart.data.datasets.length; i++) {
+        var bars = chart.getDatasetMeta(i).data;
+        for (var j = xScale.min; j <= xScale.max; j++) {
+          totalBarWidth += bars[j].width;
+        }
+        if (stacked) {
+          break;
+        }
+      }
+
+      var actualValue = totalBarWidth;
+      var expectedValue = xScale.width * categoryPercentage * barPercentage;
+      expect(actualValue).toBeCloseToPixel(expectedValue);
+
+    });
+
+    it('should correctly set bar width when min and max option is set.', function() {
+      this.config = {
+        type: 'bar',
+        data: this.data,
+        options: {
+          scales: {
+            x: {
+              min: 'March',
+              max: 'May',
+            }
+          }
+        }
+      };
+    });
+
+    it('should correctly set bar width when scale are stacked with min and max options.', function() {
+      this.config = {
+        type: 'bar',
+        data: this.data,
+        options: {
+          scales: {
+            x: {
+              min: 'March',
+              max: 'May',
+            },
+            y: {
+              stacked: true
+            }
+          }
+        }
+      };
+    });
+  });
+
+  describe('Bar height (horizontal type)', function() {
+    beforeEach(function() {
+      // 2 datasets
+      this.data = {
+        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+        datasets: [{
+          data: [10, 20, 30, 40, 50, 60, 70],
+        }, {
+          data: [10, 20, 30, 40, 50, 60, 70],
+        }]
+      };
+    });
+
+    afterEach(function() {
+      var chart = window.acquireChart(this.config);
+      var meta = chart.getDatasetMeta(0);
+      var yScale = chart.scales[meta.yAxisID];
+
+      var config = meta.controller._config;
+      var categoryPercentage = config.categoryPercentage;
+      var barPercentage = config.barPercentage;
+      var stacked = yScale.options.stacked;
+
+      var totalBarHeight = 0;
+      for (var i = 0; i < chart.data.datasets.length; i++) {
+        var bars = chart.getDatasetMeta(i).data;
+        for (var j = yScale.min; j <= yScale.max; j++) {
+          totalBarHeight += bars[j].height;
+        }
+        if (stacked) {
+          break;
+        }
+      }
+
+      var actualValue = totalBarHeight;
+      var expectedValue = yScale.height * categoryPercentage * barPercentage;
+      expect(actualValue).toBeCloseToPixel(expectedValue);
+
+    });
+
+    it('should correctly set bar height when min and max option is set.', function() {
+      this.config = {
+        type: 'bar',
+        data: this.data,
+        options: {
+          indexAxis: 'y',
+          scales: {
+            y: {
+              min: 'March',
+              max: 'May',
+            }
+          }
+        }
+      };
+    });
+
+    it('should correctly set bar height when scale are stacked with min and max options.', function() {
+      this.config = {
+        type: 'bar',
+        data: this.data,
+        options: {
+          indexAxis: 'y',
+          scales: {
+            x: {
+              stacked: true
+            },
+            y: {
+              min: 'March',
+              max: 'May',
+            }
+          }
+        }
+      };
+    });
+  });
+
+  describe('Bar thickness with a category scale', function() {
+    [undefined, 20].forEach(function(barThickness) {
+      describe('When barThickness is ' + barThickness, function() {
+        beforeEach(function() {
+          this.chart = window.acquireChart({
+            type: 'bar',
+            data: {
+              datasets: [{
+                data: [1, 2]
+              }, {
+                data: [1, 2]
+              }],
+              labels: ['label1', 'label2', 'label3']
+            },
+            options: {
+              legend: false,
+              title: false,
+              datasets: {
+                bar: {
+                  barThickness: barThickness
+                }
+              },
+              scales: {
+                x: {
+                  id: 'x',
+                  type: 'category',
+                },
+                y: {
+                  type: 'linear',
+                }
+              }
+            }
+          });
+        });
+
+        it('should correctly set bar width', function() {
+          var chart = this.chart;
+          var expected, i, ilen, meta;
+
+          if (barThickness) {
+            expected = barThickness;
+          } else {
+            var scale = chart.scales.x;
+            var options = Chart.defaults.controllers.bar.datasets;
+            var categoryPercentage = options.categoryPercentage;
+            var barPercentage = options.barPercentage;
+            var tickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
+
+            expected = tickInterval * categoryPercentage / 2 * barPercentage;
+          }
+
+          for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+            meta = chart.getDatasetMeta(i);
+            expect(meta.data[0].width).toBeCloseToPixel(expected);
+            expect(meta.data[1].width).toBeCloseToPixel(expected);
+          }
+        });
+
+        it('should correctly set bar width if maxBarThickness is specified', function() {
+          var chart = this.chart;
+          var i, ilen, meta;
+
+          chart.data.datasets[0].maxBarThickness = 10;
+          chart.data.datasets[1].maxBarThickness = 10;
+          chart.update();
+
+          for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+            meta = chart.getDatasetMeta(i);
+            expect(meta.data[0].width).toBeCloseToPixel(10);
+            expect(meta.data[1].width).toBeCloseToPixel(10);
+          }
+        });
+      });
+    });
+  });
+
+  it('minBarLength settings should be used on Y axis on bar chart', function() {
+    var minBarLength = 4;
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          minBarLength: minBarLength,
+          data: [0.05, -0.05, 10, 15, 20, 25, 30, 35]
+        }]
+      }
+    });
+
+    var data = chart.getDatasetMeta(0).data;
+
+    expect(data[0].base - minBarLength).toEqual(data[0].y);
+    expect(data[1].base + minBarLength).toEqual(data[1].y);
+  });
+
+  it('minBarLength settings should be used on X axis on horizontal bar chart', function() {
+    var minBarLength = 4;
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          indexAxis: 'y',
+          minBarLength: minBarLength,
+          data: [0.05, -0.05, 10, 15, 20, 25, 30, 35]
+        }]
+      }
+    });
+
+    var data = chart.getDatasetMeta(0).data;
+
+    expect(data[0].base + minBarLength).toEqual(data[0].x);
+    expect(data[1].base - minBarLength).toEqual(data[1].x);
+  });
+
+  it('should respect the data visibility settings', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 2, 3, 4]
+        }],
+        labels: ['A', 'B', 'C', 'D']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false,
+          }
+        }
+      }
+    });
+
+    var data = chart.getDatasetMeta(0).data;
+    expect(data[0].base).toBeCloseToPixel(512);
+    expect(data[0].y).toBeCloseToPixel(384);
+
+    chart.toggleDataVisibility(0);
+    chart.update();
+
+    data = chart.getDatasetMeta(0).data;
+    expect(data[0].base).toBeCloseToPixel(512);
+    expect(data[0].y).toBeCloseToPixel(512);
+  });
+
+  describe('Float bar', function() {
+    it('Should return correct values from getMinMax', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          labels: ['a'],
+          datasets: [{
+            data: [[10, -10]]
+          }]
+        }
+      });
+
+      expect(chart.scales.y.getMinMax()).toEqual({min: -10, max: 10});
+    });
+  });
 });
index 8a886dbca94bf6cd25ad52d7a42121bf201082a0..0a498bce665160be9a020eca6858cf2d9d0ad2bf 100644 (file)
 describe('Chart.controllers.bubble', function() {
-       describe('auto', jasmine.fixture.specs('controller.bubble'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.bubble).toBe('function');
-       });
-
-       it('should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.type).toBe('bubble');
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(0);
-               expect(meta.data).toEqual([]);
-
-               meta.controller.updateIndex(1);
-               expect(meta.controller.index).toBe(1);
-       });
-
-       it('should use the first scale IDs if the dataset does not specify them', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }]
-                       },
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.xAxisID).toBe('x');
-               expect(meta.yAxisID).toBe('y');
-       });
-
-       it('should create point elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4]
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(4); // 4 points created
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
-       });
-
-       it('should draw all elements', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4]
-                               }]
-                       },
-                       options: {
-                               animation: false,
-                               showLine: true
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should update elements when modifying style', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: [{
-                                               x: 10,
-                                               y: 10,
-                                               r: 5
-                                       }, {
-                                               x: -15,
-                                               y: -10,
-                                               r: 1
-                                       }, {
-                                               x: 0,
-                                               y: -9,
-                                               r: 2
-                                       }, {
-                                               x: -4,
-                                               y: 10,
-                                               r: 1
-                                       }]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               display: false
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               display: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               [
-                       {r: 5, x: 0, y: 0},
-                       {r: 1, x: 171, y: 512},
-                       {r: 2, x: 341, y: 486},
-                       {r: 1, x: 512, y: 0}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: Chart.defaults.backgroundColor,
-                               borderColor: Chart.defaults.borderColor,
-                               borderWidth: 1,
-                               hitRadius: 1,
-                               radius: expected.r
-                       }));
-               });
-
-               // Use dataset level styles for lines & points
-               chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
-               chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
-               chart.data.datasets[0].borderWidth = 0.55;
-
-               // point styles
-               chart.data.datasets[0].radius = 22;
-               chart.data.datasets[0].hitRadius = 3.3;
-
-               chart.update();
-
-               for (var i = 0; i < 4; ++i) {
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(98, 98, 98)',
-                               borderColor: 'rgb(8, 8, 8)',
-                               borderWidth: 0.55,
-                               hitRadius: 3.3
-                       }));
-               }
-       });
-
-       it('should handle number of data point changes in update', function() {
-               var chart = window.acquireChart({
-                       type: 'bubble',
-                       data: {
-                               datasets: [{
-                                       data: [{
-                                               x: 10,
-                                               y: 10,
-                                               r: 5
-                                       }, {
-                                               x: -15,
-                                               y: -10,
-                                               r: 1
-                                       }, {
-                                               x: 0,
-                                               y: -9,
-                                               r: 2
-                                       }, {
-                                               x: -4,
-                                               y: 10,
-                                               r: 1
-                                       }]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(4);
-
-               chart.data.datasets[0].data = [{
-                       x: 1,
-                       y: 1,
-                       r: 10
-               }, {
-                       x: 10,
-                       y: 5,
-                       r: 2
-               }]; // remove 2 items
-
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-
-               chart.data.datasets[0].data = [{
-                       x: 10,
-                       y: 10,
-                       r: 5
-               }, {
-                       x: -15,
-                       y: -10,
-                       r: 1
-               }, {
-                       x: 0,
-                       y: -9,
-                       r: 2
-               }, {
-                       x: -4,
-                       y: 10,
-                       r: 1
-               }, {
-                       x: -5,
-                       y: 0,
-                       r: 3
-               }]; // add 3 items
-
-               chart.update();
-
-               expect(meta.data.length).toBe(5);
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[4] instanceof Chart.elements.PointElement).toBe(true);
-       });
-
-       describe('Interactions', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'bubble',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3', 'label4'],
-                                       datasets: [{
-                                               data: [{
-                                                       x: 5,
-                                                       y: 5,
-                                                       r: 20
-                                               }, {
-                                                       x: -15,
-                                                       y: -10,
-                                                       r: 15
-                                               }, {
-                                                       x: 15,
-                                                       y: 10,
-                                                       r: 10
-                                               }, {
-                                                       x: -15,
-                                                       y: 10,
-                                                       r: 5
-                                               }]
-                                       }]
-                               },
-                               options: {
-                                       elements: {
-                                               point: {
-                                                       backgroundColor: 'rgb(100, 150, 200)',
-                                                       borderColor: 'rgb(50, 100, 150)',
-                                                       borderWidth: 2,
-                                                       radius: 3
-                                               }
-                                       }
-                               }
-                       });
-               });
-
-               it ('should handle default hover styles', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('#3187DD');
-                               expect(point.options.borderColor).toBe('#175A9D');
-                               expect(point.options.borderWidth).toBe(1);
-                               expect(point.options.radius).toBe(20 + 4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(20);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(20 + 4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(20);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via element options', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.options.elements.point, {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(20 + 4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(20);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('controller.bubble'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.bubble).toBe('function');
+  });
+
+  it('should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: []
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.type).toBe('bubble');
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(0);
+    expect(meta.data).toEqual([]);
+
+    meta.controller.updateIndex(1);
+    expect(meta.controller.index).toBe(1);
+  });
+
+  it('should use the first scale IDs if the dataset does not specify them', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: []
+        }]
+      },
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.xAxisID).toBe('x');
+    expect(meta.yAxisID).toBe('y');
+  });
+
+  it('should create point elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4]
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(4); // 4 points created
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
+  });
+
+  it('should draw all elements', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4]
+        }]
+      },
+      options: {
+        animation: false,
+        showLine: true
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should update elements when modifying style', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: [{
+            x: 10,
+            y: 10,
+            r: 5
+          }, {
+            x: -15,
+            y: -10,
+            r: 1
+          }, {
+            x: 0,
+            y: -9,
+            r: 2
+          }, {
+            x: -4,
+            y: 10,
+            r: 1
+          }]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            type: 'category',
+            display: false
+          },
+          y: {
+            type: 'linear',
+            display: false
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    [
+      {r: 5, x: 0, y: 0},
+      {r: 1, x: 171, y: 512},
+      {r: 2, x: 341, y: 486},
+      {r: 1, x: 512, y: 0}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: Chart.defaults.backgroundColor,
+        borderColor: Chart.defaults.borderColor,
+        borderWidth: 1,
+        hitRadius: 1,
+        radius: expected.r
+      }));
+    });
+
+    // Use dataset level styles for lines & points
+    chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
+    chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
+    chart.data.datasets[0].borderWidth = 0.55;
+
+    // point styles
+    chart.data.datasets[0].radius = 22;
+    chart.data.datasets[0].hitRadius = 3.3;
+
+    chart.update();
+
+    for (var i = 0; i < 4; ++i) {
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(98, 98, 98)',
+        borderColor: 'rgb(8, 8, 8)',
+        borderWidth: 0.55,
+        hitRadius: 3.3
+      }));
+    }
+  });
+
+  it('should handle number of data point changes in update', function() {
+    var chart = window.acquireChart({
+      type: 'bubble',
+      data: {
+        datasets: [{
+          data: [{
+            x: 10,
+            y: 10,
+            r: 5
+          }, {
+            x: -15,
+            y: -10,
+            r: 1
+          }, {
+            x: 0,
+            y: -9,
+            r: 2
+          }, {
+            x: -4,
+            y: 10,
+            r: 1
+          }]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(4);
+
+    chart.data.datasets[0].data = [{
+      x: 1,
+      y: 1,
+      r: 10
+    }, {
+      x: 10,
+      y: 5,
+      r: 2
+    }]; // remove 2 items
+
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+
+    chart.data.datasets[0].data = [{
+      x: 10,
+      y: 10,
+      r: 5
+    }, {
+      x: -15,
+      y: -10,
+      r: 1
+    }, {
+      x: 0,
+      y: -9,
+      r: 2
+    }, {
+      x: -4,
+      y: 10,
+      r: 1
+    }, {
+      x: -5,
+      y: 0,
+      r: 3
+    }]; // add 3 items
+
+    chart.update();
+
+    expect(meta.data.length).toBe(5);
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[4] instanceof Chart.elements.PointElement).toBe(true);
+  });
+
+  describe('Interactions', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'bubble',
+        data: {
+          labels: ['label1', 'label2', 'label3', 'label4'],
+          datasets: [{
+            data: [{
+              x: 5,
+              y: 5,
+              r: 20
+            }, {
+              x: -15,
+              y: -10,
+              r: 15
+            }, {
+              x: 15,
+              y: 10,
+              r: 10
+            }, {
+              x: -15,
+              y: 10,
+              r: 5
+            }]
+          }]
+        },
+        options: {
+          elements: {
+            point: {
+              backgroundColor: 'rgb(100, 150, 200)',
+              borderColor: 'rgb(50, 100, 150)',
+              borderWidth: 2,
+              radius: 3
+            }
+          }
+        }
+      });
+    });
+
+    it ('should handle default hover styles', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('#3187DD');
+        expect(point.options.borderColor).toBe('#175A9D');
+        expect(point.options.borderWidth).toBe(1);
+        expect(point.options.radius).toBe(20 + 4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(20);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(20 + 4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(20);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via element options', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.options.elements.point, {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(20 + 4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(20);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
 });
index a2693cde217673af8af8c54cb7564dee44e80b15..16f0b74013790812b2423329186682d11d533446 100644 (file)
 describe('Chart.controllers.doughnut', function() {
-       describe('auto', jasmine.fixture.specs('controller.doughnut'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.doughnut).toBe('function');
-               expect(typeof Chart.controllers.pie).toBe('function');
-       });
-
-       it('should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.type).toBe('doughnut');
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(0);
-               expect(meta.data).toEqual([]);
-
-               meta.controller.updateIndex(1);
-               expect(meta.controller.index).toBe(1);
-       });
-
-       it('should create arc elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4]
-                               }],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4); // 4 arcs created
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
-       });
-
-       it ('should reset and update elements', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2, 3, 4],
-                                       hidden: true
-                               }, {
-                                       data: [5, 6, 0, 7]
-                               }, {
-                                       data: [8, 9, 10, 11]
-                               }],
-                               labels: ['label0', 'label1', 'label2', 'label3']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false,
-                               },
-                               animation: {
-                                       duration: 0,
-                                       animateRotate: true,
-                                       animateScale: false
-                               },
-                               cutoutPercentage: 50,
-                               rotation: 0,
-                               circumference: 360,
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-
-               meta.controller.reset(); // reset first
-
-               expect(meta.data.length).toBe(4);
-
-               [
-                       {c: 0},
-                       {c: 0},
-                       {c: 0},
-                       {c: 0}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(256);
-                       expect(meta.data[i].y).toBeCloseToPixel(256);
-                       expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
-                       expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
-                       expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
-                       expect(meta.data[i].startAngle).toBeCloseToPixel(Math.PI * -0.5);
-                       expect(meta.data[i].endAngle).toBeCloseToPixel(Math.PI * -0.5);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(255, 0, 0)',
-                               borderColor: 'rgb(0, 0, 255)',
-                               borderWidth: 2
-                       }));
-               });
-
-               chart.update();
-
-               [
-                       {c: 1.7453292519, s: -1.5707963267, e: 0.1745329251},
-                       {c: 2.0943951023, s: 0.1745329251, e: 2.2689280275},
-                       {c: 0, s: 2.2689280275, e: 2.2689280275},
-                       {c: 2.4434609527, s: 2.2689280275, e: 4.7123889803}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(256);
-                       expect(meta.data[i].y).toBeCloseToPixel(256);
-                       expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
-                       expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
-                       expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
-                       expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
-                       expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(255, 0, 0)',
-                               borderColor: 'rgb(0, 0, 255)',
-                               borderWidth: 2
-                       }));
-               });
-
-               // Change the amount of data and ensure that arcs are updated accordingly
-               chart.data.datasets[1].data = [1, 2]; // remove 2 elements from dataset 0
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-
-               // Add data
-               chart.data.datasets[1].data = [1, 2, 3, 4];
-               chart.update();
-
-               expect(meta.data.length).toBe(4);
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
-       });
-
-       it ('should rotate and limit circumference', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [2, 4],
-                                       hidden: true
-                               }, {
-                                       data: [1, 3]
-                               }, {
-                                       data: [1, 0]
-                               }],
-                               labels: ['label0', 'label1', 'label2']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false,
-                               },
-                               cutoutPercentage: 50,
-                               rotation: 270,
-                               circumference: 90,
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-
-               expect(meta.data.length).toBe(2);
-
-               // Only startAngle, endAngle and circumference should be different.
-               [
-                       {c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
-                       {c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(512);
-                       expect(meta.data[i].y).toBeCloseToPixel(512);
-                       expect(meta.data[i].outerRadius).toBeCloseToPixel(512);
-                       expect(meta.data[i].innerRadius).toBeCloseToPixel(384);
-                       expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
-                       expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
-                       expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
-               });
-       });
-
-       it('should treat negative values as positive', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [-1, -3]
-                               }],
-                               labels: ['label0', 'label1']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               cutoutPercentage: 50,
-                               rotation: 270,
-                               circumference: 90,
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 0, 255)',
-                                               borderWidth: 2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(2);
-
-               // Only startAngle, endAngle and circumference should be different.
-               [
-                       {c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
-                       {c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
-                       expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
-                       expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
-               });
-       });
-
-       it ('should draw all arcs', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4]
-                               }],
-                               labels: ['label0', 'label1', 'label2', 'label3']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it ('should calculate radiuses based on the border widths of the visible outermost dataset', function() {
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       data: [2, 4],
-                                       borderWidth: 4,
-                                       hidden: true
-                               }, {
-                                       data: [1, 3],
-                                       borderWidth: 8
-                               }, {
-                                       data: [1, 0],
-                                       borderWidth: 12
-                               }],
-                               labels: ['label0', 'label1']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               }
-                       }
-               });
-
-               chart.update();
-
-               var controller = chart.getDatasetMeta(0).controller;
-               expect(chart.chartArea.bottom - chart.chartArea.top).toBe(512);
-
-               expect(controller.getMaxBorderWidth()).toBe(8);
-               expect(controller.outerRadius).toBe(252);
-               expect(controller.innerRadius).toBe(189);
-
-               controller = chart.getDatasetMeta(1).controller;
-               expect(controller.getMaxBorderWidth()).toBe(8);
-               expect(controller.outerRadius).toBe(252);
-               expect(controller.innerRadius).toBe(189);
-
-               controller = chart.getDatasetMeta(2).controller;
-               expect(controller.getMaxBorderWidth()).toBe(8);
-               expect(controller.outerRadius).toBe(189);
-               expect(controller.innerRadius).toBe(126);
-       });
-
-       describe('Interactions', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'doughnut',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3', 'label4'],
-                                       datasets: [{
-                                               data: [10, 15, 0, 4]
-                                       }]
-                               },
-                               options: {
-                                       cutoutPercentage: 0,
-                                       elements: {
-                                               arc: {
-                                                       backgroundColor: 'rgb(100, 150, 200)',
-                                                       borderColor: 'rgb(50, 100, 150)',
-                                                       borderWidth: 2,
-                                               }
-                                       }
-                               }
-                       });
-               });
-
-               it ('should handle default hover styles', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('#3187DD');
-                               expect(arc.options.borderColor).toBe('#175A9D');
-                               expect(arc.options.borderWidth).toBe(2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-
-               it ('should handle hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(arc.options.borderWidth).toBe(8.4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-
-               it ('should handle hover styles defined via element options', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.options.elements.arc, {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(arc.options.borderWidth).toBe(8.4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('controller.doughnut'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.doughnut).toBe('function');
+    expect(typeof Chart.controllers.pie).toBe('function');
+  });
+
+  it('should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.type).toBe('doughnut');
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(0);
+    expect(meta.data).toEqual([]);
+
+    meta.controller.updateIndex(1);
+    expect(meta.controller.index).toBe(1);
+  });
+
+  it('should create arc elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4]
+        }],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4); // 4 arcs created
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
+  });
+
+  it ('should reset and update elements', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [1, 2, 3, 4],
+          hidden: true
+        }, {
+          data: [5, 6, 0, 7]
+        }, {
+          data: [8, 9, 10, 11]
+        }],
+        labels: ['label0', 'label1', 'label2', 'label3']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false,
+        },
+        animation: {
+          duration: 0,
+          animateRotate: true,
+          animateScale: false
+        },
+        cutoutPercentage: 50,
+        rotation: 0,
+        circumference: 360,
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+
+    meta.controller.reset(); // reset first
+
+    expect(meta.data.length).toBe(4);
+
+    [
+      {c: 0},
+      {c: 0},
+      {c: 0},
+      {c: 0}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(256);
+      expect(meta.data[i].y).toBeCloseToPixel(256);
+      expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
+      expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
+      expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
+      expect(meta.data[i].startAngle).toBeCloseToPixel(Math.PI * -0.5);
+      expect(meta.data[i].endAngle).toBeCloseToPixel(Math.PI * -0.5);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(255, 0, 0)',
+        borderColor: 'rgb(0, 0, 255)',
+        borderWidth: 2
+      }));
+    });
+
+    chart.update();
+
+    [
+      {c: 1.7453292519, s: -1.5707963267, e: 0.1745329251},
+      {c: 2.0943951023, s: 0.1745329251, e: 2.2689280275},
+      {c: 0, s: 2.2689280275, e: 2.2689280275},
+      {c: 2.4434609527, s: 2.2689280275, e: 4.7123889803}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(256);
+      expect(meta.data[i].y).toBeCloseToPixel(256);
+      expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
+      expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
+      expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
+      expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
+      expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(255, 0, 0)',
+        borderColor: 'rgb(0, 0, 255)',
+        borderWidth: 2
+      }));
+    });
+
+    // Change the amount of data and ensure that arcs are updated accordingly
+    chart.data.datasets[1].data = [1, 2]; // remove 2 elements from dataset 0
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+
+    // Add data
+    chart.data.datasets[1].data = [1, 2, 3, 4];
+    chart.update();
+
+    expect(meta.data.length).toBe(4);
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
+  });
+
+  it ('should rotate and limit circumference', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [2, 4],
+          hidden: true
+        }, {
+          data: [1, 3]
+        }, {
+          data: [1, 0]
+        }],
+        labels: ['label0', 'label1', 'label2']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false,
+        },
+        cutoutPercentage: 50,
+        rotation: 270,
+        circumference: 90,
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+
+    expect(meta.data.length).toBe(2);
+
+    // Only startAngle, endAngle and circumference should be different.
+    [
+      {c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
+      {c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(512);
+      expect(meta.data[i].y).toBeCloseToPixel(512);
+      expect(meta.data[i].outerRadius).toBeCloseToPixel(512);
+      expect(meta.data[i].innerRadius).toBeCloseToPixel(384);
+      expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
+      expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
+      expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
+    });
+  });
+
+  it('should treat negative values as positive', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [-1, -3]
+        }],
+        labels: ['label0', 'label1']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        cutoutPercentage: 50,
+        rotation: 270,
+        circumference: 90,
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 0, 255)',
+            borderWidth: 2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(2);
+
+    // Only startAngle, endAngle and circumference should be different.
+    [
+      {c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
+      {c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
+      expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
+      expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
+    });
+  });
+
+  it ('should draw all arcs', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4]
+        }],
+        labels: ['label0', 'label1', 'label2', 'label3']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it ('should calculate radiuses based on the border widths of the visible outermost dataset', function() {
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          data: [2, 4],
+          borderWidth: 4,
+          hidden: true
+        }, {
+          data: [1, 3],
+          borderWidth: 8
+        }, {
+          data: [1, 0],
+          borderWidth: 12
+        }],
+        labels: ['label0', 'label1']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        }
+      }
+    });
+
+    chart.update();
+
+    var controller = chart.getDatasetMeta(0).controller;
+    expect(chart.chartArea.bottom - chart.chartArea.top).toBe(512);
+
+    expect(controller.getMaxBorderWidth()).toBe(8);
+    expect(controller.outerRadius).toBe(252);
+    expect(controller.innerRadius).toBe(189);
+
+    controller = chart.getDatasetMeta(1).controller;
+    expect(controller.getMaxBorderWidth()).toBe(8);
+    expect(controller.outerRadius).toBe(252);
+    expect(controller.innerRadius).toBe(189);
+
+    controller = chart.getDatasetMeta(2).controller;
+    expect(controller.getMaxBorderWidth()).toBe(8);
+    expect(controller.outerRadius).toBe(189);
+    expect(controller.innerRadius).toBe(126);
+  });
+
+  describe('Interactions', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'doughnut',
+        data: {
+          labels: ['label1', 'label2', 'label3', 'label4'],
+          datasets: [{
+            data: [10, 15, 0, 4]
+          }]
+        },
+        options: {
+          cutoutPercentage: 0,
+          elements: {
+            arc: {
+              backgroundColor: 'rgb(100, 150, 200)',
+              borderColor: 'rgb(50, 100, 150)',
+              borderWidth: 2,
+            }
+          }
+        }
+      });
+    });
+
+    it ('should handle default hover styles', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('#3187DD');
+        expect(arc.options.borderColor).toBe('#175A9D');
+        expect(arc.options.borderWidth).toBe(2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+
+    it ('should handle hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(arc.options.borderWidth).toBe(8.4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+
+    it ('should handle hover styles defined via element options', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.options.elements.arc, {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(arc.options.borderWidth).toBe(8.4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+  });
 });
index afe7e9c3d7d9e08b5f3b260810c5345386c34ad8..e7bccf71e7c2cf9b02701cadcc7a28cbff6a805c 100644 (file)
 describe('Chart.controllers.line', function() {
-       describe('auto', jasmine.fixture.specs('controller.line'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.line).toBe('function');
-       });
-
-       it('should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.type).toBe('line');
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(0);
-               expect(meta.data).toEqual([]);
-
-               meta.controller.updateIndex(1);
-               expect(meta.controller.index).toBe(1);
-       });
-
-       it('Should use the first scale IDs if the dataset does not specify them', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                               labels: []
-                       },
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.xAxisID).toBe('x');
-               expect(meta.yAxisID).toBe('y');
-       });
-
-       it('Should create line elements and point elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset1'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4); // 4 points created
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.dataset instanceof Chart.elements.LineElement).toBe(true); // 1 line element
-       });
-
-       it('should draw all elements', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset1'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               spyOn(meta.dataset, 'updateControlPoints');
-               spyOn(meta.dataset, 'draw');
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.dataset.updateControlPoints.calls.count()).toBeGreaterThanOrEqual(1);
-               expect(meta.dataset.draw.calls.count()).toBe(1);
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should update elements when modifying data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset',
-                                       xAxisID: 'x',
-                                       yAxisID: 'y'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true,
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               elements: {
-                                       point: {
-                                               backgroundColor: 'red',
-                                               borderColor: 'blue',
-                                       }
-                               },
-                               scales: {
-                                       x: {
-                                               display: false
-                                       },
-                                       y: {
-                                               display: false
-                                       }
-                               }
-                       },
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4);
-
-               chart.data.datasets[0].data = [1, 2]; // remove 2 items
-               chart.data.datasets[0].borderWidth = 1;
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-               expect(meta._parsed.length).toBe(2);
-
-               [
-                       {x: 0, y: 512},
-                       {x: 171, y: 0}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'red',
-                               borderColor: 'blue',
-                       }));
-               });
-
-               chart.data.datasets[0].data = [1, 2, 3]; // add 1 items
-               chart.update();
-
-               expect(meta.data.length).toBe(3); // should add a new meta data item
-       });
-
-       it('should correctly calculate x scale for label and point', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['One'],
-                               datasets: [{
-                                       data: [1],
-                               }]
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               hover: {
-                                       mode: 'nearest',
-                                       intersect: true
-                               },
-                               scales: {
-                                       x: {
-                                               display: false,
-                                       },
-                                       y: {
-                                               display: false,
-                                               beginAtZero: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               // 1 point
-               var point = meta.data[0];
-               expect(point.x).toBeCloseToPixel(0);
-
-               // 2 points
-               chart.data.labels = ['One', 'Two'];
-               chart.data.datasets[0].data = [1, 2];
-               chart.update();
-
-               var points = meta.data;
-
-               expect(points[0].x).toBeCloseToPixel(0);
-               expect(points[1].x).toBeCloseToPixel(512);
-
-               // 3 points
-               chart.data.labels = ['One', 'Two', 'Three'];
-               chart.data.datasets[0].data = [1, 2, 3];
-               chart.update();
-
-               points = meta.data;
-
-               expect(points[0].x).toBeCloseToPixel(0);
-               expect(points[1].x).toBeCloseToPixel(256);
-               expect(points[2].x).toBeCloseToPixel(512);
-
-               // 4 points
-               chart.data.labels = ['One', 'Two', 'Three', 'Four'];
-               chart.data.datasets[0].data = [1, 2, 3, 4];
-               chart.update();
-
-               points = meta.data;
-
-               expect(points[0].x).toBeCloseToPixel(0);
-               expect(points[1].x).toBeCloseToPixel(171);
-               expect(points[2].x).toBeCloseToPixel(340);
-               expect(points[3].x).toBeCloseToPixel(512);
-       });
-
-       it('should update elements when the y scale is stacked', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, -10, 10, -10],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               display: false,
-                                       },
-                                       y: {
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {x: 0, y: 146},
-                       {x: 171, y: 439},
-                       {x: 341, y: 146},
-                       {x: 512, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {x: 0, y: 0},
-                       {x: 171, y: 73},
-                       {x: 341, y: 146},
-                       {x: 512, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-       });
-
-       it('should update elements when the y scale is stacked with multiple axes', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, -10, 10, -10],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }, {
-                                       data: [10, 10, -10, -10],
-                                       label: 'dataset3',
-                                       yAxisID: 'y2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false,
-                               },
-                               scales: {
-                                       x: {
-                                               display: false,
-                                       },
-                                       y: {
-                                               display: false,
-                                               stacked: true
-                                       },
-                                       y2: {
-                                               type: 'linear',
-                                               position: 'right',
-                                               display: false
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {x: 0, y: 146},
-                       {x: 171, y: 439},
-                       {x: 341, y: 146},
-                       {x: 512, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {x: 0, y: 0},
-                       {x: 171, y: 73},
-                       {x: 341, y: 146},
-                       {x: 512, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-       });
-
-       it('should update elements when the y scale is stacked and datasets is scatter data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [{
-                                               x: 0,
-                                               y: 10
-                                       }, {
-                                               x: 1,
-                                               y: -10
-                                       }, {
-                                               x: 2,
-                                               y: 10
-                                       }, {
-                                               x: 3,
-                                               y: -10
-                                       }],
-                                       label: 'dataset1'
-                               }, {
-                                       data: [{
-                                               x: 0,
-                                               y: 10
-                                       }, {
-                                               x: 1,
-                                               y: 15
-                                       }, {
-                                               x: 2,
-                                               y: 0
-                                       }, {
-                                               x: 3,
-                                               y: -4
-                                       }],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               display: false,
-                                       },
-                                       y: {
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {x: 0, y: 146},
-                       {x: 171, y: 439},
-                       {x: 341, y: 146},
-                       {x: 512, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {x: 0, y: 0},
-                       {x: 171, y: 73},
-                       {x: 341, y: 146},
-                       {x: 512, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-       });
-
-       it('should update elements when the y scale is stacked and data is strings', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: ['10', '-10', '10', '-10'],
-                                       label: 'dataset1'
-                               }, {
-                                       data: ['10', '15', '0', '-4'],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               scales: {
-                                       x: {
-                                               display: false,
-                                       },
-                                       y: {
-                                               display: false,
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-
-               [
-                       {x: 0, y: 146},
-                       {x: 171, y: 439},
-                       {x: 341, y: 146},
-                       {x: 512, y: 439}
-               ].forEach(function(values, i) {
-                       expect(meta0.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta0.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-               var meta1 = chart.getDatasetMeta(1);
-
-               [
-                       {x: 0, y: 0},
-                       {x: 171, y: 73},
-                       {x: 341, y: 146},
-                       {x: 512, y: 497}
-               ].forEach(function(values, i) {
-                       expect(meta1.data[i].x).toBeCloseToPixel(values.x);
-                       expect(meta1.data[i].y).toBeCloseToPixel(values.y);
-               });
-
-       });
-
-       it('should fall back to the line styles for points', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [0, 0],
-                                       label: 'dataset1',
-
-                                       // line styles
-                                       backgroundColor: 'rgb(98, 98, 98)',
-                                       borderColor: 'rgb(8, 8, 8)',
-                                       borderWidth: 0.55,
-                               }],
-                               labels: ['label1', 'label2']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.dataset.options.backgroundColor).toBe('rgb(98, 98, 98)');
-               expect(meta.dataset.options.borderColor).toBe('rgb(8, 8, 8)');
-               expect(meta.dataset.options.borderWidth).toBe(0.55);
-       });
-
-       describe('dataset global defaults', function() {
-               beforeEach(function() {
-                       this._defaults = Chart.helpers.clone(Chart.defaults.controllers.line.datasets);
-               });
-
-               afterEach(function() {
-                       Chart.defaults.controllers.line.datasets = this._defaults;
-                       delete this._defaults;
-               });
-
-               it('should utilize the dataset global default options', function() {
-                       Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
-
-                       Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
-                               spanGaps: true,
-                               tension: 0.231,
-                               backgroundColor: '#add',
-                               borderWidth: '#daa',
-                               borderColor: '#dad',
-                               borderCapStyle: 'round',
-                               borderDash: [0],
-                               borderDashOffset: 0.871,
-                               borderJoinStyle: 'miter',
-                               fill: 'start',
-                               cubicInterpolationMode: 'monotone'
-                       });
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [0, 0],
-                                               label: 'dataset1'
-                                       }],
-                                       labels: ['label1', 'label2']
-                               }
-                       });
-
-                       var options = chart.getDatasetMeta(0).dataset.options;
-
-                       expect(options.spanGaps).toBe(true);
-                       expect(options.tension).toBe(0.231);
-                       expect(options.backgroundColor).toBe('#add');
-                       expect(options.borderWidth).toBe('#daa');
-                       expect(options.borderColor).toBe('#dad');
-                       expect(options.borderCapStyle).toBe('round');
-                       expect(options.borderDash).toEqual([0]);
-                       expect(options.borderDashOffset).toBe(0.871);
-                       expect(options.borderJoinStyle).toBe('miter');
-                       expect(options.fill).toBe('start');
-                       expect(options.cubicInterpolationMode).toBe('monotone');
-               });
-
-               it('should be overriden by user-supplied values', function() {
-                       Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
-
-                       Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
-                               spanGaps: true,
-                               tension: 0.231
-                       });
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [0, 0],
-                                               label: 'dataset1',
-                                               spanGaps: true,
-                                               backgroundColor: '#dad'
-                                       }],
-                                       labels: ['label1', 'label2']
-                               },
-                               options: {
-                                       datasets: {
-                                               line: {
-                                                       tension: 0.345,
-                                                       backgroundColor: '#add'
-                                               }
-                                       }
-                               }
-                       });
-
-                       var options = chart.getDatasetMeta(0).dataset.options;
-
-                       // dataset-level option overrides global default
-                       expect(options.spanGaps).toBe(true);
-                       // chart-level default overrides global default
-                       expect(options.tension).toBe(0.345);
-                       // dataset-level option overrides chart-level default
-                       expect(options.backgroundColor).toBe('#dad');
-               });
-       });
-
-       it('should obey the chart-level dataset options', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [0, 0],
-                                       label: 'dataset1'
-                               }],
-                               labels: ['label1', 'label2']
-                       },
-                       options: {
-                               datasets: {
-                                       line: {
-                                               spanGaps: true,
-                                               tension: 0.231,
-                                               backgroundColor: '#add',
-                                               borderWidth: '#daa',
-                                               borderColor: '#dad',
-                                               borderCapStyle: 'round',
-                                               borderDash: [0],
-                                               borderDashOffset: 0.871,
-                                               borderJoinStyle: 'miter',
-                                               fill: 'start',
-                                               cubicInterpolationMode: 'monotone'
-                                       }
-                               }
-                       }
-               });
-
-               var options = chart.getDatasetMeta(0).dataset.options;
-
-               expect(options.spanGaps).toBe(true);
-               expect(options.tension).toBe(0.231);
-               expect(options.backgroundColor).toBe('#add');
-               expect(options.borderWidth).toBe('#daa');
-               expect(options.borderColor).toBe('#dad');
-               expect(options.borderCapStyle).toBe('round');
-               expect(options.borderDash).toEqual([0]);
-               expect(options.borderDashOffset).toBe(0.871);
-               expect(options.borderJoinStyle).toBe('miter');
-               expect(options.fill).toBe('start');
-               expect(options.cubicInterpolationMode).toBe('monotone');
-       });
-
-       it('should obey the dataset options', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [0, 0],
-                                       label: 'dataset1',
-                                       spanGaps: true,
-                                       tension: 0.231,
-                                       backgroundColor: '#add',
-                                       borderWidth: '#daa',
-                                       borderColor: '#dad',
-                                       borderCapStyle: 'round',
-                                       borderDash: [0],
-                                       borderDashOffset: 0.871,
-                                       borderJoinStyle: 'miter',
-                                       fill: 'start',
-                                       cubicInterpolationMode: 'monotone'
-                               }],
-                               labels: ['label1', 'label2']
-                       }
-               });
-
-               var options = chart.getDatasetMeta(0).dataset.options;
-
-               expect(options.spanGaps).toBe(true);
-               expect(options.tension).toBe(0.231);
-               expect(options.backgroundColor).toBe('#add');
-               expect(options.borderWidth).toBe('#daa');
-               expect(options.borderColor).toBe('#dad');
-               expect(options.borderCapStyle).toBe('round');
-               expect(options.borderDash).toEqual([0]);
-               expect(options.borderDashOffset).toBe(0.871);
-               expect(options.borderJoinStyle).toBe('miter');
-               expect(options.fill).toBe('start');
-               expect(options.cubicInterpolationMode).toBe('monotone');
-       });
-
-       it('should handle number of data point changes in update', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset1',
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               chart.data.datasets[0].data = [1, 2]; // remove 2 items
-               chart.update();
-               expect(meta.data.length).toBe(2);
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-
-               chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
-               chart.update();
-               expect(meta.data.length).toBe(5);
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[4] instanceof Chart.elements.PointElement).toBe(true);
-       });
-
-       describe('Interactions', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3', 'label4'],
-                                       datasets: [{
-                                               data: [10, 15, 0, -4]
-                                       }]
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       offset: true
-                                               }
-                                       },
-                                       elements: {
-                                               point: {
-                                                       backgroundColor: 'rgb(100, 150, 200)',
-                                                       borderColor: 'rgb(50, 100, 150)',
-                                                       borderWidth: 2,
-                                                       radius: 3
-                                               }
-                                       }
-                               }
-                       });
-               });
-
-               it ('should handle default hover styles', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('#3187DD');
-                               expect(point.options.borderColor).toBe('#175A9D');
-                               expect(point.options.borderWidth).toBe(1);
-                               expect(point.options.radius).toBe(4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-                                       done();
-                               });
-
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via element options', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.options.elements.point, {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-
-                                       done();
-                               });
-
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle dataset hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-                       var dataset = chart.getDatasetMeta(0).dataset;
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               backgroundColor: '#AAA',
-                               borderColor: '#BBB',
-                               borderWidth: 6,
-                               hoverBackgroundColor: '#000',
-                               hoverBorderColor: '#111',
-                               hoverBorderWidth: 12
-                       });
-
-                       chart.options.hover = {mode: 'dataset'};
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(dataset.options.backgroundColor).toBe('#000');
-                               expect(dataset.options.borderColor).toBe('#111');
-                               expect(dataset.options.borderWidth).toBe(12);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(dataset.options.backgroundColor).toBe('#AAA');
-                                       expect(dataset.options.borderColor).toBe('#BBB');
-                                       expect(dataset.options.borderWidth).toBe(6);
-
-                                       done();
-                               });
-
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
-
-       it('should allow 0 as a point border width', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset1',
-                                       pointBorderWidth: 0
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               var point = meta.data[0];
-
-               expect(point.options.borderWidth).toBe(0);
-       });
-
-       it('should allow an array as the point border width setting', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset1',
-                                       pointBorderWidth: [1, 2, 3, 4]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data[0].options.borderWidth).toBe(1);
-               expect(meta.data[1].options.borderWidth).toBe(2);
-               expect(meta.data[2].options.borderWidth).toBe(3);
-               expect(meta.data[3].options.borderWidth).toBe(4);
-       });
-
-       it('should render a million points', function() {
-               var data = [];
-               for (let x = 0; x < 1e6; x++) {
-                       data.push({x, y: Math.sin(x / 10000)});
-               }
-               function createChart() {
-                       window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data,
-                                               borderWidth: 1,
-                                               radius: 0
-                                       }],
-                               },
-                               options: {
-                                       scales: {
-                                               x: {type: 'linear'},
-                                               y: {type: 'linear'}
-                                       }
-                               }
-                       });
-               }
-               expect(createChart).not.toThrow();
-       });
+  describe('auto', jasmine.fixture.specs('controller.line'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.line).toBe('function');
+  });
+
+  it('should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.type).toBe('line');
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(0);
+    expect(meta.data).toEqual([]);
+
+    meta.controller.updateIndex(1);
+    expect(meta.controller.index).toBe(1);
+  });
+
+  it('Should use the first scale IDs if the dataset does not specify them', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: []
+        }],
+        labels: []
+      },
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.xAxisID).toBe('x');
+    expect(meta.yAxisID).toBe('y');
+  });
+
+  it('Should create line elements and point elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset1'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4); // 4 points created
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.dataset instanceof Chart.elements.LineElement).toBe(true); // 1 line element
+  });
+
+  it('should draw all elements', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset1'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    spyOn(meta.dataset, 'updateControlPoints');
+    spyOn(meta.dataset, 'draw');
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.dataset.updateControlPoints.calls.count()).toBeGreaterThanOrEqual(1);
+    expect(meta.dataset.draw.calls.count()).toBe(1);
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should update elements when modifying data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset',
+          xAxisID: 'x',
+          yAxisID: 'y'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true,
+        plugins: {
+          legend: false,
+          title: false
+        },
+        elements: {
+          point: {
+            backgroundColor: 'red',
+            borderColor: 'blue',
+          }
+        },
+        scales: {
+          x: {
+            display: false
+          },
+          y: {
+            display: false
+          }
+        }
+      },
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4);
+
+    chart.data.datasets[0].data = [1, 2]; // remove 2 items
+    chart.data.datasets[0].borderWidth = 1;
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+    expect(meta._parsed.length).toBe(2);
+
+    [
+      {x: 0, y: 512},
+      {x: 171, y: 0}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'red',
+        borderColor: 'blue',
+      }));
+    });
+
+    chart.data.datasets[0].data = [1, 2, 3]; // add 1 items
+    chart.update();
+
+    expect(meta.data.length).toBe(3); // should add a new meta data item
+  });
+
+  it('should correctly calculate x scale for label and point', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: ['One'],
+        datasets: [{
+          data: [1],
+        }]
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        hover: {
+          mode: 'nearest',
+          intersect: true
+        },
+        scales: {
+          x: {
+            display: false,
+          },
+          y: {
+            display: false,
+            beginAtZero: true
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    // 1 point
+    var point = meta.data[0];
+    expect(point.x).toBeCloseToPixel(0);
+
+    // 2 points
+    chart.data.labels = ['One', 'Two'];
+    chart.data.datasets[0].data = [1, 2];
+    chart.update();
+
+    var points = meta.data;
+
+    expect(points[0].x).toBeCloseToPixel(0);
+    expect(points[1].x).toBeCloseToPixel(512);
+
+    // 3 points
+    chart.data.labels = ['One', 'Two', 'Three'];
+    chart.data.datasets[0].data = [1, 2, 3];
+    chart.update();
+
+    points = meta.data;
+
+    expect(points[0].x).toBeCloseToPixel(0);
+    expect(points[1].x).toBeCloseToPixel(256);
+    expect(points[2].x).toBeCloseToPixel(512);
+
+    // 4 points
+    chart.data.labels = ['One', 'Two', 'Three', 'Four'];
+    chart.data.datasets[0].data = [1, 2, 3, 4];
+    chart.update();
+
+    points = meta.data;
+
+    expect(points[0].x).toBeCloseToPixel(0);
+    expect(points[1].x).toBeCloseToPixel(171);
+    expect(points[2].x).toBeCloseToPixel(340);
+    expect(points[3].x).toBeCloseToPixel(512);
+  });
+
+  it('should update elements when the y scale is stacked', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, -10, 10, -10],
+          label: 'dataset1'
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            display: false,
+          },
+          y: {
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {x: 0, y: 146},
+      {x: 171, y: 439},
+      {x: 341, y: 146},
+      {x: 512, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {x: 0, y: 0},
+      {x: 171, y: 73},
+      {x: 341, y: 146},
+      {x: 512, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+  });
+
+  it('should update elements when the y scale is stacked with multiple axes', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, -10, 10, -10],
+          label: 'dataset1'
+        }, {
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }, {
+          data: [10, 10, -10, -10],
+          label: 'dataset3',
+          yAxisID: 'y2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false,
+        },
+        scales: {
+          x: {
+            display: false,
+          },
+          y: {
+            display: false,
+            stacked: true
+          },
+          y2: {
+            type: 'linear',
+            position: 'right',
+            display: false
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {x: 0, y: 146},
+      {x: 171, y: 439},
+      {x: 341, y: 146},
+      {x: 512, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {x: 0, y: 0},
+      {x: 171, y: 73},
+      {x: 341, y: 146},
+      {x: 512, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+  });
+
+  it('should update elements when the y scale is stacked and datasets is scatter data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [{
+            x: 0,
+            y: 10
+          }, {
+            x: 1,
+            y: -10
+          }, {
+            x: 2,
+            y: 10
+          }, {
+            x: 3,
+            y: -10
+          }],
+          label: 'dataset1'
+        }, {
+          data: [{
+            x: 0,
+            y: 10
+          }, {
+            x: 1,
+            y: 15
+          }, {
+            x: 2,
+            y: 0
+          }, {
+            x: 3,
+            y: -4
+          }],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            display: false,
+          },
+          y: {
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {x: 0, y: 146},
+      {x: 171, y: 439},
+      {x: 341, y: 146},
+      {x: 512, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {x: 0, y: 0},
+      {x: 171, y: 73},
+      {x: 341, y: 146},
+      {x: 512, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+  });
+
+  it('should update elements when the y scale is stacked and data is strings', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: ['10', '-10', '10', '-10'],
+          label: 'dataset1'
+        }, {
+          data: ['10', '15', '0', '-4'],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        plugins: {
+          legend: false,
+          title: false
+        },
+        scales: {
+          x: {
+            display: false,
+          },
+          y: {
+            display: false,
+            stacked: true
+          }
+        }
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+
+    [
+      {x: 0, y: 146},
+      {x: 171, y: 439},
+      {x: 341, y: 146},
+      {x: 512, y: 439}
+    ].forEach(function(values, i) {
+      expect(meta0.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta0.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+    var meta1 = chart.getDatasetMeta(1);
+
+    [
+      {x: 0, y: 0},
+      {x: 171, y: 73},
+      {x: 341, y: 146},
+      {x: 512, y: 497}
+    ].forEach(function(values, i) {
+      expect(meta1.data[i].x).toBeCloseToPixel(values.x);
+      expect(meta1.data[i].y).toBeCloseToPixel(values.y);
+    });
+
+  });
+
+  it('should fall back to the line styles for points', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [0, 0],
+          label: 'dataset1',
+
+          // line styles
+          backgroundColor: 'rgb(98, 98, 98)',
+          borderColor: 'rgb(8, 8, 8)',
+          borderWidth: 0.55,
+        }],
+        labels: ['label1', 'label2']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.dataset.options.backgroundColor).toBe('rgb(98, 98, 98)');
+    expect(meta.dataset.options.borderColor).toBe('rgb(8, 8, 8)');
+    expect(meta.dataset.options.borderWidth).toBe(0.55);
+  });
+
+  describe('dataset global defaults', function() {
+    beforeEach(function() {
+      this._defaults = Chart.helpers.clone(Chart.defaults.controllers.line.datasets);
+    });
+
+    afterEach(function() {
+      Chart.defaults.controllers.line.datasets = this._defaults;
+      delete this._defaults;
+    });
+
+    it('should utilize the dataset global default options', function() {
+      Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
+
+      Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
+        spanGaps: true,
+        tension: 0.231,
+        backgroundColor: '#add',
+        borderWidth: '#daa',
+        borderColor: '#dad',
+        borderCapStyle: 'round',
+        borderDash: [0],
+        borderDashOffset: 0.871,
+        borderJoinStyle: 'miter',
+        fill: 'start',
+        cubicInterpolationMode: 'monotone'
+      });
+
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [0, 0],
+            label: 'dataset1'
+          }],
+          labels: ['label1', 'label2']
+        }
+      });
+
+      var options = chart.getDatasetMeta(0).dataset.options;
+
+      expect(options.spanGaps).toBe(true);
+      expect(options.tension).toBe(0.231);
+      expect(options.backgroundColor).toBe('#add');
+      expect(options.borderWidth).toBe('#daa');
+      expect(options.borderColor).toBe('#dad');
+      expect(options.borderCapStyle).toBe('round');
+      expect(options.borderDash).toEqual([0]);
+      expect(options.borderDashOffset).toBe(0.871);
+      expect(options.borderJoinStyle).toBe('miter');
+      expect(options.fill).toBe('start');
+      expect(options.cubicInterpolationMode).toBe('monotone');
+    });
+
+    it('should be overriden by user-supplied values', function() {
+      Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
+
+      Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
+        spanGaps: true,
+        tension: 0.231
+      });
+
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [0, 0],
+            label: 'dataset1',
+            spanGaps: true,
+            backgroundColor: '#dad'
+          }],
+          labels: ['label1', 'label2']
+        },
+        options: {
+          datasets: {
+            line: {
+              tension: 0.345,
+              backgroundColor: '#add'
+            }
+          }
+        }
+      });
+
+      var options = chart.getDatasetMeta(0).dataset.options;
+
+      // dataset-level option overrides global default
+      expect(options.spanGaps).toBe(true);
+      // chart-level default overrides global default
+      expect(options.tension).toBe(0.345);
+      // dataset-level option overrides chart-level default
+      expect(options.backgroundColor).toBe('#dad');
+    });
+  });
+
+  it('should obey the chart-level dataset options', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [0, 0],
+          label: 'dataset1'
+        }],
+        labels: ['label1', 'label2']
+      },
+      options: {
+        datasets: {
+          line: {
+            spanGaps: true,
+            tension: 0.231,
+            backgroundColor: '#add',
+            borderWidth: '#daa',
+            borderColor: '#dad',
+            borderCapStyle: 'round',
+            borderDash: [0],
+            borderDashOffset: 0.871,
+            borderJoinStyle: 'miter',
+            fill: 'start',
+            cubicInterpolationMode: 'monotone'
+          }
+        }
+      }
+    });
+
+    var options = chart.getDatasetMeta(0).dataset.options;
+
+    expect(options.spanGaps).toBe(true);
+    expect(options.tension).toBe(0.231);
+    expect(options.backgroundColor).toBe('#add');
+    expect(options.borderWidth).toBe('#daa');
+    expect(options.borderColor).toBe('#dad');
+    expect(options.borderCapStyle).toBe('round');
+    expect(options.borderDash).toEqual([0]);
+    expect(options.borderDashOffset).toBe(0.871);
+    expect(options.borderJoinStyle).toBe('miter');
+    expect(options.fill).toBe('start');
+    expect(options.cubicInterpolationMode).toBe('monotone');
+  });
+
+  it('should obey the dataset options', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [0, 0],
+          label: 'dataset1',
+          spanGaps: true,
+          tension: 0.231,
+          backgroundColor: '#add',
+          borderWidth: '#daa',
+          borderColor: '#dad',
+          borderCapStyle: 'round',
+          borderDash: [0],
+          borderDashOffset: 0.871,
+          borderJoinStyle: 'miter',
+          fill: 'start',
+          cubicInterpolationMode: 'monotone'
+        }],
+        labels: ['label1', 'label2']
+      }
+    });
+
+    var options = chart.getDatasetMeta(0).dataset.options;
+
+    expect(options.spanGaps).toBe(true);
+    expect(options.tension).toBe(0.231);
+    expect(options.backgroundColor).toBe('#add');
+    expect(options.borderWidth).toBe('#daa');
+    expect(options.borderColor).toBe('#dad');
+    expect(options.borderCapStyle).toBe('round');
+    expect(options.borderDash).toEqual([0]);
+    expect(options.borderDashOffset).toBe(0.871);
+    expect(options.borderJoinStyle).toBe('miter');
+    expect(options.fill).toBe('start');
+    expect(options.cubicInterpolationMode).toBe('monotone');
+  });
+
+  it('should handle number of data point changes in update', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset1',
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    chart.data.datasets[0].data = [1, 2]; // remove 2 items
+    chart.update();
+    expect(meta.data.length).toBe(2);
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+
+    chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
+    chart.update();
+    expect(meta.data.length).toBe(5);
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[4] instanceof Chart.elements.PointElement).toBe(true);
+  });
+
+  describe('Interactions', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          labels: ['label1', 'label2', 'label3', 'label4'],
+          datasets: [{
+            data: [10, 15, 0, -4]
+          }]
+        },
+        options: {
+          scales: {
+            x: {
+              offset: true
+            }
+          },
+          elements: {
+            point: {
+              backgroundColor: 'rgb(100, 150, 200)',
+              borderColor: 'rgb(50, 100, 150)',
+              borderWidth: 2,
+              radius: 3
+            }
+          }
+        }
+      });
+    });
+
+    it ('should handle default hover styles', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('#3187DD');
+        expect(point.options.borderColor).toBe('#175A9D');
+        expect(point.options.borderWidth).toBe(1);
+        expect(point.options.radius).toBe(4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+          done();
+        });
+
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via element options', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.options.elements.point, {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+
+          done();
+        });
+
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle dataset hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+      var dataset = chart.getDatasetMeta(0).dataset;
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        backgroundColor: '#AAA',
+        borderColor: '#BBB',
+        borderWidth: 6,
+        hoverBackgroundColor: '#000',
+        hoverBorderColor: '#111',
+        hoverBorderWidth: 12
+      });
+
+      chart.options.hover = {mode: 'dataset'};
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(dataset.options.backgroundColor).toBe('#000');
+        expect(dataset.options.borderColor).toBe('#111');
+        expect(dataset.options.borderWidth).toBe(12);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(dataset.options.backgroundColor).toBe('#AAA');
+          expect(dataset.options.borderColor).toBe('#BBB');
+          expect(dataset.options.borderWidth).toBe(6);
+
+          done();
+        });
+
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
+
+  it('should allow 0 as a point border width', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset1',
+          pointBorderWidth: 0
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[0];
+
+    expect(point.options.borderWidth).toBe(0);
+  });
+
+  it('should allow an array as the point border width setting', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset1',
+          pointBorderWidth: [1, 2, 3, 4]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data[0].options.borderWidth).toBe(1);
+    expect(meta.data[1].options.borderWidth).toBe(2);
+    expect(meta.data[2].options.borderWidth).toBe(3);
+    expect(meta.data[3].options.borderWidth).toBe(4);
+  });
+
+  it('should render a million points', function() {
+    var data = [];
+    for (let x = 0; x < 1e6; x++) {
+      data.push({x, y: Math.sin(x / 10000)});
+    }
+    function createChart() {
+      window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data,
+            borderWidth: 1,
+            radius: 0
+          }],
+        },
+        options: {
+          scales: {
+            x: {type: 'linear'},
+            y: {type: 'linear'}
+          }
+        }
+      });
+    }
+    expect(createChart).not.toThrow();
+  });
 });
index 5afa179125c923b5776bf65fe98756492f3251cc..b5895a1b33522127d47ce576a091da29e17482df 100644 (file)
 describe('Chart.controllers.polarArea', function() {
-       describe('auto', jasmine.fixture.specs('controller.polarArea'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.polarArea).toBe('function');
-       });
-
-       it('should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.type).toEqual('polarArea');
-               expect(meta.data).toEqual([]);
-               expect(meta.hidden).toBe(null);
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(1);
-
-               meta.controller.updateIndex(0);
-               expect(meta.controller.index).toBe(0);
-       });
-
-       it('should create arc elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: [10, 15, 0, -4]}
-                               ],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.data.length).toBe(4); // 4 arcs created
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
-       });
-
-       it('should draw all elements', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should update elements when modifying data', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true,
-                               plugins: {
-                                       legend: false,
-                                       title: false
-                               },
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderWidth: 1.2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4);
-
-               [
-                       {o: 177, s: -0.5 * Math.PI, e: 0},
-                       {o: 240, s: 0, e: 0.5 * Math.PI},
-                       {o: 51, s: 0.5 * Math.PI, e: Math.PI},
-                       {o: 0, s: Math.PI, e: 1.5 * Math.PI}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(256);
-                       expect(meta.data[i].y).toBeCloseToPixel(259);
-                       expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
-                       expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
-                       expect(meta.data[i].startAngle).toBe(expected.s);
-                       expect(meta.data[i].endAngle).toBe(expected.e);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(255, 0, 0)',
-                               borderColor: 'rgb(0, 255, 0)',
-                               borderWidth: 1.2
-                       }));
-               });
-
-               // arc styles
-               chart.data.datasets[0].backgroundColor = 'rgb(128, 129, 130)';
-               chart.data.datasets[0].borderColor = 'rgb(56, 57, 58)';
-               chart.data.datasets[0].borderWidth = 1.123;
-
-               chart.update();
-
-               for (var i = 0; i < 4; ++i) {
-                       expect(meta.data[i].options.backgroundColor).toBe('rgb(128, 129, 130)');
-                       expect(meta.data[i].options.borderColor).toBe('rgb(56, 57, 58)');
-                       expect(meta.data[i].options.borderWidth).toBe(1.123);
-               }
-
-               chart.update();
-
-               expect(meta.data[0].x).toBeCloseToPixel(256);
-               expect(meta.data[0].y).toBeCloseToPixel(259);
-               expect(meta.data[0].innerRadius).toBeCloseToPixel(0);
-               expect(meta.data[0].outerRadius).toBeCloseToPixel(177);
-       });
-
-       it('should update elements with start angle from options', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true,
-                               plugins: {
-                                       legend: false,
-                                       title: false,
-                               },
-                               startAngle: 90, // default is 0
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderWidth: 1.2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4);
-
-               [
-                       {o: 177, s: 0, e: 0.5 * Math.PI},
-                       {o: 240, s: 0.5 * Math.PI, e: Math.PI},
-                       {o: 51, s: Math.PI, e: 1.5 * Math.PI},
-                       {o: 0, s: 1.5 * Math.PI, e: 2.0 * Math.PI}
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(256);
-                       expect(meta.data[i].y).toBeCloseToPixel(259);
-                       expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
-                       expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
-                       expect(meta.data[i].startAngle).toBe(expected.s);
-                       expect(meta.data[i].endAngle).toBe(expected.e);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(255, 0, 0)',
-                               borderColor: 'rgb(0, 255, 0)',
-                               borderWidth: 1.2
-                       }));
-               });
-       });
-
-       it('should handle number of data point changes in update', function() {
-               var chart = window.acquireChart({
-                       type: 'polarArea',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, -4],
-                                       label: 'dataset2'
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true,
-                               elements: {
-                                       arc: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderWidth: 1.2
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.data.length).toBe(4);
-
-               // remove 2 items
-               chart.data.labels = ['label1', 'label2'];
-               chart.data.datasets[0].data = [1, 2];
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-
-               // add 3 items
-               chart.data.labels = ['label1', 'label2', 'label3', 'label4', 'label5'];
-               chart.data.datasets[0].data = [1, 2, 3, 4, 5];
-               chart.update();
-
-               expect(meta.data.length).toBe(5);
-               expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
-               expect(meta.data[4] instanceof Chart.elements.ArcElement).toBe(true);
-       });
-
-       describe('Interactions', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'polarArea',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3', 'label4'],
-                                       datasets: [{
-                                               data: [10, 15, 0, 4]
-                                       }]
-                               },
-                               options: {
-                                       cutoutPercentage: 0,
-                                       elements: {
-                                               arc: {
-                                                       backgroundColor: 'rgb(100, 150, 200)',
-                                                       borderColor: 'rgb(50, 100, 150)',
-                                                       borderWidth: 2,
-                                               }
-                                       }
-                               }
-                       });
-               });
-
-               it ('should handle default hover styles', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('#3187DD');
-                               expect(arc.options.borderColor).toBe('#175A9D');
-                               expect(arc.options.borderWidth).toBe(2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-
-               it ('should handle hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(arc.options.borderWidth).toBe(8.4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-
-               it ('should handle hover styles defined via element options', function(done) {
-                       var chart = this.chart;
-                       var arc = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.options.elements.arc, {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(arc.options.borderWidth).toBe(8.4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(arc.options.borderWidth).toBe(2);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', arc);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', arc);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('controller.polarArea'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.polarArea).toBe('function');
+  });
+
+  it('should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [
+          {data: []},
+          {data: []}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.type).toEqual('polarArea');
+    expect(meta.data).toEqual([]);
+    expect(meta.hidden).toBe(null);
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(1);
+
+    meta.controller.updateIndex(0);
+    expect(meta.controller.index).toBe(0);
+  });
+
+  it('should create arc elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [
+          {data: []},
+          {data: [10, 15, 0, -4]}
+        ],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(1);
+    expect(meta.data.length).toBe(4); // 4 arcs created
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
+  });
+
+  it('should draw all elements', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should update elements when modifying data', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true,
+        plugins: {
+          legend: false,
+          title: false
+        },
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 255, 0)',
+            borderWidth: 1.2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4);
+
+    [
+      {o: 177, s: -0.5 * Math.PI, e: 0},
+      {o: 240, s: 0, e: 0.5 * Math.PI},
+      {o: 51, s: 0.5 * Math.PI, e: Math.PI},
+      {o: 0, s: Math.PI, e: 1.5 * Math.PI}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(256);
+      expect(meta.data[i].y).toBeCloseToPixel(259);
+      expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
+      expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
+      expect(meta.data[i].startAngle).toBe(expected.s);
+      expect(meta.data[i].endAngle).toBe(expected.e);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(255, 0, 0)',
+        borderColor: 'rgb(0, 255, 0)',
+        borderWidth: 1.2
+      }));
+    });
+
+    // arc styles
+    chart.data.datasets[0].backgroundColor = 'rgb(128, 129, 130)';
+    chart.data.datasets[0].borderColor = 'rgb(56, 57, 58)';
+    chart.data.datasets[0].borderWidth = 1.123;
+
+    chart.update();
+
+    for (var i = 0; i < 4; ++i) {
+      expect(meta.data[i].options.backgroundColor).toBe('rgb(128, 129, 130)');
+      expect(meta.data[i].options.borderColor).toBe('rgb(56, 57, 58)');
+      expect(meta.data[i].options.borderWidth).toBe(1.123);
+    }
+
+    chart.update();
+
+    expect(meta.data[0].x).toBeCloseToPixel(256);
+    expect(meta.data[0].y).toBeCloseToPixel(259);
+    expect(meta.data[0].innerRadius).toBeCloseToPixel(0);
+    expect(meta.data[0].outerRadius).toBeCloseToPixel(177);
+  });
+
+  it('should update elements with start angle from options', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true,
+        plugins: {
+          legend: false,
+          title: false,
+        },
+        startAngle: 90, // default is 0
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 255, 0)',
+            borderWidth: 1.2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4);
+
+    [
+      {o: 177, s: 0, e: 0.5 * Math.PI},
+      {o: 240, s: 0.5 * Math.PI, e: Math.PI},
+      {o: 51, s: Math.PI, e: 1.5 * Math.PI},
+      {o: 0, s: 1.5 * Math.PI, e: 2.0 * Math.PI}
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(256);
+      expect(meta.data[i].y).toBeCloseToPixel(259);
+      expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
+      expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
+      expect(meta.data[i].startAngle).toBe(expected.s);
+      expect(meta.data[i].endAngle).toBe(expected.e);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(255, 0, 0)',
+        borderColor: 'rgb(0, 255, 0)',
+        borderWidth: 1.2
+      }));
+    });
+  });
+
+  it('should handle number of data point changes in update', function() {
+    var chart = window.acquireChart({
+      type: 'polarArea',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, -4],
+          label: 'dataset2'
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true,
+        elements: {
+          arc: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderColor: 'rgb(0, 255, 0)',
+            borderWidth: 1.2
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.data.length).toBe(4);
+
+    // remove 2 items
+    chart.data.labels = ['label1', 'label2'];
+    chart.data.datasets[0].data = [1, 2];
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+
+    // add 3 items
+    chart.data.labels = ['label1', 'label2', 'label3', 'label4', 'label5'];
+    chart.data.datasets[0].data = [1, 2, 3, 4, 5];
+    chart.update();
+
+    expect(meta.data.length).toBe(5);
+    expect(meta.data[0] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.ArcElement).toBe(true);
+    expect(meta.data[4] instanceof Chart.elements.ArcElement).toBe(true);
+  });
+
+  describe('Interactions', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'polarArea',
+        data: {
+          labels: ['label1', 'label2', 'label3', 'label4'],
+          datasets: [{
+            data: [10, 15, 0, 4]
+          }]
+        },
+        options: {
+          cutoutPercentage: 0,
+          elements: {
+            arc: {
+              backgroundColor: 'rgb(100, 150, 200)',
+              borderColor: 'rgb(50, 100, 150)',
+              borderWidth: 2,
+            }
+          }
+        }
+      });
+    });
+
+    it ('should handle default hover styles', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('#3187DD');
+        expect(arc.options.borderColor).toBe('#175A9D');
+        expect(arc.options.borderWidth).toBe(2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+
+    it ('should handle hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(arc.options.borderWidth).toBe(8.4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+
+    it ('should handle hover styles defined via element options', function(done) {
+      var chart = this.chart;
+      var arc = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.options.elements.arc, {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(arc.options.borderWidth).toBe(8.4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(arc.options.borderWidth).toBe(2);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', arc);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', arc);
+    });
+  });
 });
index 9a9581fd567935780d053e242dc78d394d3c2225..c2fc1f2cdf197eb9a410745b7db801f587f5fd3d 100644 (file)
 describe('Chart.controllers.radar', function() {
-       describe('auto', jasmine.fixture.specs('controller.radar'));
-
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.radar).toBe('function');
-       });
-
-       it('Should be constructed', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.type).toBe('radar');
-               expect(meta.controller).not.toBe(undefined);
-               expect(meta.controller.index).toBe(0);
-               expect(meta.data).toEqual([]);
-
-               meta.controller.updateIndex(1);
-               expect(meta.controller.index).toBe(1);
-       });
-
-       it('Should create arc elements for each data item during initialization', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.dataset instanceof Chart.elements.LineElement).toBe(true); // line element
-               expect(meta.data.length).toBe(4); // 4 points created
-               expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
-               expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
-       });
-
-       it('should draw all elements', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               spyOn(meta.dataset, 'draw');
-               spyOn(meta.data[0], 'draw');
-               spyOn(meta.data[1], 'draw');
-               spyOn(meta.data[2], 'draw');
-               spyOn(meta.data[3], 'draw');
-
-               chart.update();
-
-               expect(meta.dataset.draw.calls.count()).toBe(1);
-               expect(meta.data[0].draw.calls.count()).toBe(1);
-               expect(meta.data[1].draw.calls.count()).toBe(1);
-               expect(meta.data[2].draw.calls.count()).toBe(1);
-               expect(meta.data[3].draw.calls.count()).toBe(1);
-       });
-
-       it('should update elements', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               showLine: true,
-                               plugins: {
-                                       legend: false,
-                                       title: false,
-                               },
-                               elements: {
-                                       line: {
-                                               backgroundColor: 'rgb(255, 0, 0)',
-                                               borderCapStyle: 'round',
-                                               borderColor: 'rgb(0, 255, 0)',
-                                               borderDash: [],
-                                               borderDashOffset: 0.1,
-                                               borderJoinStyle: 'bevel',
-                                               borderWidth: 1.2,
-                                               fill: true,
-                                               tension: 0.1,
-                                       },
-                                       point: {
-                                               backgroundColor: Chart.defaults.backgroundColor,
-                                               borderWidth: 1,
-                                               borderColor: Chart.defaults.borderColor,
-                                               hitRadius: 1,
-                                               hoverRadius: 4,
-                                               hoverBorderWidth: 1,
-                                               radius: 3,
-                                               pointStyle: 'circle'
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               meta.controller.reset(); // reset first
-
-               // Line element
-               expect(meta.dataset.options).toEqual(jasmine.objectContaining({
-                       backgroundColor: 'rgb(255, 0, 0)',
-                       borderCapStyle: 'round',
-                       borderColor: 'rgb(0, 255, 0)',
-                       borderDash: [],
-                       borderDashOffset: 0.1,
-                       borderJoinStyle: 'bevel',
-                       borderWidth: 1.2,
-                       fill: true,
-                       tension: 0.1,
-               }));
-
-               [
-                       {x: 256, y: 260},
-                       {x: 256, y: 260},
-                       {x: 256, y: 260},
-                       {x: 256, y: 260},
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: Chart.defaults.backgroundColor,
-                               borderWidth: 1,
-                               borderColor: Chart.defaults.borderColor,
-                               hitRadius: 1,
-                               radius: 3,
-                               pointStyle: 'circle',
-                       }));
-               });
-
-               // Now update controller and ensure proper updates
-               meta.controller._update();
-
-               [
-                       {x: 256, y: 120, cppx: 246, cppy: 120, cpnx: 272, cpny: 120},
-                       {x: 464, y: 260, cppx: 464, cppy: 252, cpnx: 464, cpny: 266},
-                       {x: 256, y: 260, cppx: 277, cppy: 260, cpnx: 250, cpny: 260},
-                       {x: 200, y: 260, cppx: 200, cppy: 264, cpnx: 200, cpny: 250},
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].controlPointPreviousX).toBeCloseToPixel(expected.cppx);
-                       expect(meta.data[i].controlPointPreviousY).toBeCloseToPixel(expected.cppy);
-                       expect(meta.data[i].controlPointNextX).toBeCloseToPixel(expected.cpnx);
-                       expect(meta.data[i].controlPointNextY).toBeCloseToPixel(expected.cpny);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: Chart.defaults.backgroundColor,
-                               borderWidth: 1,
-                               borderColor: Chart.defaults.borderColor,
-                               hitRadius: 1,
-                               radius: 3,
-                               pointStyle: 'circle',
-                       }));
-               });
-
-               // Use dataset level styles for lines & points
-               chart.data.datasets[0].tension = 0;
-               chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
-               chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
-               chart.data.datasets[0].borderWidth = 0.55;
-               chart.data.datasets[0].borderCapStyle = 'butt';
-               chart.data.datasets[0].borderDash = [2, 3];
-               chart.data.datasets[0].borderDashOffset = 7;
-               chart.data.datasets[0].borderJoinStyle = 'miter';
-               chart.data.datasets[0].fill = false;
-
-               // point styles
-               chart.data.datasets[0].pointRadius = 22;
-               chart.data.datasets[0].hitRadius = 3.3;
-               chart.data.datasets[0].pointBackgroundColor = 'rgb(128, 129, 130)';
-               chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
-               chart.data.datasets[0].pointBorderWidth = 1.123;
-
-               meta.controller._update();
-
-               expect(meta.dataset.options).toEqual(jasmine.objectContaining({
-                       backgroundColor: 'rgb(98, 98, 98)',
-                       borderCapStyle: 'butt',
-                       borderColor: 'rgb(8, 8, 8)',
-                       borderDash: [2, 3],
-                       borderDashOffset: 7,
-                       borderJoinStyle: 'miter',
-                       borderWidth: 0.55,
-                       fill: false,
-                       tension: 0,
-               }));
-
-               // Since tension is now 0, we don't care about the control points
-               [
-                       {x: 256, y: 120},
-                       {x: 464, y: 260},
-                       {x: 256, y: 260},
-                       {x: 200, y: 260},
-               ].forEach(function(expected, i) {
-                       expect(meta.data[i].x).toBeCloseToPixel(expected.x);
-                       expect(meta.data[i].y).toBeCloseToPixel(expected.y);
-                       expect(meta.data[i].options).toEqual(jasmine.objectContaining({
-                               backgroundColor: 'rgb(128, 129, 130)',
-                               borderWidth: 1.123,
-                               borderColor: 'rgb(56, 57, 58)',
-                               hitRadius: 3.3,
-                               radius: 22,
-                               pointStyle: 'circle'
-                       }));
-               });
-       });
-
-       describe('Interactions', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'radar',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3', 'label4'],
-                                       datasets: [{
-                                               data: [10, 15, 0, 4]
-                                       }]
-                               },
-                               options: {
-                                       elements: {
-                                               point: {
-                                                       backgroundColor: 'rgb(100, 150, 200)',
-                                                       borderColor: 'rgb(50, 100, 150)',
-                                                       borderWidth: 2,
-                                                       radius: 3
-                                               }
-                                       }
-                               }
-                       });
-               });
-
-               it ('should handle default hover styles', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('#3187DD');
-                               expect(point.options.borderColor).toBe('#175A9D');
-                               expect(point.options.borderWidth).toBe(1);
-                               expect(point.options.radius).toBe(4);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via dataset properties', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.data.datasets[0], {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should handle hover styles defined via element options', function(done) {
-                       var chart = this.chart;
-                       var point = chart.getDatasetMeta(0).data[0];
-
-                       Chart.helpers.merge(chart.options.elements.point, {
-                               hoverBackgroundColor: 'rgb(200, 100, 150)',
-                               hoverBorderColor: 'rgb(150, 50, 100)',
-                               hoverBorderWidth: 8.4,
-                               hoverRadius: 4.2
-                       });
-
-                       chart.update();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
-                               expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
-                               expect(point.options.borderWidth).toBe(8.4);
-                               expect(point.options.radius).toBe(4.2);
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
-                                       expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
-                                       expect(point.options.borderWidth).toBe(2);
-                                       expect(point.options.radius).toBe(3);
-
-                                       done();
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
-
-       it('should allow pointBorderWidth to be set to 0', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4],
-                                       pointBorderWidth: 0
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               var point = meta.data[0];
-               expect(point.options.borderWidth).toBe(0);
-       });
-
-       it('should use the pointRadius setting over the radius setting', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4],
-                                       pointRadius: 10,
-                                       radius: 15,
-                               }, {
-                                       data: [20, 20, 20, 20],
-                                       radius: 20
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       }
-               });
-
-               var meta0 = chart.getDatasetMeta(0);
-               var meta1 = chart.getDatasetMeta(1);
-               expect(meta0.data[0].options.radius).toBe(10);
-               expect(meta1.data[0].options.radius).toBe(20);
-       });
-
-       it('should return id for value scale', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 15, 0, 4],
-                                       pointBorderWidth: 0
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               scales: {
-                                       test: {
-                                               axis: 'r'
-                                       }
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.vScale.id).toBe('test');
-       });
+  describe('auto', jasmine.fixture.specs('controller.radar'));
+
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.radar).toBe('function');
+  });
+
+  it('Should be constructed', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.type).toBe('radar');
+    expect(meta.controller).not.toBe(undefined);
+    expect(meta.controller.index).toBe(0);
+    expect(meta.data).toEqual([]);
+
+    meta.controller.updateIndex(1);
+    expect(meta.controller.index).toBe(1);
+  });
+
+  it('Should create arc elements for each data item during initialization', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.dataset instanceof Chart.elements.LineElement).toBe(true); // line element
+    expect(meta.data.length).toBe(4); // 4 points created
+    expect(meta.data[0] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[1] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[2] instanceof Chart.elements.PointElement).toBe(true);
+    expect(meta.data[3] instanceof Chart.elements.PointElement).toBe(true);
+  });
+
+  it('should draw all elements', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    spyOn(meta.dataset, 'draw');
+    spyOn(meta.data[0], 'draw');
+    spyOn(meta.data[1], 'draw');
+    spyOn(meta.data[2], 'draw');
+    spyOn(meta.data[3], 'draw');
+
+    chart.update();
+
+    expect(meta.dataset.draw.calls.count()).toBe(1);
+    expect(meta.data[0].draw.calls.count()).toBe(1);
+    expect(meta.data[1].draw.calls.count()).toBe(1);
+    expect(meta.data[2].draw.calls.count()).toBe(1);
+    expect(meta.data[3].draw.calls.count()).toBe(1);
+  });
+
+  it('should update elements', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        showLine: true,
+        plugins: {
+          legend: false,
+          title: false,
+        },
+        elements: {
+          line: {
+            backgroundColor: 'rgb(255, 0, 0)',
+            borderCapStyle: 'round',
+            borderColor: 'rgb(0, 255, 0)',
+            borderDash: [],
+            borderDashOffset: 0.1,
+            borderJoinStyle: 'bevel',
+            borderWidth: 1.2,
+            fill: true,
+            tension: 0.1,
+          },
+          point: {
+            backgroundColor: Chart.defaults.backgroundColor,
+            borderWidth: 1,
+            borderColor: Chart.defaults.borderColor,
+            hitRadius: 1,
+            hoverRadius: 4,
+            hoverBorderWidth: 1,
+            radius: 3,
+            pointStyle: 'circle'
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    meta.controller.reset(); // reset first
+
+    // Line element
+    expect(meta.dataset.options).toEqual(jasmine.objectContaining({
+      backgroundColor: 'rgb(255, 0, 0)',
+      borderCapStyle: 'round',
+      borderColor: 'rgb(0, 255, 0)',
+      borderDash: [],
+      borderDashOffset: 0.1,
+      borderJoinStyle: 'bevel',
+      borderWidth: 1.2,
+      fill: true,
+      tension: 0.1,
+    }));
+
+    [
+      {x: 256, y: 260},
+      {x: 256, y: 260},
+      {x: 256, y: 260},
+      {x: 256, y: 260},
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: Chart.defaults.backgroundColor,
+        borderWidth: 1,
+        borderColor: Chart.defaults.borderColor,
+        hitRadius: 1,
+        radius: 3,
+        pointStyle: 'circle',
+      }));
+    });
+
+    // Now update controller and ensure proper updates
+    meta.controller._update();
+
+    [
+      {x: 256, y: 120, cppx: 246, cppy: 120, cpnx: 272, cpny: 120},
+      {x: 464, y: 260, cppx: 464, cppy: 252, cpnx: 464, cpny: 266},
+      {x: 256, y: 260, cppx: 277, cppy: 260, cpnx: 250, cpny: 260},
+      {x: 200, y: 260, cppx: 200, cppy: 264, cpnx: 200, cpny: 250},
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].controlPointPreviousX).toBeCloseToPixel(expected.cppx);
+      expect(meta.data[i].controlPointPreviousY).toBeCloseToPixel(expected.cppy);
+      expect(meta.data[i].controlPointNextX).toBeCloseToPixel(expected.cpnx);
+      expect(meta.data[i].controlPointNextY).toBeCloseToPixel(expected.cpny);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: Chart.defaults.backgroundColor,
+        borderWidth: 1,
+        borderColor: Chart.defaults.borderColor,
+        hitRadius: 1,
+        radius: 3,
+        pointStyle: 'circle',
+      }));
+    });
+
+    // Use dataset level styles for lines & points
+    chart.data.datasets[0].tension = 0;
+    chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
+    chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
+    chart.data.datasets[0].borderWidth = 0.55;
+    chart.data.datasets[0].borderCapStyle = 'butt';
+    chart.data.datasets[0].borderDash = [2, 3];
+    chart.data.datasets[0].borderDashOffset = 7;
+    chart.data.datasets[0].borderJoinStyle = 'miter';
+    chart.data.datasets[0].fill = false;
+
+    // point styles
+    chart.data.datasets[0].pointRadius = 22;
+    chart.data.datasets[0].hitRadius = 3.3;
+    chart.data.datasets[0].pointBackgroundColor = 'rgb(128, 129, 130)';
+    chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
+    chart.data.datasets[0].pointBorderWidth = 1.123;
+
+    meta.controller._update();
+
+    expect(meta.dataset.options).toEqual(jasmine.objectContaining({
+      backgroundColor: 'rgb(98, 98, 98)',
+      borderCapStyle: 'butt',
+      borderColor: 'rgb(8, 8, 8)',
+      borderDash: [2, 3],
+      borderDashOffset: 7,
+      borderJoinStyle: 'miter',
+      borderWidth: 0.55,
+      fill: false,
+      tension: 0,
+    }));
+
+    // Since tension is now 0, we don't care about the control points
+    [
+      {x: 256, y: 120},
+      {x: 464, y: 260},
+      {x: 256, y: 260},
+      {x: 200, y: 260},
+    ].forEach(function(expected, i) {
+      expect(meta.data[i].x).toBeCloseToPixel(expected.x);
+      expect(meta.data[i].y).toBeCloseToPixel(expected.y);
+      expect(meta.data[i].options).toEqual(jasmine.objectContaining({
+        backgroundColor: 'rgb(128, 129, 130)',
+        borderWidth: 1.123,
+        borderColor: 'rgb(56, 57, 58)',
+        hitRadius: 3.3,
+        radius: 22,
+        pointStyle: 'circle'
+      }));
+    });
+  });
+
+  describe('Interactions', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'radar',
+        data: {
+          labels: ['label1', 'label2', 'label3', 'label4'],
+          datasets: [{
+            data: [10, 15, 0, 4]
+          }]
+        },
+        options: {
+          elements: {
+            point: {
+              backgroundColor: 'rgb(100, 150, 200)',
+              borderColor: 'rgb(50, 100, 150)',
+              borderWidth: 2,
+              radius: 3
+            }
+          }
+        }
+      });
+    });
+
+    it ('should handle default hover styles', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('#3187DD');
+        expect(point.options.borderColor).toBe('#175A9D');
+        expect(point.options.borderWidth).toBe(1);
+        expect(point.options.radius).toBe(4);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via dataset properties', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.data.datasets[0], {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should handle hover styles defined via element options', function(done) {
+      var chart = this.chart;
+      var point = chart.getDatasetMeta(0).data[0];
+
+      Chart.helpers.merge(chart.options.elements.point, {
+        hoverBackgroundColor: 'rgb(200, 100, 150)',
+        hoverBorderColor: 'rgb(150, 50, 100)',
+        hoverBorderWidth: 8.4,
+        hoverRadius: 4.2
+      });
+
+      chart.update();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
+        expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
+        expect(point.options.borderWidth).toBe(8.4);
+        expect(point.options.radius).toBe(4.2);
+
+        afterEvent(chart, 'mouseout', function() {
+          expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
+          expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
+          expect(point.options.borderWidth).toBe(2);
+          expect(point.options.radius).toBe(3);
+
+          done();
+        });
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
+
+  it('should allow pointBorderWidth to be set to 0', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4],
+          pointBorderWidth: 0
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[0];
+    expect(point.options.borderWidth).toBe(0);
+  });
+
+  it('should use the pointRadius setting over the radius setting', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4],
+          pointRadius: 10,
+          radius: 15,
+        }, {
+          data: [20, 20, 20, 20],
+          radius: 20
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta0 = chart.getDatasetMeta(0);
+    var meta1 = chart.getDatasetMeta(1);
+    expect(meta0.data[0].options.radius).toBe(10);
+    expect(meta1.data[0].options.radius).toBe(20);
+  });
+
+  it('should return id for value scale', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 15, 0, 4],
+          pointBorderWidth: 0
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        scales: {
+          test: {
+            axis: 'r'
+          }
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.vScale.id).toBe('test');
+  });
 });
index b181c91c5ee069f5cdc538db1d7789c7452825fd..5f3aa27c3ddee686b2b39a26021b440d71b1060c 100644 (file)
@@ -1,74 +1,74 @@
 describe('Chart.controllers.scatter', function() {
-       describe('auto', jasmine.fixture.specs('controller.scatter'));
+  describe('auto', jasmine.fixture.specs('controller.scatter'));
 
-       it('should be registered as dataset controller', function() {
-               expect(typeof Chart.controllers.scatter).toBe('function');
-       });
+  it('should be registered as dataset controller', function() {
+    expect(typeof Chart.controllers.scatter).toBe('function');
+  });
 
-       it('should test default tooltip callbacks', function(done) {
-               var chart = window.acquireChart({
-                       type: 'scatter',
-                       data: {
-                               datasets: [{
-                                       data: [{
-                                               x: 10,
-                                               y: 15
-                                       }],
-                                       label: 'dataset1'
-                               }],
-                       },
-                       options: {}
-               });
-               var point = chart.getDatasetMeta(0).data[0];
+  it('should test default tooltip callbacks', function(done) {
+    var chart = window.acquireChart({
+      type: 'scatter',
+      data: {
+        datasets: [{
+          data: [{
+            x: 10,
+            y: 15
+          }],
+          label: 'dataset1'
+        }],
+      },
+      options: {}
+    });
+    var point = chart.getDatasetMeta(0).data[0];
 
-               afterEvent(chart, 'mousemove', function() {
-                       // Title should be empty
-                       expect(chart.tooltip.title.length).toBe(0);
-                       expect(chart.tooltip.body[0].lines).toEqual(['(10, 15)']);
+    afterEvent(chart, 'mousemove', function() {
+      // Title should be empty
+      expect(chart.tooltip.title.length).toBe(0);
+      expect(chart.tooltip.body[0].lines).toEqual(['(10, 15)']);
 
-                       done();
-               });
+      done();
+    });
 
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
 
-       it('should only show a single point in the tooltip on multiple datasets', function(done) {
-               var chart = window.acquireChart({
-                       type: 'scatter',
-                       data: {
-                               datasets: [{
-                                       data: [{
-                                               x: 10,
-                                               y: 15
-                                       },
-                                       {
-                                               x: 12,
-                                               y: 10
-                                       }],
-                                       label: 'dataset1'
-                               },
-                               {
-                                       data: [{
-                                               x: 20,
-                                               y: 10
-                                       },
-                                       {
-                                               x: 4,
-                                               y: 8
-                                       }],
-                                       label: 'dataset2'
-                               }]
-                       },
-                       options: {}
-               });
-               var point = chart.getDatasetMeta(0).data[1];
+  it('should only show a single point in the tooltip on multiple datasets', function(done) {
+    var chart = window.acquireChart({
+      type: 'scatter',
+      data: {
+        datasets: [{
+          data: [{
+            x: 10,
+            y: 15
+          },
+          {
+            x: 12,
+            y: 10
+          }],
+          label: 'dataset1'
+        },
+        {
+          data: [{
+            x: 20,
+            y: 10
+          },
+          {
+            x: 4,
+            y: 8
+          }],
+          label: 'dataset2'
+        }]
+      },
+      options: {}
+    });
+    var point = chart.getDatasetMeta(0).data[1];
 
-               afterEvent(chart, 'mousemove', function() {
-                       expect(chart.tooltip.body.length).toEqual(1);
+    afterEvent(chart, 'mousemove', function() {
+      expect(chart.tooltip.body.length).toEqual(1);
 
-                       done();
-               });
+      done();
+    });
 
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
 });
index ed566f4cbf6324163373e11f883d9fea9ee4ac9b..ab4d7e4311cf0cf30447f0fd708b3a7ef6174642 100644 (file)
@@ -1,86 +1,86 @@
 describe('Chart.Animation', function() {
-       it('should animate boolean', function() {
-               const target = {prop: false};
-               const anim = new Chart.Animation({duration: 1000}, target, 'prop', true);
-               expect(anim.active()).toBeTrue();
+  it('should animate boolean', function() {
+    const target = {prop: false};
+    const anim = new Chart.Animation({duration: 1000}, target, 'prop', true);
+    expect(anim.active()).toBeTrue();
 
-               anim.tick(anim._start + 500);
-               expect(anim.active()).toBeTrue();
-               expect(target.prop).toBeFalse();
+    anim.tick(anim._start + 500);
+    expect(anim.active()).toBeTrue();
+    expect(target.prop).toBeFalse();
 
-               anim.tick(anim._start + 501);
-               expect(anim.active()).toBeTrue();
-               expect(target.prop).toBeTrue();
+    anim.tick(anim._start + 501);
+    expect(anim.active()).toBeTrue();
+    expect(target.prop).toBeTrue();
 
-               anim.tick(anim._start - 100);
-               expect(anim.active()).toBeTrue();
-               expect(target.prop).toBeFalse();
+    anim.tick(anim._start - 100);
+    expect(anim.active()).toBeTrue();
+    expect(target.prop).toBeFalse();
 
-               anim.tick(anim._start + 1000);
-               expect(anim.active()).toBeFalse();
-               expect(target.prop).toBeTrue();
-       });
+    anim.tick(anim._start + 1000);
+    expect(anim.active()).toBeFalse();
+    expect(target.prop).toBeTrue();
+  });
 
-       describe('color', function() {
-               it('should fall back to transparent', function() {
-                       const target = {};
-                       const anim = new Chart.Animation({duration: 1000, type: 'color'}, target, 'color', 'red');
-                       anim._from = undefined;
-                       anim.tick(anim._start + 500);
-                       expect(target.color).toEqual('#FF000080');
+  describe('color', function() {
+    it('should fall back to transparent', function() {
+      const target = {};
+      const anim = new Chart.Animation({duration: 1000, type: 'color'}, target, 'color', 'red');
+      anim._from = undefined;
+      anim.tick(anim._start + 500);
+      expect(target.color).toEqual('#FF000080');
 
-                       anim._from = 'blue';
-                       anim._to = undefined;
-                       anim.tick(anim._start + 500);
-                       expect(target.color).toEqual('#0000FF80');
-               });
+      anim._from = 'blue';
+      anim._to = undefined;
+      anim.tick(anim._start + 500);
+      expect(target.color).toEqual('#0000FF80');
+    });
 
-               it('should not try to mix invalid color', function() {
-                       const target = {color: 'blue'};
-                       const anim = new Chart.Animation({duration: 1000, type: 'color'}, target, 'color', 'invalid');
-                       anim.tick(anim._start + 500);
-                       expect(target.color).toEqual('invalid');
-               });
-       });
+    it('should not try to mix invalid color', function() {
+      const target = {color: 'blue'};
+      const anim = new Chart.Animation({duration: 1000, type: 'color'}, target, 'color', 'invalid');
+      anim.tick(anim._start + 500);
+      expect(target.color).toEqual('invalid');
+    });
+  });
 
-       it('should loop', function() {
-               const target = {value: 0};
-               const anim = new Chart.Animation({duration: 100, loop: true}, target, 'value', 10);
-               anim.tick(anim._start + 50);
-               expect(target.value).toEqual(5);
-               anim.tick(anim._start + 100);
-               expect(target.value).toEqual(10);
-               anim.tick(anim._start + 150);
-               expect(target.value).toEqual(5);
-               anim.tick(anim._start + 400);
-               expect(target.value).toEqual(0);
-       });
+  it('should loop', function() {
+    const target = {value: 0};
+    const anim = new Chart.Animation({duration: 100, loop: true}, target, 'value', 10);
+    anim.tick(anim._start + 50);
+    expect(target.value).toEqual(5);
+    anim.tick(anim._start + 100);
+    expect(target.value).toEqual(10);
+    anim.tick(anim._start + 150);
+    expect(target.value).toEqual(5);
+    anim.tick(anim._start + 400);
+    expect(target.value).toEqual(0);
+  });
 
-       it('should update', function() {
-               const target = {testColor: 'transparent'};
-               const anim = new Chart.Animation({duration: 100, type: 'color'}, target, 'testColor', 'red');
+  it('should update', function() {
+    const target = {testColor: 'transparent'};
+    const anim = new Chart.Animation({duration: 100, type: 'color'}, target, 'testColor', 'red');
 
-               anim.tick(anim._start + 50);
-               expect(target.testColor).toEqual('#FF000080');
+    anim.tick(anim._start + 50);
+    expect(target.testColor).toEqual('#FF000080');
 
-               anim.update({duration: 500}, 'blue', Date.now());
-               anim.tick(anim._start + 250);
-               expect(target.testColor).toEqual('#4000BFBF');
+    anim.update({duration: 500}, 'blue', Date.now());
+    anim.tick(anim._start + 250);
+    expect(target.testColor).toEqual('#4000BFBF');
 
-               anim.tick(anim._start + 500);
-               expect(target.testColor).toEqual('blue');
-       });
+    anim.tick(anim._start + 500);
+    expect(target.testColor).toEqual('blue');
+  });
 
-       it('should not update when finished', function() {
-               const target = {testColor: 'transparent'};
-               const anim = new Chart.Animation({duration: 100, type: 'color'}, target, 'testColor', 'red');
+  it('should not update when finished', function() {
+    const target = {testColor: 'transparent'};
+    const anim = new Chart.Animation({duration: 100, type: 'color'}, target, 'testColor', 'red');
 
-               anim.tick(anim._start + 100);
-               expect(target.testColor).toEqual('red');
-               expect(anim.active()).toBeFalse();
+    anim.tick(anim._start + 100);
+    expect(target.testColor).toEqual('red');
+    expect(anim.active()).toBeFalse();
 
-               anim.update({duration: 500}, 'blue', Date.now());
-               expect(anim._duration).toEqual(100);
-               expect(anim._to).toEqual('red');
-       });
+    anim.update({duration: 500}, 'blue', Date.now());
+    expect(anim._duration).toEqual(100);
+    expect(anim._to).toEqual('red');
+  });
 });
index e82b92a73bc3b547d2379e6df57022196bdc3a70..d7b2c19390219b3fd978872a939d9858674ed954 100644 (file)
 describe('Chart.animations', function() {
-       it('should override property collection with property', function() {
-               const chart = {};
-               const anims = new Chart.Animations(chart, {
-                       collection1: {
-                               properties: ['property1', 'property2'],
-                               duration: 1000
-                       },
-                       property2: {
-                               duration: 2000
-                       }
-               });
-               expect(anims._properties.get('property1')).toEqual(jasmine.objectContaining({duration: 1000}));
-               expect(anims._properties.get('property2')).toEqual({duration: 2000});
-       });
-
-       it('should ignore duplicate definitions from collections', function() {
-               const chart = {};
-               const anims = new Chart.Animations(chart, {
-                       collection1: {
-                               properties: ['property1'],
-                               duration: 1000
-                       },
-                       collection2: {
-                               properties: ['property1', 'property2'],
-                               duration: 2000
-                       }
-               });
-               expect(anims._properties.get('property1')).toEqual(jasmine.objectContaining({duration: 1000}));
-               expect(anims._properties.get('property2')).toEqual(jasmine.objectContaining({duration: 2000}));
-       });
-
-       it('should not animate undefined options key', function() {
-               const chart = {};
-               const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
-               const target = {
-                       value: 1,
-                       options: {
-                               option: 2
-                       }
-               };
-               expect(anims.update(target, {
-                       options: undefined
-               })).toBeUndefined();
-       });
-
-       it('should assing options directly, if target does not have previous options', function() {
-               const chart = {};
-               const anims = new Chart.Animations(chart, {option: {duration: 200}});
-               const target = {};
-               expect(anims.update(target, {options: {option: 1}})).toBeUndefined();
-       });
-
-       it('should clone the target options, if those are shared and new options are not', function() {
-               const chart = {};
-               const anims = new Chart.Animations(chart, {option: {duration: 200}});
-               const options = {option: 0, $shared: true};
-               const target = {options};
-               expect(anims.update(target, {options: {option: 1}})).toBeTrue();
-               expect(target.options.$shared).not.toBeTrue();
-               expect(target.options !== options).toBeTrue();
-       });
-
-       it('should assign shared options to target after animations complete', function(done) {
-               const chart = {
-                       draw: function() {},
-                       options: {
-                               animation: {
-                                       debug: false
-                               }
-                       }
-               };
-               const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
-
-               const target = {
-                       value: 1,
-                       options: {
-                               option: 2
-                       }
-               };
-               const sharedOpts = {option: 10, $shared: true};
-
-               expect(anims.update(target, {
-                       options: sharedOpts
-               })).toBeTrue();
-
-               expect(target.options !== sharedOpts).toBeTrue();
-
-               Chart.animator.start(chart);
-
-               setTimeout(function() {
-                       expect(Chart.animator.running(chart)).toBeFalse();
-                       expect(target.options === sharedOpts).toBeTrue();
-
-                       Chart.animator.remove(chart);
-                       done();
-               }, 300);
-       });
-
-       it('should not assign shared options to target when animations are cancelled', function(done) {
-               const chart = {
-                       draw: function() {},
-                       options: {
-                               animation: {
-                                       debug: false
-                               }
-                       }
-               };
-               const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
-
-               const target = {
-                       value: 1,
-                       options: {
-                               option: 2
-                       }
-               };
-               const sharedOpts = {option: 10, $shared: true};
-
-               expect(anims.update(target, {
-                       options: sharedOpts
-               })).toBeTrue();
-
-               expect(target.options !== sharedOpts).toBeTrue();
-
-               Chart.animator.start(chart);
-
-               setTimeout(function() {
-                       expect(Chart.animator.running(chart)).toBeTrue();
-                       Chart.animator.stop(chart);
-                       expect(Chart.animator.running(chart)).toBeFalse();
-
-                       setTimeout(function() {
-                               expect(target.options === sharedOpts).toBeFalse();
-
-                               Chart.animator.remove(chart);
-                               done();
-                       }, 250);
-               }, 50);
-       });
-
-
-       it('should assign final shared options to target after animations complete', function(done) {
-               const chart = {
-                       draw: function() {},
-                       options: {
-                               animation: {
-                                       debug: false
-                               }
-                       }
-               };
-               const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
-
-               const origOpts = {option: 2};
-               const target = {
-                       value: 1,
-                       options: origOpts
-               };
-               const sharedOpts = {option: 10, $shared: true};
-               const sharedOpts2 = {option: 20, $shared: true};
-
-               expect(anims.update(target, {
-                       options: sharedOpts
-               })).toBeTrue();
-
-               expect(target.options !== sharedOpts).toBeTrue();
-
-               Chart.animator.start(chart);
-
-               setTimeout(function() {
-                       expect(Chart.animator.running(chart)).toBeTrue();
-
-                       expect(target.options === origOpts).toBeTrue();
-
-                       expect(anims.update(target, {
-                               options: sharedOpts2
-                       })).toBeUndefined();
-
-                       expect(target.options === origOpts).toBeTrue();
-
-                       setTimeout(function() {
-                               expect(target.options === sharedOpts2).toBeTrue();
-
-                               Chart.animator.remove(chart);
-                               done();
-                       }, 250);
-               }, 50);
-       });
+  it('should override property collection with property', function() {
+    const chart = {};
+    const anims = new Chart.Animations(chart, {
+      collection1: {
+        properties: ['property1', 'property2'],
+        duration: 1000
+      },
+      property2: {
+        duration: 2000
+      }
+    });
+    expect(anims._properties.get('property1')).toEqual(jasmine.objectContaining({duration: 1000}));
+    expect(anims._properties.get('property2')).toEqual({duration: 2000});
+  });
+
+  it('should ignore duplicate definitions from collections', function() {
+    const chart = {};
+    const anims = new Chart.Animations(chart, {
+      collection1: {
+        properties: ['property1'],
+        duration: 1000
+      },
+      collection2: {
+        properties: ['property1', 'property2'],
+        duration: 2000
+      }
+    });
+    expect(anims._properties.get('property1')).toEqual(jasmine.objectContaining({duration: 1000}));
+    expect(anims._properties.get('property2')).toEqual(jasmine.objectContaining({duration: 2000}));
+  });
+
+  it('should not animate undefined options key', function() {
+    const chart = {};
+    const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
+    const target = {
+      value: 1,
+      options: {
+        option: 2
+      }
+    };
+    expect(anims.update(target, {
+      options: undefined
+    })).toBeUndefined();
+  });
+
+  it('should assing options directly, if target does not have previous options', function() {
+    const chart = {};
+    const anims = new Chart.Animations(chart, {option: {duration: 200}});
+    const target = {};
+    expect(anims.update(target, {options: {option: 1}})).toBeUndefined();
+  });
+
+  it('should clone the target options, if those are shared and new options are not', function() {
+    const chart = {};
+    const anims = new Chart.Animations(chart, {option: {duration: 200}});
+    const options = {option: 0, $shared: true};
+    const target = {options};
+    expect(anims.update(target, {options: {option: 1}})).toBeTrue();
+    expect(target.options.$shared).not.toBeTrue();
+    expect(target.options !== options).toBeTrue();
+  });
+
+  it('should assign shared options to target after animations complete', function(done) {
+    const chart = {
+      draw: function() {},
+      options: {
+        animation: {
+          debug: false
+        }
+      }
+    };
+    const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
+
+    const target = {
+      value: 1,
+      options: {
+        option: 2
+      }
+    };
+    const sharedOpts = {option: 10, $shared: true};
+
+    expect(anims.update(target, {
+      options: sharedOpts
+    })).toBeTrue();
+
+    expect(target.options !== sharedOpts).toBeTrue();
+
+    Chart.animator.start(chart);
+
+    setTimeout(function() {
+      expect(Chart.animator.running(chart)).toBeFalse();
+      expect(target.options === sharedOpts).toBeTrue();
+
+      Chart.animator.remove(chart);
+      done();
+    }, 300);
+  });
+
+  it('should not assign shared options to target when animations are cancelled', function(done) {
+    const chart = {
+      draw: function() {},
+      options: {
+        animation: {
+          debug: false
+        }
+      }
+    };
+    const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
+
+    const target = {
+      value: 1,
+      options: {
+        option: 2
+      }
+    };
+    const sharedOpts = {option: 10, $shared: true};
+
+    expect(anims.update(target, {
+      options: sharedOpts
+    })).toBeTrue();
+
+    expect(target.options !== sharedOpts).toBeTrue();
+
+    Chart.animator.start(chart);
+
+    setTimeout(function() {
+      expect(Chart.animator.running(chart)).toBeTrue();
+      Chart.animator.stop(chart);
+      expect(Chart.animator.running(chart)).toBeFalse();
+
+      setTimeout(function() {
+        expect(target.options === sharedOpts).toBeFalse();
+
+        Chart.animator.remove(chart);
+        done();
+      }, 250);
+    }, 50);
+  });
+
+
+  it('should assign final shared options to target after animations complete', function(done) {
+    const chart = {
+      draw: function() {},
+      options: {
+        animation: {
+          debug: false
+        }
+      }
+    };
+    const anims = new Chart.Animations(chart, {value: {duration: 100}, option: {duration: 200}});
+
+    const origOpts = {option: 2};
+    const target = {
+      value: 1,
+      options: origOpts
+    };
+    const sharedOpts = {option: 10, $shared: true};
+    const sharedOpts2 = {option: 20, $shared: true};
+
+    expect(anims.update(target, {
+      options: sharedOpts
+    })).toBeTrue();
+
+    expect(target.options !== sharedOpts).toBeTrue();
+
+    Chart.animator.start(chart);
+
+    setTimeout(function() {
+      expect(Chart.animator.running(chart)).toBeTrue();
+
+      expect(target.options === origOpts).toBeTrue();
+
+      expect(anims.update(target, {
+        options: sharedOpts2
+      })).toBeUndefined();
+
+      expect(target.options === origOpts).toBeTrue();
+
+      setTimeout(function() {
+        expect(target.options === sharedOpts2).toBeTrue();
+
+        Chart.animator.remove(chart);
+        done();
+      }, 250);
+    }, 50);
+  });
 });
index cb05c139bf80674b0c1c4f4dea8f737d17839b39..218ff396a5ec776d75c3ae7b2964a79e8be91654 100644 (file)
@@ -1,48 +1,48 @@
 describe('Chart.animator', function() {
-       it('should fire onProgress for each draw', function(done) {
-               let count = 0;
-               let drawCount = 0;
-               const progress = (animation) => {
-                       count++;
-                       expect(animation.numSteps).toEqual(250);
-                       expect(animation.currentStep <= 250).toBeTrue();
-               };
-               acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [10, 5, 0, 25, 78, -10]}
-                               ],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       },
-                       options: {
-                               animation: {
-                                       duration: 250,
-                                       onProgress: progress,
-                                       onComplete: function() {
-                                               expect(count).toEqual(drawCount);
-                                               done();
-                                       }
-                               }
-                       },
-                       plugins: [{
-                               afterDraw() {
-                                       drawCount++;
-                               }
-                       }]
-               }, {
-                       canvas: {
-                               height: 150,
-                               width: 250
-                       },
-               });
-       });
+  it('should fire onProgress for each draw', function(done) {
+    let count = 0;
+    let drawCount = 0;
+    const progress = (animation) => {
+      count++;
+      expect(animation.numSteps).toEqual(250);
+      expect(animation.currentStep <= 250).toBeTrue();
+    };
+    acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [10, 5, 0, 25, 78, -10]}
+        ],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      },
+      options: {
+        animation: {
+          duration: 250,
+          onProgress: progress,
+          onComplete: function() {
+            expect(count).toEqual(drawCount);
+            done();
+          }
+        }
+      },
+      plugins: [{
+        afterDraw() {
+          drawCount++;
+        }
+      }]
+    }, {
+      canvas: {
+        height: 150,
+        width: 250
+      },
+    });
+  });
 
-       it('should not fail when adding no items', function() {
-               const chart = {};
-               Chart.animator.add(chart, undefined);
-               Chart.animator.add(chart, []);
-               Chart.animator.start(chart);
-               expect(Chart.animator.running(chart)).toBeFalse();
-       });
+  it('should not fail when adding no items', function() {
+    const chart = {};
+    Chart.animator.add(chart, undefined);
+    Chart.animator.add(chart, []);
+    Chart.animator.start(chart);
+    expect(Chart.animator.running(chart)).toBeFalse();
+  });
 });
index 3b6b68db6b966468084e05b348afd1e885553572..43a161c94d15db7fcce00c3cdbdba968e2e47e59 100644 (file)
 describe('Chart', function() {
 
-       // https://github.com/chartjs/Chart.js/issues/2481
-       // See global.deprecations.tests.js for backward compatibility
-       it('should be defined and prototype of chart instances', function() {
-               var chart = acquireChart({});
-               expect(Chart).toBeDefined();
-               expect(Chart instanceof Object).toBeTruthy();
-               expect(chart.constructor).toBe(Chart);
-               expect(chart instanceof Chart).toBeTruthy();
-       });
-
-       it('should throw an error if the canvas is already in use', function() {
-               var config = {
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [1, 2, 3, 4]
-                               }],
-                               labels: ['A', 'B', 'C', 'D']
-                       }
-               };
-               var chart = acquireChart(config);
-               var canvas = chart.canvas;
-
-               function createChart() {
-                       return new Chart(canvas, config);
-               }
-
-               expect(createChart).toThrow(new Error(
-                       'Canvas is already in use. ' +
+  // https://github.com/chartjs/Chart.js/issues/2481
+  // See global.deprecations.tests.js for backward compatibility
+  it('should be defined and prototype of chart instances', function() {
+    var chart = acquireChart({});
+    expect(Chart).toBeDefined();
+    expect(Chart instanceof Object).toBeTruthy();
+    expect(chart.constructor).toBe(Chart);
+    expect(chart instanceof Chart).toBeTruthy();
+  });
+
+  it('should throw an error if the canvas is already in use', function() {
+    var config = {
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [1, 2, 3, 4]
+        }],
+        labels: ['A', 'B', 'C', 'D']
+      }
+    };
+    var chart = acquireChart(config);
+    var canvas = chart.canvas;
+
+    function createChart() {
+      return new Chart(canvas, config);
+    }
+
+    expect(createChart).toThrow(new Error(
+      'Canvas is already in use. ' +
                        'Chart with ID \'' + chart.id + '\'' +
                        ' must be destroyed before the canvas can be reused.'
-               ));
-
-               chart.destroy();
-               expect(createChart).not.toThrow();
-       });
-
-       describe('config initialization', function() {
-               it('should create missing config.data properties', function() {
-                       var chart = acquireChart({});
-                       var data = chart.data;
-
-                       expect(data instanceof Object).toBeTruthy();
-                       expect(data.labels instanceof Array).toBeTruthy();
-                       expect(data.labels.length).toBe(0);
-                       expect(data.datasets instanceof Array).toBeTruthy();
-                       expect(data.datasets.length).toBe(0);
-               });
-
-               it('should not alter config.data references', function() {
-                       var ds0 = {data: [10, 11, 12, 13]};
-                       var ds1 = {data: [20, 21, 22, 23]};
-                       var datasets = [ds0, ds1];
-                       var labels = [0, 1, 2, 3];
-                       var data = {labels: labels, datasets: datasets};
-
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: data
-                       });
-
-                       expect(chart.data).toBe(data);
-                       expect(chart.data.labels).toBe(labels);
-                       expect(chart.data.datasets).toBe(datasets);
-                       expect(chart.data.datasets[0]).toBe(ds0);
-                       expect(chart.data.datasets[1]).toBe(ds1);
-                       expect(chart.data.datasets[0].data).toBe(ds0.data);
-                       expect(chart.data.datasets[1].data).toBe(ds1.data);
-               });
-
-               it('should define chart.data as an alias for config.data', function() {
-                       var config = {data: {labels: [], datasets: []}};
-                       var chart = acquireChart(config);
-
-                       expect(chart.data).toBe(config.data);
-
-                       chart.data = {labels: [1, 2, 3], datasets: [{data: [4, 5, 6]}]};
-
-                       expect(config.data).toBe(chart.data);
-                       expect(config.data.labels).toEqual([1, 2, 3]);
-                       expect(config.data.datasets[0].data).toEqual([4, 5, 6]);
-
-                       config.data = {labels: [7, 8, 9], datasets: [{data: [10, 11, 12]}]};
-
-                       expect(chart.data).toBe(config.data);
-                       expect(chart.data.labels).toEqual([7, 8, 9]);
-                       expect(chart.data.datasets[0].data).toEqual([10, 11, 12]);
-               });
-
-               it('should initialize config with default interaction options', function() {
-                       var callback = function() {};
-                       var defaults = Chart.defaults;
-                       var defaultMode = defaults.controllers.line.interaction.mode;
-
-                       defaults.hover.onHover = callback;
-                       defaults.controllers.line.spanGaps = true;
-                       defaults.controllers.line.interaction.mode = 'test';
-
-                       var chart = acquireChart({
-                               type: 'line'
-                       });
-
-                       var options = chart.options;
-                       expect(options.font.size).toBe(defaults.font.size);
-                       expect(options.showLine).toBe(defaults.controllers.line.showLine);
-                       expect(options.spanGaps).toBe(true);
-                       expect(options.hover.onHover).toBe(callback);
-                       expect(options.hover.mode).toBe('test');
-
-                       defaults.hover.onHover = null;
-                       defaults.controllers.line.spanGaps = false;
-                       defaults.controllers.line.interaction.mode = defaultMode;
-               });
-
-               it('should initialize config with default hover options', function() {
-                       var callback = function() {};
-                       var defaults = Chart.defaults;
-
-                       defaults.hover.onHover = callback;
-                       defaults.controllers.line.spanGaps = true;
-                       defaults.controllers.line.hover.mode = 'test';
-
-                       var chart = acquireChart({
-                               type: 'line'
-                       });
-
-                       var options = chart.options;
-                       expect(options.font.size).toBe(defaults.font.size);
-                       expect(options.showLine).toBe(defaults.controllers.line.showLine);
-                       expect(options.spanGaps).toBe(true);
-                       expect(options.hover.onHover).toBe(callback);
-                       expect(options.hover.mode).toBe('test');
-
-                       defaults.hover.onHover = null;
-                       defaults.controllers.line.spanGaps = false;
-                       delete defaults.controllers.line.hover.mode;
-               });
-
-               it('should override default options', function() {
-                       var callback = function() {};
-                       var defaults = Chart.defaults;
-
-                       defaults.hover.onHover = callback;
-                       defaults.controllers.line.hover.mode = 'x-axis';
-                       defaults.controllers.line.spanGaps = true;
-
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       spanGaps: false,
-                                       hover: {
-                                               mode: 'dataset',
-                                       },
-                                       plugins: {
-                                               title: {
-                                                       position: 'bottom'
-                                               }
-                                       }
-                               }
-                       });
-
-                       var options = chart.options;
-                       expect(options.showLine).toBe(defaults.showLine);
-                       expect(options.spanGaps).toBe(false);
-                       expect(options.hover.mode).toBe('dataset');
-                       expect(options.plugins.title.position).toBe('bottom');
-
-                       defaults.hover.onHover = null;
-                       delete defaults.controllers.line.hover.mode;
-                       defaults.controllers.line.spanGaps = false;
-               });
-
-               it('should override axis positions that are incorrect', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       position: 'left',
-                                               },
-                                               y: {
-                                                       position: 'bottom'
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scaleOptions = chart.options.scales;
-                       expect(scaleOptions.x.position).toBe('bottom');
-                       expect(scaleOptions.y.position).toBe('left');
-               });
-
-               it('should throw an error if the chart type is incorrect', function() {
-                       function createChart() {
-                               acquireChart({
-                                       type: 'area',
-                                       data: {
-                                               datasets: [{
-                                                       label: 'first',
-                                                       data: [10, 20]
-                                               }],
-                                               labels: ['0', '1'],
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'linear',
-                                                               position: 'left',
-                                                       },
-                                                       y: {
-                                                               type: 'category',
-                                                               position: 'bottom'
-                                                       }
-                                               }
-                                       }
-                               });
-                       }
-                       expect(createChart).toThrow(new Error('"area" is not a registered controller.'));
-               });
-
-               describe('should disable hover', function() {
-                       it('when options.hover=false', function() {
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       options: {
-                                               hover: false
-                                       }
-                               });
-                               expect(chart.options.hover).toBeFalse();
-                       });
-
-                       it('when options.interation=false and options.hover is not defined', function() {
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       options: {
-                                               interaction: false
-                                       }
-                               });
-                               expect(chart.options.hover).toBeFalse();
-                       });
-
-                       it('when options.interation=false and options.hover is defined', function() {
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       options: {
-                                               interaction: false,
-                                               hover: {mode: 'nearest'}
-                                       }
-                               });
-                               expect(chart.options.hover).toBeFalse();
-                       });
-               });
-
-               it('should activate element on hover', function(done) {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               }
-                       });
-
-                       var point = chart.getDatasetMeta(0).data[1];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point}]);
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it('should not activate elements when hover is disabled', function(done) {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       hover: false
-                               }
-                       });
-
-                       var point = chart.getDatasetMeta(0).data[1];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(chart.getActiveElements()).toEqual([]);
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
-
-       describe('when merging scale options', function() {
-               beforeEach(function() {
-                       Chart.helpers.merge(Chart.defaults.scale, {
-                               _jasmineCheckA: 'a0',
-                               _jasmineCheckB: 'b0',
-                               _jasmineCheckC: 'c0'
-                       });
-
-                       Chart.helpers.merge(Chart.defaults.scales.logarithmic, {
-                               _jasmineCheckB: 'b1',
-                               _jasmineCheckC: 'c1',
-                       });
-               });
-
-               afterEach(function() {
-                       delete Chart.defaults.scale._jasmineCheckA;
-                       delete Chart.defaults.scale._jasmineCheckB;
-                       delete Chart.defaults.scale._jasmineCheckC;
-                       delete Chart.defaults.scales.logarithmic._jasmineCheckB;
-                       delete Chart.defaults.scales.logarithmic._jasmineCheckC;
-               });
-
-               it('should default to "category" for x scales and "linear" for y scales', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               xFoo0: {},
-                                               xFoo1: {},
-                                               yBar0: {},
-                                               yBar1: {},
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.xFoo0.type).toBe('category');
-                       expect(chart.scales.xFoo1.type).toBe('category');
-                       expect(chart.scales.yBar0.type).toBe('linear');
-                       expect(chart.scales.yBar1.type).toBe('linear');
-               });
-
-               it('should correctly apply defaults on central scale', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               foo: {
-                                                       type: 'logarithmic',
-                                                       _jasmineCheckC: 'c2',
-                                                       _jasmineCheckD: 'd2'
-                                               }
-                                       }
-                               }
-                       });
-
-                       // let's check a few values from the user options and defaults
-
-                       expect(chart.scales.foo.type).toBe('logarithmic');
-                       expect(chart.scales.foo.options).toEqual(chart.options.scales.foo);
-                       expect(chart.scales.foo.options).toEqual(
-                               jasmine.objectContaining({
-                                       _jasmineCheckA: 'a0',
-                                       _jasmineCheckB: 'b1',
-                                       _jasmineCheckC: 'c2',
-                                       _jasmineCheckD: 'd2'
-                               }));
-               });
-
-               it('should correctly apply defaults on xy scales', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'logarithmic',
-                                                       _jasmineCheckC: 'c2',
-                                                       _jasmineCheckD: 'd2'
-                                               },
-                                               y: {
-                                                       type: 'time',
-                                                       _jasmineCheckC: 'c2',
-                                                       _jasmineCheckE: 'e2'
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.x.type).toBe('logarithmic');
-                       expect(chart.scales.x.options).toBe(chart.options.scales.x);
-                       expect(chart.scales.x.options).toEqual(
-                               jasmine.objectContaining({
-                                       _jasmineCheckA: 'a0',
-                                       _jasmineCheckB: 'b1',
-                                       _jasmineCheckC: 'c2',
-                                       _jasmineCheckD: 'd2'
-                               }));
-
-                       expect(chart.scales.y.type).toBe('time');
-                       expect(chart.scales.y.options).toBe(chart.options.scales.y);
-                       expect(chart.scales.y.options).toEqual(
-                               jasmine.objectContaining({
-                                       _jasmineCheckA: 'a0',
-                                       _jasmineCheckB: 'b0',
-                                       _jasmineCheckC: 'c2',
-                                       _jasmineCheckE: 'e2'
-                               }));
-               });
-
-               it('should not alter defaults when merging config', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       _jasmineCheck: 42,
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                                       _jasmineCheck: 42,
-                                               },
-                                               y: {
-                                                       type: 'category',
-                                                       _jasmineCheck: 42,
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.options._jasmineCheck).toBeDefined();
-                       expect(chart.scales.x.options._jasmineCheck).toBeDefined();
-                       expect(chart.scales.y.options._jasmineCheck).toBeDefined();
-
-                       expect(Chart.defaults.controllers.line._jasmineCheck).not.toBeDefined();
-                       expect(Chart.defaults._jasmineCheck).not.toBeDefined();
-                       expect(Chart.defaults.scales.linear._jasmineCheck).not.toBeDefined();
-                       expect(Chart.defaults.scales.category._jasmineCheck).not.toBeDefined();
-               });
-       });
-
-       describe('Updating options', function() {
-               it('update should result to same set of options as construct', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: [],
-                               options: {
-                                       animation: false,
-                                       locale: 'en-US',
-                                       responsive: false
-                               }
-                       });
-                       const options = chart.options;
-                       chart.options = {
-                               animation: false,
-                               locale: 'en-US',
-                               responsive: false
-                       };
-                       chart.update();
-                       expect(chart.options).toEqual(jasmine.objectContaining(options));
-               });
-       });
-
-       describe('config.options.responsive: true (maintainAspectRatio: false)', function() {
-               it('should fill parent width and height', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 150px; height: 245px'
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 350,
-                               rw: 300, rh: 350,
-                       });
-               });
-
-               it('should resize the canvas when parent width changes', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 350,
-                               rw: 300, rh: 350,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 455, dh: 350,
-                                       rw: 455, rh: 350,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 150, dh: 350,
-                                               rw: 150, rh: 350,
-                                       });
-
-                                       done();
-                               });
-                               wrapper.style.width = '150px';
-                       });
-                       wrapper.style.width = '455px';
-               });
-
-               it('should restore the original size when parent became invisible', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px; position: relative'
-                               }
-                       });
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 300, dh: 350,
-                                       rw: 300, rh: 350,
-                               });
-
-                               var original = chart.resize;
-                               chart.resize = function() {
-                                       fail('resize should not have been called');
-                               };
-
-                               var wrapper = chart.canvas.parentNode;
-                               wrapper.style.display = 'none';
-
-                               setTimeout(function() {
-                                       expect(wrapper.clientWidth).toEqual(0);
-                                       expect(wrapper.clientHeight).toEqual(0);
-
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 300, dh: 350,
-                                               rw: 300, rh: 350,
-                                       });
-
-                                       chart.resize = original;
-
-                                       waitForResize(chart, function() {
-                                               expect(chart).toBeChartOfSize({
-                                                       dw: 300, dh: 350,
-                                                       rw: 300, rh: 350,
-                                               });
-
-                                               done();
-                                       });
-                                       wrapper.style.display = 'block';
-                               }, 200);
-                       });
-               });
-
-               it('should resize the canvas when parent is RTL and width changes', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px; position: relative; direction: rtl'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 350,
-                               rw: 300, rh: 350,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 455, dh: 350,
-                                       rw: 455, rh: 350,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 150, dh: 350,
-                                               rw: 150, rh: 350,
-                                       });
-
-                                       done();
-                               });
-                               wrapper.style.width = '150px';
-                       });
-                       wrapper.style.width = '455px';
-               });
-
-               it('should resize the canvas when parent height changes', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 350,
-                               rw: 300, rh: 350,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 300, dh: 455,
-                                       rw: 300, rh: 455,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 300, dh: 150,
-                                               rw: 300, rh: 150,
-                                       });
-
-                                       done();
-                               });
-                               wrapper.style.height = '150px';
-                       });
-                       wrapper.style.height = '455px';
-               });
-
-               it('should not include parent padding when resizing the canvas', function(done) {
-                       var chart = acquireChart({
-                               type: 'line',
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'padding: 50px; width: 320px; height: 350px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 350,
-                               rw: 320, rh: 350,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 455, dh: 355,
-                                       rw: 455, rh: 355,
-                               });
-
-                               done();
-                       });
-                       wrapper.style.height = '355px';
-                       wrapper.style.width = '455px';
-               });
-
-               it('should resize the canvas when the canvas display style changes from "none" to "block"', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'display: none;'
-                               },
-                               wrapper: {
-                                       style: 'width: 320px; height: 350px'
-                               }
-                       });
-
-                       var canvas = chart.canvas;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 320, dh: 350,
-                                       rw: 320, rh: 350,
-                               });
-
-                               done();
-                       });
-                       canvas.style.display = 'block';
-               });
-
-               it('should resize the canvas when the wrapper display style changes from "none" to "block"', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'display: none; width: 460px; height: 380px'
-                               }
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 460, dh: 380,
-                                       rw: 460, rh: 380,
-                               });
-
-                               done();
-                       });
-                       wrapper.style.display = 'block';
-               });
-
-               // https://github.com/chartjs/Chart.js/issues/5485
-               it('should resize the canvas when the devicePixelRatio changes', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false,
-                                       devicePixelRatio: 1
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 400px; height: 200px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 400, dh: 200,
-                               rw: 400, rh: 200,
-                       });
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 400, dh: 200,
-                                       rw: 800, rh: 400,
-                               });
-
-                               done();
-                       });
-                       chart.options.devicePixelRatio = 2;
-                       chart.resize();
-               });
-
-               // https://github.com/chartjs/Chart.js/issues/3790
-               it('should resize the canvas if attached to the DOM after construction', function(done) {
-                       var canvas = document.createElement('canvas');
-                       var wrapper = document.createElement('div');
-                       var body = window.document.body;
-                       var chart = new Chart(canvas, {
-                               type: 'line',
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 0, dh: 0,
-                               rw: 0, rh: 0,
-                       });
-                       expect(chart.chartArea).toBeUndefined();
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 455, dh: 355,
-                                       rw: 455, rh: 355,
-                               });
-
-                               expect(chart.chartArea).not.toBeUndefined();
-
-                               body.removeChild(wrapper);
-                               chart.destroy();
-                               done();
-                       });
-
-                       wrapper.style.cssText = 'width: 455px; height: 355px';
-                       wrapper.appendChild(canvas);
-                       body.appendChild(wrapper);
-               });
-
-               it('should resize the canvas when attached to a different parent', function(done) {
-                       var canvas = document.createElement('canvas');
-                       var wrapper = document.createElement('div');
-                       var body = window.document.body;
-                       var chart = new Chart(canvas, {
-                               type: 'line',
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 0, dh: 0,
-                               rw: 0, rh: 0,
-                       });
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 455, dh: 355,
-                                       rw: 455, rh: 355,
-                               });
-
-                               var target = document.createElement('div');
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 640, dh: 480,
-                                               rw: 640, rh: 480,
-                                       });
-
-                                       body.removeChild(wrapper);
-                                       body.removeChild(target);
-                                       chart.destroy();
-                                       done();
-                               });
-
-                               target.style.cssText = 'width: 640px; height: 480px';
-                               target.appendChild(canvas);
-                               body.appendChild(target);
-                       });
-
-                       wrapper.style.cssText = 'width: 455px; height: 355px';
-                       wrapper.appendChild(canvas);
-                       body.appendChild(wrapper);
-               });
-
-               // https://github.com/chartjs/Chart.js/issues/3521
-               it('should resize the canvas after the wrapper has been re-attached to the DOM', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 320px; height: 350px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 350,
-                               rw: 320, rh: 350,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       var parent = wrapper.parentNode;
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 320, dh: 355,
-                                       rw: 320, rh: 355,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 455, dh: 355,
-                                               rw: 455, rh: 355,
-                                       });
-
-                                       done();
-                               });
-
-                               parent.removeChild(wrapper);
-                               wrapper.style.width = '455px';
-                               parent.appendChild(wrapper);
-                       });
-
-                       parent.removeChild(wrapper);
-                       parent.appendChild(wrapper);
-                       wrapper.style.height = '355px';
-               });
-
-               // https://github.com/chartjs/Chart.js/issues/4737
-               it('should resize the canvas when re-creating the chart', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true
-                               }
-                       }, {
-                               wrapper: {
-                                       style: 'width: 320px'
-                               }
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-
-                       waitForResize(chart, function() {
-                               var canvas = chart.canvas;
-                               expect(chart).toBeChartOfSize({
-                                       dw: 320, dh: 320,
-                                       rw: 320, rh: 320,
-                               });
-
-                               chart.destroy();
-                               chart = new Chart(canvas, {
-                                       type: 'line',
-                                       options: {
-                                               responsive: true
-                                       }
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 455, dh: 455,
-                                               rw: 455, rh: 455,
-                                       });
-
-                                       chart.destroy();
-                                       window.document.body.removeChild(wrapper);
-                                       done();
-                               });
-                               canvas.parentNode.style.width = '455px';
-                       });
-               });
-       });
-
-       describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
-               it('should resize the canvas with correct aspect ratio when parent width changes', function(done) {
-                       var chart = acquireChart({
-                               type: 'line', // AR == 2
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: true
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 150,
-                               rw: 300, rh: 150,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 450, dh: 225,
-                                       rw: 450, rh: 225,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 150, dh: 75,
-                                               rw: 150, rh: 75,
-                                       });
-
-                                       done();
-                               });
-                               wrapper.style.width = '150px';
-                       });
-                       wrapper.style.width = '450px';
-               });
-
-               it('should not resize the canvas when parent height changes', function(done) {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: true
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               },
-                               wrapper: {
-                                       style: 'width: 320px; height: 350px; position: relative'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 160,
-                               rw: 320, rh: 160,
-                       });
-
-                       var wrapper = chart.canvas.parentNode;
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 320, dh: 160,
-                                       rw: 320, rh: 160,
-                               });
-
-                               waitForResize(chart, function() {
-                                       expect(chart).toBeChartOfSize({
-                                               dw: 320, dh: 160,
-                                               rw: 320, rh: 160,
-                                       });
-
-                                       done();
-                               });
-                               wrapper.style.height = '150px';
-                       });
-                       wrapper.style.height = '455px';
-               });
-       });
-
-       describe('Retina scale (a.k.a. device pixel ratio)', function() {
-               beforeEach(function() {
-                       this.devicePixelRatio = window.devicePixelRatio;
-                       window.devicePixelRatio = 3;
-               });
-
-               afterEach(function() {
-                       window.devicePixelRatio = this.devicePixelRatio;
-               });
-
-               // see https://github.com/chartjs/Chart.js/issues/3575
-               it ('should scale the render size but not the "implicit" display size', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       width: 320,
-                                       height: 240,
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 240,
-                               rw: 960, rh: 720,
-                       });
-               });
-
-               it ('should scale the render size but not the "explicit" display size', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 320px; height: 240px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 240,
-                               rw: 960, rh: 720,
-                       });
-               });
-       });
-
-       describe('config.options.devicePixelRatio', function() {
-               beforeEach(function() {
-                       this.devicePixelRatio = window.devicePixelRatio;
-                       window.devicePixelRatio = 1;
-               });
-
-               afterEach(function() {
-                       window.devicePixelRatio = this.devicePixelRatio;
-               });
-
-               // see https://github.com/chartjs/Chart.js/issues/3575
-               it ('should scale the render size but not the "implicit" display size', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false,
-                                       devicePixelRatio: 3
-                               }
-                       }, {
-                               canvas: {
-                                       width: 320,
-                                       height: 240,
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 240,
-                               rw: 960, rh: 720,
-                       });
-               });
-
-               it ('should scale the render size but not the "explicit" display size', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false,
-                                       devicePixelRatio: 3
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 320px; height: 240px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 320, dh: 240,
-                               rw: 960, rh: 720,
-                       });
-               });
-       });
-
-       describe('controller.reset', function() {
-               it('should reset the chart elements', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 0]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               }
-                       });
-
-                       var meta = chart.getDatasetMeta(0);
-
-                       // Verify that points are at their initial correct location,
-                       // then we will reset and see that they moved
-                       expect(meta.data[0].y).toBeCloseToPixel(333);
-                       expect(meta.data[1].y).toBeCloseToPixel(183);
-                       expect(meta.data[2].y).toBeCloseToPixel(32);
-                       expect(meta.data[3].y).toBeCloseToPixel(482);
-
-                       chart.reset();
-
-                       // For a line chart, the animation state is the bottom
-                       expect(meta.data[0].y).toBeCloseToPixel(482);
-                       expect(meta.data[1].y).toBeCloseToPixel(482);
-                       expect(meta.data[2].y).toBeCloseToPixel(482);
-                       expect(meta.data[3].y).toBeCloseToPixel(482);
-               });
-       });
-
-       describe('config update', function() {
-               it ('should update options', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               }
-                       });
-
-                       chart.options = {
-                               responsive: false,
-                               scales: {
-                                       y: {
-                                               min: 0,
-                                               max: 10
-                                       }
-                               }
-                       };
-                       chart.update();
-
-                       var yScale = chart.scales.y;
-                       expect(yScale.options.min).toBe(0);
-                       expect(yScale.options.max).toBe(10);
-               });
-
-               it ('should update scales options', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               }
-                       });
-
-                       chart.options.scales.y.min = 0;
-                       chart.options.scales.y.max = 10;
-                       chart.update();
-
-                       var yScale = chart.scales.y;
-                       expect(yScale.options.min).toBe(0);
-                       expect(yScale.options.max).toBe(10);
-               });
-
-               it ('should update scales options from new object', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               }
-                       });
-
-                       var newScalesConfig = {
-                               y: {
-                                       min: 0,
-                                       max: 10
-                               }
-                       };
-                       chart.options.scales = newScalesConfig;
-
-                       chart.update();
-
-                       var yScale = chart.scales.y;
-                       expect(yScale.options.min).toBe(0);
-                       expect(yScale.options.max).toBe(10);
-               });
-
-               it ('should remove discarded scale', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true,
-                                       scales: {
-                                               y: {
-                                                       min: 0,
-                                                       max: 10
-                                               }
-                                       }
-                               }
-                       });
-
-                       var newScalesConfig = {
-                               y: {
-                                       min: 0,
-                                       max: 10
-                               }
-                       };
-                       chart.options.scales = newScalesConfig;
-
-                       chart.update();
-
-                       var yScale = chart.scales.yAxis0;
-                       expect(yScale).toBeUndefined();
-                       var newyScale = chart.scales.y;
-                       expect(newyScale.options.min).toBe(0);
-                       expect(newyScale.options.max).toBe(10);
-               });
-
-               it ('should update tooltip options', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               }
-                       });
-
-                       var newTooltipConfig = {
-                               mode: 'dataset',
-                               intersect: false
-                       };
-                       chart.options.plugins.tooltip = newTooltipConfig;
-
-                       chart.update();
-                       expect(chart.tooltip.options).toEqual(jasmine.objectContaining(newTooltipConfig));
-               });
-
-               it ('should update the tooltip on update', function(done) {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true,
-                                       tooltip: {
-                                               mode: 'nearest'
-                                       }
-                               }
-                       });
-
-                       // Trigger an event over top of a point to
-                       // put an item into the tooltip
-                       var meta = chart.getDatasetMeta(0);
-                       var point = meta.data[1];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               // Check and see if tooltip was displayed
-                               var tooltip = chart.tooltip;
-
-                               expect(chart._active[0].element).toEqual(point);
-                               expect(tooltip._active[0].element).toEqual(point);
-
-                               // Update and confirm tooltip is updated
-                               chart.update();
-                               expect(chart._active[0].element).toEqual(point);
-                               expect(tooltip._active[0].element).toEqual(point);
-
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-
-               it ('should update the metadata', function() {
-                       var cfg = {
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               type: 'line',
-                                               data: [10, 20, 30, 0]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true,
-                                       scales: {
-                                               x: {
-                                                       type: 'category'
-                                               },
-                                               y: {
-                                                       type: 'linear',
-                                                       scaleLabel: {
-                                                               display: true,
-                                                               labelString: 'Value'
-                                                       }
-                                               }
-                                       }
-                               }
-                       };
-                       var chart = acquireChart(cfg);
-                       var meta = chart.getDatasetMeta(0);
-                       expect(meta.type).toBe('line');
-
-                       // change the dataset to bar and check that meta was updated
-                       chart.config.data.datasets[0].type = 'bar';
-                       chart.update();
-                       meta = chart.getDatasetMeta(0);
-                       expect(meta.type).toBe('bar');
-               });
-       });
-
-       describe('plugin.extensions', function() {
-               var hooks = {
-                       install: ['install'],
-                       uninstall: ['uninstall'],
-                       init: [
-                               'beforeInit',
-                               'resize',
-                               'afterInit'
-                       ],
-                       start: ['start'],
-                       stop: ['stop'],
-                       update: [
-                               'beforeUpdate',
-                               'beforeLayout',
-                               'beforeDataLimits',
-                               'afterDataLimits',
-                               'beforeBuildTicks',
-                               'afterBuildTicks',
-                               'beforeDataLimits',
-                               'afterDataLimits',
-                               'beforeBuildTicks',
-                               'afterBuildTicks',
-                               'afterLayout',
-                               'beforeDatasetsUpdate',
-                               'beforeDatasetUpdate',
-                               'afterDatasetUpdate',
-                               'afterDatasetsUpdate',
-                               'afterUpdate',
-                       ],
-                       render: [
-                               'beforeRender',
-                               'beforeDraw',
-                               'beforeDatasetsDraw',
-                               'beforeDatasetDraw',
-                               'afterDatasetDraw',
-                               'afterDatasetsDraw',
-                               'beforeTooltipDraw',
-                               'afterTooltipDraw',
-                               'afterDraw',
-                               'afterRender',
-                       ],
-                       resize: [
-                               'resize'
-                       ],
-                       destroy: [
-                               'destroy'
-                       ]
-               };
-
-               it ('should notify plugin in correct order', function(done) {
-                       var plugin = this.plugin = {};
-                       var sequence = [];
-
-                       Object.keys(hooks).forEach(function(group) {
-                               hooks[group].forEach(function(name) {
-                                       plugin[name] = function() {
-                                               sequence.push(name);
-                                       };
-                               });
-                       });
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {datasets: [{}]},
-                               plugins: [plugin],
-                               options: {
-                                       responsive: true
-                               }
-                       }, {
-                               wrapper: {
-                                       style: 'width: 300px'
-                               }
-                       });
-
-                       waitForResize(chart, function() {
-                               chart.destroy();
-
-                               expect(sequence).toEqual([].concat(
-                                       hooks.install,
-                                       hooks.start,
-                                       hooks.init,
-                                       hooks.update,
-                                       hooks.render,
-                                       hooks.resize,
-                                       hooks.update,
-                                       hooks.render,
-                                       hooks.destroy,
-                                       hooks.stop,
-                                       hooks.uninstall
-                               ));
-
-                               done();
-                       });
-                       chart.canvas.parentNode.style.width = '400px';
-               });
-
-               it ('should notify initially disabled plugin in correct order', function() {
-                       var plugin = this.plugin = {id: 'plugin'};
-                       var sequence = [];
-
-                       Object.keys(hooks).forEach(function(group) {
-                               hooks[group].forEach(function(name) {
-                                       plugin[name] = function() {
-                                               sequence.push(name);
-                                       };
-                               });
-                       });
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {datasets: [{}]},
-                               plugins: [plugin],
-                               options: {
-                                       plugins: {
-                                               plugin: false
-                                       }
-                               }
-                       });
-
-                       expect(sequence).toEqual([].concat(
-                               hooks.install
-                       ));
-
-                       sequence = [];
-                       chart.options.plugins.plugin = true;
-                       chart.update();
-
-                       expect(sequence).toEqual([].concat(
-                               hooks.start,
-                               hooks.update,
-                               hooks.render
-                       ));
-
-                       sequence = [];
-                       chart.options.plugins.plugin = false;
-                       chart.update();
-
-                       expect(sequence).toEqual(hooks.stop);
-
-                       sequence = [];
-                       chart.destroy();
-
-                       expect(sequence).toEqual(hooks.uninstall);
-               });
-
-               it('should not notify before/afterDatasetDraw if dataset is hidden', function() {
-                       var sequence = [];
-                       var plugin = this.plugin = {
-                               beforeDatasetDraw: function(chart, args) {
-                                       sequence.push('before-' + args.index);
-                               },
-                               afterDatasetDraw: function(chart, args) {
-                                       sequence.push('after-' + args.index);
-                               }
-                       };
-
-                       window.acquireChart({
-                               type: 'line',
-                               data: {datasets: [{}, {hidden: true}, {}]},
-                               plugins: [plugin]
-                       });
-
-                       expect(sequence).toEqual([
-                               'before-2', 'after-2',
-                               'before-0', 'after-0'
-                       ]);
-               });
-       });
-
-       describe('metasets', function() {
-               beforeEach(function() {
-                       this.chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {label: '1', order: 2},
-                                               {label: '2', order: 1},
-                                               {label: '3', order: 4},
-                                               {label: '4', order: 3},
-                                       ]
-                               }
-                       });
-               });
-               afterEach(function() {
-                       const metasets = this.chart._metasets;
-                       expect(metasets.length).toEqual(this.chart.data.datasets.length);
-                       for (let i = 0; i < metasets.length; i++) {
-                               expect(metasets[i].index).toEqual(i);
-                               expect(metasets[i]._dataset).toEqual(this.chart.data.datasets[i]);
-                       }
-               });
-               it('should build metasets array in order', function() {
-                       const metasets = this.chart._metasets;
-                       expect(metasets[0].order).toEqual(2);
-                       expect(metasets[1].order).toEqual(1);
-                       expect(metasets[2].order).toEqual(4);
-                       expect(metasets[3].order).toEqual(3);
-               });
-               it('should build sorted metasets array in correct order', function() {
-                       const metasets = this.chart._sortedMetasets;
-                       expect(metasets[0].order).toEqual(1);
-                       expect(metasets[1].order).toEqual(2);
-                       expect(metasets[2].order).toEqual(3);
-                       expect(metasets[3].order).toEqual(4);
-               });
-               it('should be moved when datasets are removed from begining', function() {
-                       this.chart.data.datasets.splice(0, 2);
-                       this.chart.update();
-                       const metasets = this.chart._metasets;
-                       expect(metasets[0].order).toEqual(4);
-                       expect(metasets[1].order).toEqual(3);
-               });
-               it('should be moved when datasets are removed from middle', function() {
-                       this.chart.data.datasets.splice(1, 2);
-                       this.chart.update();
-                       const metasets = this.chart._metasets;
-                       expect(metasets[0].order).toEqual(2);
-                       expect(metasets[1].order).toEqual(3);
-               });
-               it('should be moved when datasets are inserted', function() {
-                       this.chart.data.datasets.splice(1, 0, {label: '1.5', order: 5});
-                       this.chart.update();
-                       const metasets = this.chart._metasets;
-                       expect(metasets[0].order).toEqual(2);
-                       expect(metasets[1].order).toEqual(5);
-                       expect(metasets[2].order).toEqual(1);
-                       expect(metasets[3].order).toEqual(4);
-                       expect(metasets[4].order).toEqual(3);
-               });
-               it('should be replaced when dataset is replaced', function() {
-                       this.chart.data.datasets.splice(1, 1, {label: '1.5', order: 5});
-                       this.chart.update();
-                       const metasets = this.chart._metasets;
-                       expect(metasets[0].order).toEqual(2);
-                       expect(metasets[1].order).toEqual(5);
-                       expect(metasets[2].order).toEqual(4);
-                       expect(metasets[3].order).toEqual(3);
-               });
-       });
-
-       describe('data visibility', function() {
-               it('should hide a dataset', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [0, 1, 2]
-                                       }],
-                                       labels: ['a', 'b', 'c']
-                               }
-                       });
-
-                       chart.setDatasetVisibility(0, false);
-
-                       var meta = chart.getDatasetMeta(0);
-                       expect(meta.hidden).toBe(true);
-               });
-
-               it('should toggle data visibility by index', function() {
-                       var chart = acquireChart({
-                               type: 'pie',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3]
-                                       }]
-                               }
-                       });
-
-                       expect(chart.getDataVisibility(1)).toBe(true);
-
-                       chart.toggleDataVisibility(1);
-                       expect(chart.getDataVisibility(1)).toBe(false);
-
-                       chart.update();
-                       expect(chart.getDataVisibility(1)).toBe(false);
-               });
-       });
-
-       describe('isDatasetVisible', function() {
-               it('should return false if index is out of bounds', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [0, 1, 2]
-                                       }],
-                                       labels: ['a', 'b', 'c']
-                               }
-                       });
-
-                       expect(chart.isDatasetVisible(1)).toBe(false);
-               });
-       });
-
-       describe('getChart', function() {
-               it('should get the chart from the canvas ID', function() {
-                       var chart = acquireChart({
-                               type: 'pie',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3]
-                                       }]
-                               }
-                       });
-                       chart.canvas.id = 'myID';
-
-                       expect(Chart.getChart('myID')).toBe(chart);
-               });
-
-               it('should get the chart from an HTMLCanvasElement', function() {
-                       var chart = acquireChart({
-                               type: 'pie',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3]
-                                       }]
-                               }
-                       });
-                       expect(Chart.getChart(chart.canvas)).toBe(chart);
-               });
-
-               it('should get the chart from an CanvasRenderingContext2D', function() {
-                       var chart = acquireChart({
-                               type: 'pie',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3]
-                                       }]
-                               }
-                       });
-                       expect(Chart.getChart(chart.ctx)).toBe(chart);
-               });
-
-               it('should return undefined when a chart is not found or bad data is provided', function() {
-                       expect(Chart.getChart(1)).toBeUndefined();
-               });
-       });
-
-       describe('active elements', function() {
-               it('should set the active elements', function() {
-                       var chart = acquireChart({
-                               type: 'pie',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3],
-                                               borderColor: 'red',
-                                               hoverBorderColor: 'blue',
-                                       }]
-                               }
-                       });
-
-                       const meta = chart.getDatasetMeta(0);
-                       let props = meta.data[0].getProps(['borderColor']);
-                       expect(props.options.borderColor).toEqual('red');
-
-                       chart.setActiveElements([{
-                               datasetIndex: 0,
-                               index: 0,
-                       }]);
-
-                       props = meta.data[0].getProps(['borderColor']);
-                       expect(props.options.borderColor).toEqual('blue');
-
-                       const active = chart.getActiveElements();
-                       expect(active.length).toEqual(1);
-                       expect(active[0].element).toBe(meta.data[0]);
-               });
-       });
+    ));
+
+    chart.destroy();
+    expect(createChart).not.toThrow();
+  });
+
+  describe('config initialization', function() {
+    it('should create missing config.data properties', function() {
+      var chart = acquireChart({});
+      var data = chart.data;
+
+      expect(data instanceof Object).toBeTruthy();
+      expect(data.labels instanceof Array).toBeTruthy();
+      expect(data.labels.length).toBe(0);
+      expect(data.datasets instanceof Array).toBeTruthy();
+      expect(data.datasets.length).toBe(0);
+    });
+
+    it('should not alter config.data references', function() {
+      var ds0 = {data: [10, 11, 12, 13]};
+      var ds1 = {data: [20, 21, 22, 23]};
+      var datasets = [ds0, ds1];
+      var labels = [0, 1, 2, 3];
+      var data = {labels: labels, datasets: datasets};
+
+      var chart = acquireChart({
+        type: 'line',
+        data: data
+      });
+
+      expect(chart.data).toBe(data);
+      expect(chart.data.labels).toBe(labels);
+      expect(chart.data.datasets).toBe(datasets);
+      expect(chart.data.datasets[0]).toBe(ds0);
+      expect(chart.data.datasets[1]).toBe(ds1);
+      expect(chart.data.datasets[0].data).toBe(ds0.data);
+      expect(chart.data.datasets[1].data).toBe(ds1.data);
+    });
+
+    it('should define chart.data as an alias for config.data', function() {
+      var config = {data: {labels: [], datasets: []}};
+      var chart = acquireChart(config);
+
+      expect(chart.data).toBe(config.data);
+
+      chart.data = {labels: [1, 2, 3], datasets: [{data: [4, 5, 6]}]};
+
+      expect(config.data).toBe(chart.data);
+      expect(config.data.labels).toEqual([1, 2, 3]);
+      expect(config.data.datasets[0].data).toEqual([4, 5, 6]);
+
+      config.data = {labels: [7, 8, 9], datasets: [{data: [10, 11, 12]}]};
+
+      expect(chart.data).toBe(config.data);
+      expect(chart.data.labels).toEqual([7, 8, 9]);
+      expect(chart.data.datasets[0].data).toEqual([10, 11, 12]);
+    });
+
+    it('should initialize config with default interaction options', function() {
+      var callback = function() {};
+      var defaults = Chart.defaults;
+      var defaultMode = defaults.controllers.line.interaction.mode;
+
+      defaults.hover.onHover = callback;
+      defaults.controllers.line.spanGaps = true;
+      defaults.controllers.line.interaction.mode = 'test';
+
+      var chart = acquireChart({
+        type: 'line'
+      });
+
+      var options = chart.options;
+      expect(options.font.size).toBe(defaults.font.size);
+      expect(options.showLine).toBe(defaults.controllers.line.showLine);
+      expect(options.spanGaps).toBe(true);
+      expect(options.hover.onHover).toBe(callback);
+      expect(options.hover.mode).toBe('test');
+
+      defaults.hover.onHover = null;
+      defaults.controllers.line.spanGaps = false;
+      defaults.controllers.line.interaction.mode = defaultMode;
+    });
+
+    it('should initialize config with default hover options', function() {
+      var callback = function() {};
+      var defaults = Chart.defaults;
+
+      defaults.hover.onHover = callback;
+      defaults.controllers.line.spanGaps = true;
+      defaults.controllers.line.hover.mode = 'test';
+
+      var chart = acquireChart({
+        type: 'line'
+      });
+
+      var options = chart.options;
+      expect(options.font.size).toBe(defaults.font.size);
+      expect(options.showLine).toBe(defaults.controllers.line.showLine);
+      expect(options.spanGaps).toBe(true);
+      expect(options.hover.onHover).toBe(callback);
+      expect(options.hover.mode).toBe('test');
+
+      defaults.hover.onHover = null;
+      defaults.controllers.line.spanGaps = false;
+      delete defaults.controllers.line.hover.mode;
+    });
+
+    it('should override default options', function() {
+      var callback = function() {};
+      var defaults = Chart.defaults;
+
+      defaults.hover.onHover = callback;
+      defaults.controllers.line.hover.mode = 'x-axis';
+      defaults.controllers.line.spanGaps = true;
+
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          spanGaps: false,
+          hover: {
+            mode: 'dataset',
+          },
+          plugins: {
+            title: {
+              position: 'bottom'
+            }
+          }
+        }
+      });
+
+      var options = chart.options;
+      expect(options.showLine).toBe(defaults.showLine);
+      expect(options.spanGaps).toBe(false);
+      expect(options.hover.mode).toBe('dataset');
+      expect(options.plugins.title.position).toBe('bottom');
+
+      defaults.hover.onHover = null;
+      delete defaults.controllers.line.hover.mode;
+      defaults.controllers.line.spanGaps = false;
+    });
+
+    it('should override axis positions that are incorrect', function() {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              position: 'left',
+            },
+            y: {
+              position: 'bottom'
+            }
+          }
+        }
+      });
+
+      var scaleOptions = chart.options.scales;
+      expect(scaleOptions.x.position).toBe('bottom');
+      expect(scaleOptions.y.position).toBe('left');
+    });
+
+    it('should throw an error if the chart type is incorrect', function() {
+      function createChart() {
+        acquireChart({
+          type: 'area',
+          data: {
+            datasets: [{
+              label: 'first',
+              data: [10, 20]
+            }],
+            labels: ['0', '1'],
+          },
+          options: {
+            scales: {
+              x: {
+                type: 'linear',
+                position: 'left',
+              },
+              y: {
+                type: 'category',
+                position: 'bottom'
+              }
+            }
+          }
+        });
+      }
+      expect(createChart).toThrow(new Error('"area" is not a registered controller.'));
+    });
+
+    describe('should disable hover', function() {
+      it('when options.hover=false', function() {
+        var chart = acquireChart({
+          type: 'line',
+          options: {
+            hover: false
+          }
+        });
+        expect(chart.options.hover).toBeFalse();
+      });
+
+      it('when options.interation=false and options.hover is not defined', function() {
+        var chart = acquireChart({
+          type: 'line',
+          options: {
+            interaction: false
+          }
+        });
+        expect(chart.options.hover).toBeFalse();
+      });
+
+      it('when options.interation=false and options.hover is defined', function() {
+        var chart = acquireChart({
+          type: 'line',
+          options: {
+            interaction: false,
+            hover: {mode: 'nearest'}
+          }
+        });
+        expect(chart.options.hover).toBeFalse();
+      });
+    });
+
+    it('should activate element on hover', function(done) {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        }
+      });
+
+      var point = chart.getDatasetMeta(0).data[1];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(chart.getActiveElements()).toEqual([{datasetIndex: 0, index: 1, element: point}]);
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it('should not activate elements when hover is disabled', function(done) {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          hover: false
+        }
+      });
+
+      var point = chart.getDatasetMeta(0).data[1];
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(chart.getActiveElements()).toEqual([]);
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
+
+  describe('when merging scale options', function() {
+    beforeEach(function() {
+      Chart.helpers.merge(Chart.defaults.scale, {
+        _jasmineCheckA: 'a0',
+        _jasmineCheckB: 'b0',
+        _jasmineCheckC: 'c0'
+      });
+
+      Chart.helpers.merge(Chart.defaults.scales.logarithmic, {
+        _jasmineCheckB: 'b1',
+        _jasmineCheckC: 'c1',
+      });
+    });
+
+    afterEach(function() {
+      delete Chart.defaults.scale._jasmineCheckA;
+      delete Chart.defaults.scale._jasmineCheckB;
+      delete Chart.defaults.scale._jasmineCheckC;
+      delete Chart.defaults.scales.logarithmic._jasmineCheckB;
+      delete Chart.defaults.scales.logarithmic._jasmineCheckC;
+    });
+
+    it('should default to "category" for x scales and "linear" for y scales', function() {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            xFoo0: {},
+            xFoo1: {},
+            yBar0: {},
+            yBar1: {},
+          }
+        }
+      });
+
+      expect(chart.scales.xFoo0.type).toBe('category');
+      expect(chart.scales.xFoo1.type).toBe('category');
+      expect(chart.scales.yBar0.type).toBe('linear');
+      expect(chart.scales.yBar1.type).toBe('linear');
+    });
+
+    it('should correctly apply defaults on central scale', function() {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            foo: {
+              type: 'logarithmic',
+              _jasmineCheckC: 'c2',
+              _jasmineCheckD: 'd2'
+            }
+          }
+        }
+      });
+
+      // let's check a few values from the user options and defaults
+
+      expect(chart.scales.foo.type).toBe('logarithmic');
+      expect(chart.scales.foo.options).toEqual(chart.options.scales.foo);
+      expect(chart.scales.foo.options).toEqual(
+        jasmine.objectContaining({
+          _jasmineCheckA: 'a0',
+          _jasmineCheckB: 'b1',
+          _jasmineCheckC: 'c2',
+          _jasmineCheckD: 'd2'
+        }));
+    });
+
+    it('should correctly apply defaults on xy scales', function() {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'logarithmic',
+              _jasmineCheckC: 'c2',
+              _jasmineCheckD: 'd2'
+            },
+            y: {
+              type: 'time',
+              _jasmineCheckC: 'c2',
+              _jasmineCheckE: 'e2'
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.x.type).toBe('logarithmic');
+      expect(chart.scales.x.options).toBe(chart.options.scales.x);
+      expect(chart.scales.x.options).toEqual(
+        jasmine.objectContaining({
+          _jasmineCheckA: 'a0',
+          _jasmineCheckB: 'b1',
+          _jasmineCheckC: 'c2',
+          _jasmineCheckD: 'd2'
+        }));
+
+      expect(chart.scales.y.type).toBe('time');
+      expect(chart.scales.y.options).toBe(chart.options.scales.y);
+      expect(chart.scales.y.options).toEqual(
+        jasmine.objectContaining({
+          _jasmineCheckA: 'a0',
+          _jasmineCheckB: 'b0',
+          _jasmineCheckC: 'c2',
+          _jasmineCheckE: 'e2'
+        }));
+    });
+
+    it('should not alter defaults when merging config', function() {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          _jasmineCheck: 42,
+          scales: {
+            x: {
+              type: 'linear',
+              _jasmineCheck: 42,
+            },
+            y: {
+              type: 'category',
+              _jasmineCheck: 42,
+            }
+          }
+        }
+      });
+
+      expect(chart.options._jasmineCheck).toBeDefined();
+      expect(chart.scales.x.options._jasmineCheck).toBeDefined();
+      expect(chart.scales.y.options._jasmineCheck).toBeDefined();
+
+      expect(Chart.defaults.controllers.line._jasmineCheck).not.toBeDefined();
+      expect(Chart.defaults._jasmineCheck).not.toBeDefined();
+      expect(Chart.defaults.scales.linear._jasmineCheck).not.toBeDefined();
+      expect(Chart.defaults.scales.category._jasmineCheck).not.toBeDefined();
+    });
+  });
+
+  describe('Updating options', function() {
+    it('update should result to same set of options as construct', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: [],
+        options: {
+          animation: false,
+          locale: 'en-US',
+          responsive: false
+        }
+      });
+      const options = chart.options;
+      chart.options = {
+        animation: false,
+        locale: 'en-US',
+        responsive: false
+      };
+      chart.update();
+      expect(chart.options).toEqual(jasmine.objectContaining(options));
+    });
+  });
+
+  describe('config.options.responsive: true (maintainAspectRatio: false)', function() {
+    it('should fill parent width and height', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 150px; height: 245px'
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 350,
+        rw: 300, rh: 350,
+      });
+    });
+
+    it('should resize the canvas when parent width changes', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 350,
+        rw: 300, rh: 350,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 455, dh: 350,
+          rw: 455, rh: 350,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 150, dh: 350,
+            rw: 150, rh: 350,
+          });
+
+          done();
+        });
+        wrapper.style.width = '150px';
+      });
+      wrapper.style.width = '455px';
+    });
+
+    it('should restore the original size when parent became invisible', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px; position: relative'
+        }
+      });
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 300, dh: 350,
+          rw: 300, rh: 350,
+        });
+
+        var original = chart.resize;
+        chart.resize = function() {
+          fail('resize should not have been called');
+        };
+
+        var wrapper = chart.canvas.parentNode;
+        wrapper.style.display = 'none';
+
+        setTimeout(function() {
+          expect(wrapper.clientWidth).toEqual(0);
+          expect(wrapper.clientHeight).toEqual(0);
+
+          expect(chart).toBeChartOfSize({
+            dw: 300, dh: 350,
+            rw: 300, rh: 350,
+          });
+
+          chart.resize = original;
+
+          waitForResize(chart, function() {
+            expect(chart).toBeChartOfSize({
+              dw: 300, dh: 350,
+              rw: 300, rh: 350,
+            });
+
+            done();
+          });
+          wrapper.style.display = 'block';
+        }, 200);
+      });
+    });
+
+    it('should resize the canvas when parent is RTL and width changes', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px; position: relative; direction: rtl'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 350,
+        rw: 300, rh: 350,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 455, dh: 350,
+          rw: 455, rh: 350,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 150, dh: 350,
+            rw: 150, rh: 350,
+          });
+
+          done();
+        });
+        wrapper.style.width = '150px';
+      });
+      wrapper.style.width = '455px';
+    });
+
+    it('should resize the canvas when parent height changes', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 350,
+        rw: 300, rh: 350,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 300, dh: 455,
+          rw: 300, rh: 455,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 300, dh: 150,
+            rw: 300, rh: 150,
+          });
+
+          done();
+        });
+        wrapper.style.height = '150px';
+      });
+      wrapper.style.height = '455px';
+    });
+
+    it('should not include parent padding when resizing the canvas', function(done) {
+      var chart = acquireChart({
+        type: 'line',
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'padding: 50px; width: 320px; height: 350px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 350,
+        rw: 320, rh: 350,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 455, dh: 355,
+          rw: 455, rh: 355,
+        });
+
+        done();
+      });
+      wrapper.style.height = '355px';
+      wrapper.style.width = '455px';
+    });
+
+    it('should resize the canvas when the canvas display style changes from "none" to "block"', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: 'display: none;'
+        },
+        wrapper: {
+          style: 'width: 320px; height: 350px'
+        }
+      });
+
+      var canvas = chart.canvas;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 320, dh: 350,
+          rw: 320, rh: 350,
+        });
+
+        done();
+      });
+      canvas.style.display = 'block';
+    });
+
+    it('should resize the canvas when the wrapper display style changes from "none" to "block"', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'display: none; width: 460px; height: 380px'
+        }
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 460, dh: 380,
+          rw: 460, rh: 380,
+        });
+
+        done();
+      });
+      wrapper.style.display = 'block';
+    });
+
+    // https://github.com/chartjs/Chart.js/issues/5485
+    it('should resize the canvas when the devicePixelRatio changes', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false,
+          devicePixelRatio: 1
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 400px; height: 200px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 400, dh: 200,
+        rw: 400, rh: 200,
+      });
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 400, dh: 200,
+          rw: 800, rh: 400,
+        });
+
+        done();
+      });
+      chart.options.devicePixelRatio = 2;
+      chart.resize();
+    });
+
+    // https://github.com/chartjs/Chart.js/issues/3790
+    it('should resize the canvas if attached to the DOM after construction', function(done) {
+      var canvas = document.createElement('canvas');
+      var wrapper = document.createElement('div');
+      var body = window.document.body;
+      var chart = new Chart(canvas, {
+        type: 'line',
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 0, dh: 0,
+        rw: 0, rh: 0,
+      });
+      expect(chart.chartArea).toBeUndefined();
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 455, dh: 355,
+          rw: 455, rh: 355,
+        });
+
+        expect(chart.chartArea).not.toBeUndefined();
+
+        body.removeChild(wrapper);
+        chart.destroy();
+        done();
+      });
+
+      wrapper.style.cssText = 'width: 455px; height: 355px';
+      wrapper.appendChild(canvas);
+      body.appendChild(wrapper);
+    });
+
+    it('should resize the canvas when attached to a different parent', function(done) {
+      var canvas = document.createElement('canvas');
+      var wrapper = document.createElement('div');
+      var body = window.document.body;
+      var chart = new Chart(canvas, {
+        type: 'line',
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 0, dh: 0,
+        rw: 0, rh: 0,
+      });
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 455, dh: 355,
+          rw: 455, rh: 355,
+        });
+
+        var target = document.createElement('div');
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 640, dh: 480,
+            rw: 640, rh: 480,
+          });
+
+          body.removeChild(wrapper);
+          body.removeChild(target);
+          chart.destroy();
+          done();
+        });
+
+        target.style.cssText = 'width: 640px; height: 480px';
+        target.appendChild(canvas);
+        body.appendChild(target);
+      });
+
+      wrapper.style.cssText = 'width: 455px; height: 355px';
+      wrapper.appendChild(canvas);
+      body.appendChild(wrapper);
+    });
+
+    // https://github.com/chartjs/Chart.js/issues/3521
+    it('should resize the canvas after the wrapper has been re-attached to the DOM', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 320px; height: 350px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 350,
+        rw: 320, rh: 350,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      var parent = wrapper.parentNode;
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 320, dh: 355,
+          rw: 320, rh: 355,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 455, dh: 355,
+            rw: 455, rh: 355,
+          });
+
+          done();
+        });
+
+        parent.removeChild(wrapper);
+        wrapper.style.width = '455px';
+        parent.appendChild(wrapper);
+      });
+
+      parent.removeChild(wrapper);
+      parent.appendChild(wrapper);
+      wrapper.style.height = '355px';
+    });
+
+    // https://github.com/chartjs/Chart.js/issues/4737
+    it('should resize the canvas when re-creating the chart', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true
+        }
+      }, {
+        wrapper: {
+          style: 'width: 320px'
+        }
+      });
+
+      var wrapper = chart.canvas.parentNode;
+
+      waitForResize(chart, function() {
+        var canvas = chart.canvas;
+        expect(chart).toBeChartOfSize({
+          dw: 320, dh: 320,
+          rw: 320, rh: 320,
+        });
+
+        chart.destroy();
+        chart = new Chart(canvas, {
+          type: 'line',
+          options: {
+            responsive: true
+          }
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 455, dh: 455,
+            rw: 455, rh: 455,
+          });
+
+          chart.destroy();
+          window.document.body.removeChild(wrapper);
+          done();
+        });
+        canvas.parentNode.style.width = '455px';
+      });
+    });
+  });
+
+  describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
+    it('should resize the canvas with correct aspect ratio when parent width changes', function(done) {
+      var chart = acquireChart({
+        type: 'line', // AR == 2
+        options: {
+          responsive: true,
+          maintainAspectRatio: true
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 150,
+        rw: 300, rh: 150,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 450, dh: 225,
+          rw: 450, rh: 225,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 150, dh: 75,
+            rw: 150, rh: 75,
+          });
+
+          done();
+        });
+        wrapper.style.width = '150px';
+      });
+      wrapper.style.width = '450px';
+    });
+
+    it('should not resize the canvas when parent height changes', function(done) {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: true
+        }
+      }, {
+        canvas: {
+          style: ''
+        },
+        wrapper: {
+          style: 'width: 320px; height: 350px; position: relative'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 160,
+        rw: 320, rh: 160,
+      });
+
+      var wrapper = chart.canvas.parentNode;
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 320, dh: 160,
+          rw: 320, rh: 160,
+        });
+
+        waitForResize(chart, function() {
+          expect(chart).toBeChartOfSize({
+            dw: 320, dh: 160,
+            rw: 320, rh: 160,
+          });
+
+          done();
+        });
+        wrapper.style.height = '150px';
+      });
+      wrapper.style.height = '455px';
+    });
+  });
+
+  describe('Retina scale (a.k.a. device pixel ratio)', function() {
+    beforeEach(function() {
+      this.devicePixelRatio = window.devicePixelRatio;
+      window.devicePixelRatio = 3;
+    });
+
+    afterEach(function() {
+      window.devicePixelRatio = this.devicePixelRatio;
+    });
+
+    // see https://github.com/chartjs/Chart.js/issues/3575
+    it ('should scale the render size but not the "implicit" display size', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          width: 320,
+          height: 240,
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 240,
+        rw: 960, rh: 720,
+      });
+    });
+
+    it ('should scale the render size but not the "explicit" display size', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 320px; height: 240px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 240,
+        rw: 960, rh: 720,
+      });
+    });
+  });
+
+  describe('config.options.devicePixelRatio', function() {
+    beforeEach(function() {
+      this.devicePixelRatio = window.devicePixelRatio;
+      window.devicePixelRatio = 1;
+    });
+
+    afterEach(function() {
+      window.devicePixelRatio = this.devicePixelRatio;
+    });
+
+    // see https://github.com/chartjs/Chart.js/issues/3575
+    it ('should scale the render size but not the "implicit" display size', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false,
+          devicePixelRatio: 3
+        }
+      }, {
+        canvas: {
+          width: 320,
+          height: 240,
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 240,
+        rw: 960, rh: 720,
+      });
+    });
+
+    it ('should scale the render size but not the "explicit" display size', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false,
+          devicePixelRatio: 3
+        }
+      }, {
+        canvas: {
+          style: 'width: 320px; height: 240px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 320, dh: 240,
+        rw: 960, rh: 720,
+      });
+    });
+  });
+
+  describe('controller.reset', function() {
+    it('should reset the chart elements', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 0]
+          }]
+        },
+        options: {
+          responsive: true
+        }
+      });
+
+      var meta = chart.getDatasetMeta(0);
+
+      // Verify that points are at their initial correct location,
+      // then we will reset and see that they moved
+      expect(meta.data[0].y).toBeCloseToPixel(333);
+      expect(meta.data[1].y).toBeCloseToPixel(183);
+      expect(meta.data[2].y).toBeCloseToPixel(32);
+      expect(meta.data[3].y).toBeCloseToPixel(482);
+
+      chart.reset();
+
+      // For a line chart, the animation state is the bottom
+      expect(meta.data[0].y).toBeCloseToPixel(482);
+      expect(meta.data[1].y).toBeCloseToPixel(482);
+      expect(meta.data[2].y).toBeCloseToPixel(482);
+      expect(meta.data[3].y).toBeCloseToPixel(482);
+    });
+  });
+
+  describe('config update', function() {
+    it ('should update options', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true
+        }
+      });
+
+      chart.options = {
+        responsive: false,
+        scales: {
+          y: {
+            min: 0,
+            max: 10
+          }
+        }
+      };
+      chart.update();
+
+      var yScale = chart.scales.y;
+      expect(yScale.options.min).toBe(0);
+      expect(yScale.options.max).toBe(10);
+    });
+
+    it ('should update scales options', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true
+        }
+      });
+
+      chart.options.scales.y.min = 0;
+      chart.options.scales.y.max = 10;
+      chart.update();
+
+      var yScale = chart.scales.y;
+      expect(yScale.options.min).toBe(0);
+      expect(yScale.options.max).toBe(10);
+    });
+
+    it ('should update scales options from new object', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true
+        }
+      });
+
+      var newScalesConfig = {
+        y: {
+          min: 0,
+          max: 10
+        }
+      };
+      chart.options.scales = newScalesConfig;
+
+      chart.update();
+
+      var yScale = chart.scales.y;
+      expect(yScale.options.min).toBe(0);
+      expect(yScale.options.max).toBe(10);
+    });
+
+    it ('should remove discarded scale', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true,
+          scales: {
+            y: {
+              min: 0,
+              max: 10
+            }
+          }
+        }
+      });
+
+      var newScalesConfig = {
+        y: {
+          min: 0,
+          max: 10
+        }
+      };
+      chart.options.scales = newScalesConfig;
+
+      chart.update();
+
+      var yScale = chart.scales.yAxis0;
+      expect(yScale).toBeUndefined();
+      var newyScale = chart.scales.y;
+      expect(newyScale.options.min).toBe(0);
+      expect(newyScale.options.max).toBe(10);
+    });
+
+    it ('should update tooltip options', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true
+        }
+      });
+
+      var newTooltipConfig = {
+        mode: 'dataset',
+        intersect: false
+      };
+      chart.options.plugins.tooltip = newTooltipConfig;
+
+      chart.update();
+      expect(chart.tooltip.options).toEqual(jasmine.objectContaining(newTooltipConfig));
+    });
+
+    it ('should update the tooltip on update', function(done) {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true,
+          tooltip: {
+            mode: 'nearest'
+          }
+        }
+      });
+
+      // Trigger an event over top of a point to
+      // put an item into the tooltip
+      var meta = chart.getDatasetMeta(0);
+      var point = meta.data[1];
+
+      afterEvent(chart, 'mousemove', function() {
+        // Check and see if tooltip was displayed
+        var tooltip = chart.tooltip;
+
+        expect(chart._active[0].element).toEqual(point);
+        expect(tooltip._active[0].element).toEqual(point);
+
+        // Update and confirm tooltip is updated
+        chart.update();
+        expect(chart._active[0].element).toEqual(point);
+        expect(tooltip._active[0].element).toEqual(point);
+
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+
+    it ('should update the metadata', function() {
+      var cfg = {
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            type: 'line',
+            data: [10, 20, 30, 0]
+          }]
+        },
+        options: {
+          responsive: true,
+          scales: {
+            x: {
+              type: 'category'
+            },
+            y: {
+              type: 'linear',
+              scaleLabel: {
+                display: true,
+                labelString: 'Value'
+              }
+            }
+          }
+        }
+      };
+      var chart = acquireChart(cfg);
+      var meta = chart.getDatasetMeta(0);
+      expect(meta.type).toBe('line');
+
+      // change the dataset to bar and check that meta was updated
+      chart.config.data.datasets[0].type = 'bar';
+      chart.update();
+      meta = chart.getDatasetMeta(0);
+      expect(meta.type).toBe('bar');
+    });
+  });
+
+  describe('plugin.extensions', function() {
+    var hooks = {
+      install: ['install'],
+      uninstall: ['uninstall'],
+      init: [
+        'beforeInit',
+        'resize',
+        'afterInit'
+      ],
+      start: ['start'],
+      stop: ['stop'],
+      update: [
+        'beforeUpdate',
+        'beforeLayout',
+        'beforeDataLimits',
+        'afterDataLimits',
+        'beforeBuildTicks',
+        'afterBuildTicks',
+        'beforeDataLimits',
+        'afterDataLimits',
+        'beforeBuildTicks',
+        'afterBuildTicks',
+        'afterLayout',
+        'beforeDatasetsUpdate',
+        'beforeDatasetUpdate',
+        'afterDatasetUpdate',
+        'afterDatasetsUpdate',
+        'afterUpdate',
+      ],
+      render: [
+        'beforeRender',
+        'beforeDraw',
+        'beforeDatasetsDraw',
+        'beforeDatasetDraw',
+        'afterDatasetDraw',
+        'afterDatasetsDraw',
+        'beforeTooltipDraw',
+        'afterTooltipDraw',
+        'afterDraw',
+        'afterRender',
+      ],
+      resize: [
+        'resize'
+      ],
+      destroy: [
+        'destroy'
+      ]
+    };
+
+    it ('should notify plugin in correct order', function(done) {
+      var plugin = this.plugin = {};
+      var sequence = [];
+
+      Object.keys(hooks).forEach(function(group) {
+        hooks[group].forEach(function(name) {
+          plugin[name] = function() {
+            sequence.push(name);
+          };
+        });
+      });
+
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {datasets: [{}]},
+        plugins: [plugin],
+        options: {
+          responsive: true
+        }
+      }, {
+        wrapper: {
+          style: 'width: 300px'
+        }
+      });
+
+      waitForResize(chart, function() {
+        chart.destroy();
+
+        expect(sequence).toEqual([].concat(
+          hooks.install,
+          hooks.start,
+          hooks.init,
+          hooks.update,
+          hooks.render,
+          hooks.resize,
+          hooks.update,
+          hooks.render,
+          hooks.destroy,
+          hooks.stop,
+          hooks.uninstall
+        ));
+
+        done();
+      });
+      chart.canvas.parentNode.style.width = '400px';
+    });
+
+    it ('should notify initially disabled plugin in correct order', function() {
+      var plugin = this.plugin = {id: 'plugin'};
+      var sequence = [];
+
+      Object.keys(hooks).forEach(function(group) {
+        hooks[group].forEach(function(name) {
+          plugin[name] = function() {
+            sequence.push(name);
+          };
+        });
+      });
+
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {datasets: [{}]},
+        plugins: [plugin],
+        options: {
+          plugins: {
+            plugin: false
+          }
+        }
+      });
+
+      expect(sequence).toEqual([].concat(
+        hooks.install
+      ));
+
+      sequence = [];
+      chart.options.plugins.plugin = true;
+      chart.update();
+
+      expect(sequence).toEqual([].concat(
+        hooks.start,
+        hooks.update,
+        hooks.render
+      ));
+
+      sequence = [];
+      chart.options.plugins.plugin = false;
+      chart.update();
+
+      expect(sequence).toEqual(hooks.stop);
+
+      sequence = [];
+      chart.destroy();
+
+      expect(sequence).toEqual(hooks.uninstall);
+    });
+
+    it('should not notify before/afterDatasetDraw if dataset is hidden', function() {
+      var sequence = [];
+      var plugin = this.plugin = {
+        beforeDatasetDraw: function(chart, args) {
+          sequence.push('before-' + args.index);
+        },
+        afterDatasetDraw: function(chart, args) {
+          sequence.push('after-' + args.index);
+        }
+      };
+
+      window.acquireChart({
+        type: 'line',
+        data: {datasets: [{}, {hidden: true}, {}]},
+        plugins: [plugin]
+      });
+
+      expect(sequence).toEqual([
+        'before-2', 'after-2',
+        'before-0', 'after-0'
+      ]);
+    });
+  });
+
+  describe('metasets', function() {
+    beforeEach(function() {
+      this.chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {label: '1', order: 2},
+            {label: '2', order: 1},
+            {label: '3', order: 4},
+            {label: '4', order: 3},
+          ]
+        }
+      });
+    });
+    afterEach(function() {
+      const metasets = this.chart._metasets;
+      expect(metasets.length).toEqual(this.chart.data.datasets.length);
+      for (let i = 0; i < metasets.length; i++) {
+        expect(metasets[i].index).toEqual(i);
+        expect(metasets[i]._dataset).toEqual(this.chart.data.datasets[i]);
+      }
+    });
+    it('should build metasets array in order', function() {
+      const metasets = this.chart._metasets;
+      expect(metasets[0].order).toEqual(2);
+      expect(metasets[1].order).toEqual(1);
+      expect(metasets[2].order).toEqual(4);
+      expect(metasets[3].order).toEqual(3);
+    });
+    it('should build sorted metasets array in correct order', function() {
+      const metasets = this.chart._sortedMetasets;
+      expect(metasets[0].order).toEqual(1);
+      expect(metasets[1].order).toEqual(2);
+      expect(metasets[2].order).toEqual(3);
+      expect(metasets[3].order).toEqual(4);
+    });
+    it('should be moved when datasets are removed from begining', function() {
+      this.chart.data.datasets.splice(0, 2);
+      this.chart.update();
+      const metasets = this.chart._metasets;
+      expect(metasets[0].order).toEqual(4);
+      expect(metasets[1].order).toEqual(3);
+    });
+    it('should be moved when datasets are removed from middle', function() {
+      this.chart.data.datasets.splice(1, 2);
+      this.chart.update();
+      const metasets = this.chart._metasets;
+      expect(metasets[0].order).toEqual(2);
+      expect(metasets[1].order).toEqual(3);
+    });
+    it('should be moved when datasets are inserted', function() {
+      this.chart.data.datasets.splice(1, 0, {label: '1.5', order: 5});
+      this.chart.update();
+      const metasets = this.chart._metasets;
+      expect(metasets[0].order).toEqual(2);
+      expect(metasets[1].order).toEqual(5);
+      expect(metasets[2].order).toEqual(1);
+      expect(metasets[3].order).toEqual(4);
+      expect(metasets[4].order).toEqual(3);
+    });
+    it('should be replaced when dataset is replaced', function() {
+      this.chart.data.datasets.splice(1, 1, {label: '1.5', order: 5});
+      this.chart.update();
+      const metasets = this.chart._metasets;
+      expect(metasets[0].order).toEqual(2);
+      expect(metasets[1].order).toEqual(5);
+      expect(metasets[2].order).toEqual(4);
+      expect(metasets[3].order).toEqual(3);
+    });
+  });
+
+  describe('data visibility', function() {
+    it('should hide a dataset', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [0, 1, 2]
+          }],
+          labels: ['a', 'b', 'c']
+        }
+      });
+
+      chart.setDatasetVisibility(0, false);
+
+      var meta = chart.getDatasetMeta(0);
+      expect(meta.hidden).toBe(true);
+    });
+
+    it('should toggle data visibility by index', function() {
+      var chart = acquireChart({
+        type: 'pie',
+        data: {
+          datasets: [{
+            data: [1, 2, 3]
+          }]
+        }
+      });
+
+      expect(chart.getDataVisibility(1)).toBe(true);
+
+      chart.toggleDataVisibility(1);
+      expect(chart.getDataVisibility(1)).toBe(false);
+
+      chart.update();
+      expect(chart.getDataVisibility(1)).toBe(false);
+    });
+  });
+
+  describe('isDatasetVisible', function() {
+    it('should return false if index is out of bounds', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [0, 1, 2]
+          }],
+          labels: ['a', 'b', 'c']
+        }
+      });
+
+      expect(chart.isDatasetVisible(1)).toBe(false);
+    });
+  });
+
+  describe('getChart', function() {
+    it('should get the chart from the canvas ID', function() {
+      var chart = acquireChart({
+        type: 'pie',
+        data: {
+          datasets: [{
+            data: [1, 2, 3]
+          }]
+        }
+      });
+      chart.canvas.id = 'myID';
+
+      expect(Chart.getChart('myID')).toBe(chart);
+    });
+
+    it('should get the chart from an HTMLCanvasElement', function() {
+      var chart = acquireChart({
+        type: 'pie',
+        data: {
+          datasets: [{
+            data: [1, 2, 3]
+          }]
+        }
+      });
+      expect(Chart.getChart(chart.canvas)).toBe(chart);
+    });
+
+    it('should get the chart from an CanvasRenderingContext2D', function() {
+      var chart = acquireChart({
+        type: 'pie',
+        data: {
+          datasets: [{
+            data: [1, 2, 3]
+          }]
+        }
+      });
+      expect(Chart.getChart(chart.ctx)).toBe(chart);
+    });
+
+    it('should return undefined when a chart is not found or bad data is provided', function() {
+      expect(Chart.getChart(1)).toBeUndefined();
+    });
+  });
+
+  describe('active elements', function() {
+    it('should set the active elements', function() {
+      var chart = acquireChart({
+        type: 'pie',
+        data: {
+          datasets: [{
+            data: [1, 2, 3],
+            borderColor: 'red',
+            hoverBorderColor: 'blue',
+          }]
+        }
+      });
+
+      const meta = chart.getDatasetMeta(0);
+      let props = meta.data[0].getProps(['borderColor']);
+      expect(props.options.borderColor).toEqual('red');
+
+      chart.setActiveElements([{
+        datasetIndex: 0,
+        index: 0,
+      }]);
+
+      props = meta.data[0].getProps(['borderColor']);
+      expect(props.options.borderColor).toEqual('blue');
+
+      const active = chart.getActiveElements();
+      expect(active.length).toEqual(1);
+      expect(active[0].element).toBe(meta.data[0]);
+    });
+  });
 });
index 473611e1a90157509fa83f33d3b3c5ed5cabf169..2b34a8fa36cb18d1ebfeb426743a8b7430f39b92 100644 (file)
 describe('Chart.DatasetController', function() {
-       it('should listen for dataset data insertions or removals', function() {
-               var data = [0, 1, 2, 3, 4, 5];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data
-                               }]
-                       }
-               });
-
-               var controller = chart.getDatasetMeta(0).controller;
-               var methods = [
-                       '_onDataPush',
-                       '_onDataPop',
-                       '_onDataShift',
-                       '_onDataSplice',
-                       '_onDataUnshift'
-               ];
-
-               methods.forEach(function(method) {
-                       spyOn(controller, method);
-               });
-
-               data.push(6, 7, 8);
-               data.push(9);
-               data.pop();
-               data.shift();
-               data.shift();
-               data.shift();
-               data.splice(1, 4, 10, 11);
-               data.unshift(12, 13, 14, 15);
-               data.unshift(16, 17);
-
-               [2, 1, 3, 1, 2].forEach(function(expected, index) {
-                       expect(controller[methods[index]].calls.count()).toBe(expected);
-               });
-       });
-
-       it('should not try to delete non existent stacks', function() {
-               function createAndUpdateChart() {
-                       var chart = acquireChart({
-                               data: {
-                                       labels: ['q'],
-                                       datasets: [
-                                               {
-                                                       id: 'dismissed',
-                                                       label: 'Test before',
-                                                       yAxisID: 'count',
-                                                       data: [816],
-                                                       type: 'bar',
-                                                       stack: 'stack'
-                                               }
-                                       ]
-                               },
-                               options: {
-                                       scales: {
-                                               count: {
-                                                       axis: 'y',
-                                                       type: 'linear'
-                                               }
-                                       }
-                               }
-                       });
-
-                       chart.data = {
-                               datasets: [
-                                       {
-                                               id: 'tests',
-                                               yAxisID: 'count',
-                                               label: 'Test after',
-                                               data: [38300],
-                                               type: 'bar'
-                                       }
-                               ],
-                               labels: ['q']
-                       };
-
-                       chart.update();
-               }
-
-               expect(createAndUpdateChart).not.toThrow();
-       });
-
-       describe('inextensible data', function() {
-               it('should handle a frozen data object', function() {
-                       function createChart() {
-                               var data = Object.freeze([0, 1, 2, 3, 4, 5]);
-                               expect(Object.isExtensible(data)).toBeFalsy();
-
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: data
-                                               }]
-                                       }
-                               });
-
-                               var dataset = chart.data.datasets[0];
-                               dataset.data = Object.freeze([5, 4, 3, 2, 1, 0]);
-                               expect(Object.isExtensible(dataset.data)).toBeFalsy();
-                               chart.update();
-
-                               // Tests that the unlisten path also works for frozen objects
-                               chart.destroy();
-                       }
-
-                       expect(createChart).not.toThrow();
-               });
-
-               it('should handle a sealed data object', function() {
-                       function createChart() {
-                               var data = Object.seal([0, 1, 2, 3, 4, 5]);
-                               expect(Object.isExtensible(data)).toBeFalsy();
-
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: data
-                                               }]
-                                       }
-                               });
-
-                               var dataset = chart.data.datasets[0];
-                               dataset.data = Object.seal([5, 4, 3, 2, 1, 0]);
-                               expect(Object.isExtensible(dataset.data)).toBeFalsy();
-                               chart.update();
-
-                               // Tests that the unlisten path also works for frozen objects
-                               chart.destroy();
-                       }
-
-                       expect(createChart).not.toThrow();
-               });
-
-               it('should handle an unextendable data object', function() {
-                       function createChart() {
-                               var data = Object.preventExtensions([0, 1, 2, 3, 4, 5]);
-                               expect(Object.isExtensible(data)).toBeFalsy();
-
-                               var chart = acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: data
-                                               }]
-                                       }
-                               });
-
-                               var dataset = chart.data.datasets[0];
-                               dataset.data = Object.preventExtensions([5, 4, 3, 2, 1, 0]);
-                               expect(Object.isExtensible(dataset.data)).toBeFalsy();
-                               chart.update();
-
-                               // Tests that the unlisten path also works for frozen objects
-                               chart.destroy();
-                       }
-
-                       expect(createChart).not.toThrow();
-               });
-       });
-
-       it('should parse data using correct scales', function() {
-               const data1 = [0, 1, 2, 3, 4, 5];
-               const data2 = ['a', 'b', 'c', 'd', 'a'];
-               const chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [
-                                       {data: data1},
-                                       {data: data2, xAxisID: 'x2', yAxisID: 'y2'}
-                               ]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               labels: ['one', 'two', 'three', 'four', 'five', 'six']
-                                       },
-                                       x2: {
-                                               type: 'logarithmic',
-                                               labels: ['1', '10', '100', '1000', '2000']
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       },
-                                       y2: {
-                                               type: 'category',
-                                               labels: ['a', 'b', 'c', 'd', 'e']
-                                       }
-                               }
-                       }
-               });
-
-               const meta1 = chart.getDatasetMeta(0);
-               const parsedXValues1 = meta1._parsed.map(p => p.x);
-               const parsedYValues1 = meta1._parsed.map(p => p.y);
-
-               expect(meta1.data.length).toBe(6);
-               expect(parsedXValues1).toEqual([0, 1, 2, 3, 4, 5]); // label indices
-               expect(parsedYValues1).toEqual(data1);
-
-               const meta2 = chart.getDatasetMeta(1);
-               const parsedXValues2 = meta2._parsed.map(p => p.x);
-               const parsedYValues2 = meta2._parsed.map(p => p.y);
-
-               expect(meta2.data.length).toBe(5);
-               expect(parsedXValues2).toEqual([1, 10, 100, 1000, 2000]); // logarithmic scale labels
-               expect(parsedYValues2).toEqual([0, 1, 2, 3, 0]); // label indices
-       });
-
-       it('should parse using provided keys', function() {
-               const chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [
-                                               {x: 1, data: {key: 'one', value: 20}},
-                                               {data: {key: 'two', value: 30}}
-                                       ]
-                               }]
-                       },
-                       options: {
-                               parsing: {
-                                       xAxisKey: 'data.key',
-                                       yAxisKey: 'data.value'
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               labels: ['one', 'two']
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       },
-                               }
-                       }
-               });
-
-               const meta = chart.getDatasetMeta(0);
-               const parsedXValues = meta._parsed.map(p => p.x);
-               const parsedYValues = meta._parsed.map(p => p.y);
-
-               expect(meta.data.length).toBe(2);
-               expect(parsedXValues).toEqual([0, 1]); // label indices
-               expect(parsedYValues).toEqual([20, 30]);
-       });
-
-       it('should synchronize metadata when data are inserted or removed and parsing is on', function() {
-               const data = [0, 1, 2, 3, 4, 5];
-               const chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data
-                               }]
-                       }
-               });
-
-               const meta = chart.getDatasetMeta(0);
-               const parsedYValues = () => meta._parsed.map(p => p.y);
-               let first, second, last;
-
-               first = meta.data[0];
-               last = meta.data[5];
-               data.push(6, 7, 8);
-               data.push(9);
-               expect(meta.data.length).toBe(10);
-               expect(meta.data[0]).toBe(first);
-               expect(meta.data[5]).toBe(last);
-               expect(parsedYValues()).toEqual(data);
-
-               last = meta.data[9];
-               data.pop();
-               expect(meta.data.length).toBe(9);
-               expect(meta.data[0]).toBe(first);
-               expect(meta.data.indexOf(last)).toBe(-1);
-               expect(parsedYValues()).toEqual(data);
-
-               last = meta.data[8];
-               data.shift();
-               data.shift();
-               data.shift();
-               expect(meta.data.length).toBe(6);
-               expect(meta.data.indexOf(first)).toBe(-1);
-               expect(meta.data[5]).toBe(last);
-               expect(parsedYValues()).toEqual(data);
-
-               first = meta.data[0];
-               second = meta.data[1];
-               last = meta.data[5];
-               data.splice(1, 4, 10, 11);
-               expect(meta.data.length).toBe(4);
-               expect(meta.data[0]).toBe(first);
-               expect(meta.data[3]).toBe(last);
-               expect(meta.data.indexOf(second)).toBe(-1);
-               expect(parsedYValues()).toEqual(data);
-
-               data.unshift(12, 13, 14, 15);
-               data.unshift(16, 17);
-               expect(meta.data.length).toBe(10);
-               expect(meta.data[6]).toBe(first);
-               expect(meta.data[9]).toBe(last);
-               expect(parsedYValues()).toEqual(data);
-       });
-
-       it('should synchronize metadata when data are inserted or removed and parsing is off', function() {
-               var data = [{x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}, {x: 3, y: 3}, {x: 4, y: 4}, {x: 5, y: 5}];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data
-                               }]
-                       },
-                       options: {
-                               parsing: false,
-                               scales: {
-                                       x: {type: 'linear'},
-                                       y: {type: 'linear'}
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               var controller = meta.controller;
-               var first, last;
-
-               first = controller.getParsed(0);
-               last = controller.getParsed(5);
-               data.push({x: 6, y: 6}, {x: 7, y: 7}, {x: 8, y: 8});
-               data.push({x: 9, y: 9});
-               expect(meta.data.length).toBe(10);
-               expect(controller.getParsed(0)).toBe(first);
-               expect(controller.getParsed(5)).toBe(last);
-
-               last = controller.getParsed(9);
-               data.pop();
-               expect(meta.data.length).toBe(9);
-               expect(controller.getParsed(0)).toBe(first);
-               expect(controller.getParsed(9)).toBe(undefined);
-               expect(controller.getParsed(8)).toEqual({x: 8, y: 8});
-
-               last = controller.getParsed(8);
-               data.shift();
-               data.shift();
-               data.shift();
-               expect(meta.data.length).toBe(6);
-               expect(controller.getParsed(5)).toBe(last);
-
-               first = controller.getParsed(0);
-               last = controller.getParsed(5);
-               data.splice(1, 4, {x: 10, y: 10}, {x: 11, y: 11});
-               expect(meta.data.length).toBe(4);
-               expect(controller.getParsed(0)).toBe(first);
-               expect(controller.getParsed(3)).toBe(last);
-               expect(controller.getParsed(1)).toEqual({x: 10, y: 10});
-
-               data.unshift({x: 12, y: 12}, {x: 13, y: 13}, {x: 14, y: 14}, {x: 15, y: 15});
-               data.unshift({x: 16, y: 16}, {x: 17, y: 17});
-               expect(meta.data.length).toBe(10);
-               expect(controller.getParsed(6)).toBe(first);
-               expect(controller.getParsed(9)).toBe(last);
-       });
-
-       it('should re-synchronize metadata when the data object reference changes', function() {
-               var data0 = [0, 1, 2, 3, 4, 5];
-               var data1 = [6, 7, 8];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data0
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(6);
-               expect(meta._parsed.map(p => p.y)).toEqual(data0);
-
-               chart.data.datasets[0].data = data1;
-               chart.update();
-
-               expect(meta.data.length).toBe(3);
-               expect(meta._parsed.map(p => p.y)).toEqual(data1);
-
-               data1.push(9);
-               expect(meta.data.length).toBe(4);
-
-               chart.data.datasets[0].data = data0;
-               chart.update();
-
-               expect(meta.data.length).toBe(6);
-               expect(meta._parsed.map(p => p.y)).toEqual(data0);
-       });
-
-       it('should re-synchronize metadata when data are unusually altered', function() {
-               var data = [0, 1, 2, 3, 4, 5];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(6);
-
-               data.length = 2;
-               chart.update();
-
-               expect(meta.data.length).toBe(2);
-
-               data.length = 42;
-               chart.update();
-
-               expect(meta.data.length).toBe(42);
-       });
-
-       // https://github.com/chartjs/Chart.js/issues/7243
-       it('should re-synchronize metadata when data is moved and values are equal', function() {
-               var data = [10, 10, 10, 10, 10, 10];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f'],
-                               datasets: [{
-                                       data,
-                                       fill: true
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(6);
-               const firstX = meta.data[0].x;
-
-               data.push(data.shift());
-               chart.update();
-
-               expect(meta.data.length).toBe(6);
-               expect(meta.data[0].x).toEqual(firstX);
-       });
-
-       // https://github.com/chartjs/Chart.js/issues/7445
-       it('should re-synchronize metadata when data is objects and directly altered', function() {
-               var data = [{x: 'a', y: 1}, {x: 'b', y: 2}, {x: 'c', y: 3}];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['a', 'b', 'c'],
-                               datasets: [{
-                                       data,
-                                       fill: true
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.data.length).toBe(3);
-               const y3 = meta.data[2].y;
-
-               data[0].y = 3;
-               chart.update();
-               expect(meta.data[0].y).toEqual(y3);
-       });
-
-       it('should re-synchronize metadata when scaleID changes', function() {
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [],
-                                       xAxisID: 'firstXScaleID',
-                                       yAxisID: 'firstYScaleID',
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       firstXScaleID: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       secondXScaleID: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       firstYScaleID: {
-                                               type: 'linear',
-                                               position: 'left'
-                                       },
-                                       secondYScaleID: {
-                                               type: 'linear',
-                                               position: 'left'
-                                       },
-                               }
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-
-               expect(meta.xAxisID).toBe('firstXScaleID');
-               expect(meta.yAxisID).toBe('firstYScaleID');
-
-               chart.data.datasets[0].xAxisID = 'secondXScaleID';
-               chart.data.datasets[0].yAxisID = 'secondYScaleID';
-               chart.update();
-
-               expect(meta.xAxisID).toBe('secondXScaleID');
-               expect(meta.yAxisID).toBe('secondYScaleID');
-       });
-
-       it('should re-synchronize stacks when stack is changed', function() {
-               var chart = acquireChart({
-                       type: 'bar',
-                       data: {
-                               labels: ['a', 'b'],
-                               datasets: [{
-                                       data: [1, 10],
-                                       stack: '1'
-                               }, {
-                                       data: [2, 20],
-                                       stack: '2'
-                               }, {
-                                       data: [3, 30],
-                                       stack: '1'
-                               }]
-                       }
-               });
-
-               expect(chart._stacks).toEqual({
-                       'x.y.1.bar': {
-                               0: {0: 1, 2: 3},
-                               1: {0: 10, 2: 30}
-                       },
-                       'x.y.2.bar': {
-                               0: {1: 2},
-                               1: {1: 20}
-                       }
-               });
-
-               chart.data.datasets[2].stack = '2';
-               chart.update();
-
-               expect(chart._stacks).toEqual({
-                       'x.y.1.bar': {
-                               0: {0: 1},
-                               1: {0: 10}
-                       },
-                       'x.y.2.bar': {
-                               0: {1: 2, 2: 3},
-                               1: {1: 20, 2: 30}
-                       }
-               });
-       });
-
-       it('should re-synchronize stacks when data is removed', function() {
-               var chart = acquireChart({
-                       type: 'bar',
-                       data: {
-                               labels: ['a', 'b'],
-                               datasets: [{
-                                       data: [1, 10],
-                                       stack: '1'
-                               }, {
-                                       data: [2, 20],
-                                       stack: '2'
-                               }, {
-                                       data: [3, 30],
-                                       stack: '1'
-                               }]
-                       }
-               });
-
-               expect(chart._stacks).toEqual({
-                       'x.y.1.bar': {
-                               0: {0: 1, 2: 3},
-                               1: {0: 10, 2: 30}
-                       },
-                       'x.y.2.bar': {
-                               0: {1: 2},
-                               1: {1: 20}
-                       }
-               });
-
-               chart.data.datasets[2].data = [4];
-               chart.update();
-
-               expect(chart._stacks).toEqual({
-                       'x.y.1.bar': {
-                               0: {0: 1, 2: 4},
-                               1: {0: 10}
-                       },
-                       'x.y.2.bar': {
-                               0: {1: 2},
-                               1: {1: 20}
-                       }
-               });
-       });
-
-       it('should cleanup attached properties when the reference changes or when the chart is destroyed', function() {
-               var data0 = [0, 1, 2, 3, 4, 5];
-               var data1 = [6, 7, 8];
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data0
-                               }]
-                       }
-               });
-
-               var hooks = ['push', 'pop', 'shift', 'splice', 'unshift'];
-
-               expect(data0._chartjs).toBeDefined();
-               hooks.forEach(function(hook) {
-                       expect(data0[hook]).not.toBe(Array.prototype[hook]);
-               });
-
-               expect(data1._chartjs).not.toBeDefined();
-               hooks.forEach(function(hook) {
-                       expect(data1[hook]).toBe(Array.prototype[hook]);
-               });
-
-               chart.data.datasets[0].data = data1;
-               chart.update();
-
-               expect(data0._chartjs).not.toBeDefined();
-               hooks.forEach(function(hook) {
-                       expect(data0[hook]).toBe(Array.prototype[hook]);
-               });
-
-               expect(data1._chartjs).toBeDefined();
-               hooks.forEach(function(hook) {
-                       expect(data1[hook]).not.toBe(Array.prototype[hook]);
-               });
-
-               chart.destroy();
-
-               expect(data1._chartjs).not.toBeDefined();
-               hooks.forEach(function(hook) {
-                       expect(data1[hook]).toBe(Array.prototype[hook]);
-               });
-       });
-
-       it('should resolve data element options to the default color', function() {
-               var data0 = [0, 1, 2, 3, 4, 5];
-               var oldColor = Chart.defaults.borderColor;
-               Chart.defaults.borderColor = 'red';
-               var chart = acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: data0
-                               }]
-                       }
-               });
-
-               var meta = chart.getDatasetMeta(0);
-               expect(meta.dataset.options.borderColor).toBe('red');
-               expect(meta.data[0].options.borderColor).toBe('red');
-
-               // Reset old shared state
-               Chart.defaults.borderColor = oldColor;
-       });
-
-       describe('_resolveOptions', function() {
-               it('should resove names in array notation', function() {
-                       Chart.defaults.elements.line.globalTest = 'global';
-
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1],
-                                               datasetTest: 'dataset'
-                                       }]
-                               },
-                               options: {
-                                       elements: {
-                                               line: {
-                                                       elementTest: 'element'
-                                               }
-                                       }
-                               }
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller._resolveOptions(
-                               [
-                                       'datasetTest',
-                                       'elementTest',
-                                       'globalTest'
-                               ],
-                               {type: 'line'})
-                       ).toEqual({
-                               datasetTest: 'dataset',
-                               elementTest: 'element',
-                               globalTest: 'global'
-                       });
-
-                       // Remove test from global defaults
-                       delete Chart.defaults.elements.line.globalTest;
-               });
-
-               it('should resove names in object notation', function() {
-                       Chart.defaults.elements.line.global = 'global';
-
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1],
-                                               datasetTest: 'dataset'
-                                       }]
-                               },
-                               options: {
-                                       elements: {
-                                               line: {
-                                                       element: 'element'
-                                               }
-                                       }
-                               }
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller._resolveOptions(
-                               {
-                                       dataset: 'datasetTest',
-                                       element: 'elementTest',
-                                       global: 'globalTest'},
-                               {type: 'line'})
-                       ).toEqual({
-                               dataset: 'dataset',
-                               element: 'element',
-                               global: 'global'
-                       });
-
-                       // Remove test from global defaults
-                       delete Chart.defaults.elements.line.global;
-               });
-       });
-
-       describe('resolveDataElementOptions', function() {
-               it('should cache options when possible', function() {
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3],
-                                       }]
-                               },
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller.enableOptionSharing).toBeTrue();
-
-                       const opts0 = controller.resolveDataElementOptions(0);
-                       const opts1 = controller.resolveDataElementOptions(1);
-
-                       expect(opts0 === opts1).toBeTrue();
-                       expect(opts0.$shared).toBeTrue();
-                       expect(Object.isFrozen(opts0)).toBeTrue();
-               });
-
-               it('should not cache options when option sharing is disabled', function() {
-                       const chart = acquireChart({
-                               type: 'radar',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3],
-                                       }]
-                               },
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller.enableOptionSharing).toBeFalse();
-
-                       const opts0 = controller.resolveDataElementOptions(0);
-                       const opts1 = controller.resolveDataElementOptions(1);
-
-                       expect(opts0 === opts1).toBeFalse();
-                       expect(opts0.$shared).not.toBeTrue();
-                       expect(Object.isFrozen(opts0)).toBeFalse();
-               });
-
-               it('should not cache options when functions are used', function() {
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1, 2, 3],
-                                               backgroundColor: () => 'red'
-                                       }]
-                               },
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       const opts0 = controller.resolveDataElementOptions(0);
-                       const opts1 = controller.resolveDataElementOptions(1);
-
-                       expect(opts0 === opts1).toBeFalse();
-                       expect(opts0.$shared).not.toBeTrue();
-                       expect(Object.isFrozen(opts0)).toBeFalse();
-               });
-       });
-
-       describe('_resolveAnimations', function() {
-               it('should resolve to empty Animations when globally disabled', function() {
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1],
-                                               animation: {
-                                                       test: {duration: 10}
-                                               }
-                                       }]
-                               },
-                               options: {
-                                       animation: false
-                               }
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller._resolveAnimations(0)._properties.size).toEqual(0);
-               });
-
-               it('should resolve to empty Animations when disabled at dataset level', function() {
-                       const chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: [1],
-                                               animation: false
-                                       }]
-                               }
-                       });
-
-                       const controller = chart.getDatasetMeta(0).controller;
-
-                       expect(controller._resolveAnimations(0)._properties.size).toEqual(0);
-               });
-       });
+  it('should listen for dataset data insertions or removals', function() {
+    var data = [0, 1, 2, 3, 4, 5];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data
+        }]
+      }
+    });
+
+    var controller = chart.getDatasetMeta(0).controller;
+    var methods = [
+      '_onDataPush',
+      '_onDataPop',
+      '_onDataShift',
+      '_onDataSplice',
+      '_onDataUnshift'
+    ];
+
+    methods.forEach(function(method) {
+      spyOn(controller, method);
+    });
+
+    data.push(6, 7, 8);
+    data.push(9);
+    data.pop();
+    data.shift();
+    data.shift();
+    data.shift();
+    data.splice(1, 4, 10, 11);
+    data.unshift(12, 13, 14, 15);
+    data.unshift(16, 17);
+
+    [2, 1, 3, 1, 2].forEach(function(expected, index) {
+      expect(controller[methods[index]].calls.count()).toBe(expected);
+    });
+  });
+
+  it('should not try to delete non existent stacks', function() {
+    function createAndUpdateChart() {
+      var chart = acquireChart({
+        data: {
+          labels: ['q'],
+          datasets: [
+            {
+              id: 'dismissed',
+              label: 'Test before',
+              yAxisID: 'count',
+              data: [816],
+              type: 'bar',
+              stack: 'stack'
+            }
+          ]
+        },
+        options: {
+          scales: {
+            count: {
+              axis: 'y',
+              type: 'linear'
+            }
+          }
+        }
+      });
+
+      chart.data = {
+        datasets: [
+          {
+            id: 'tests',
+            yAxisID: 'count',
+            label: 'Test after',
+            data: [38300],
+            type: 'bar'
+          }
+        ],
+        labels: ['q']
+      };
+
+      chart.update();
+    }
+
+    expect(createAndUpdateChart).not.toThrow();
+  });
+
+  describe('inextensible data', function() {
+    it('should handle a frozen data object', function() {
+      function createChart() {
+        var data = Object.freeze([0, 1, 2, 3, 4, 5]);
+        expect(Object.isExtensible(data)).toBeFalsy();
+
+        var chart = acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: data
+            }]
+          }
+        });
+
+        var dataset = chart.data.datasets[0];
+        dataset.data = Object.freeze([5, 4, 3, 2, 1, 0]);
+        expect(Object.isExtensible(dataset.data)).toBeFalsy();
+        chart.update();
+
+        // Tests that the unlisten path also works for frozen objects
+        chart.destroy();
+      }
+
+      expect(createChart).not.toThrow();
+    });
+
+    it('should handle a sealed data object', function() {
+      function createChart() {
+        var data = Object.seal([0, 1, 2, 3, 4, 5]);
+        expect(Object.isExtensible(data)).toBeFalsy();
+
+        var chart = acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: data
+            }]
+          }
+        });
+
+        var dataset = chart.data.datasets[0];
+        dataset.data = Object.seal([5, 4, 3, 2, 1, 0]);
+        expect(Object.isExtensible(dataset.data)).toBeFalsy();
+        chart.update();
+
+        // Tests that the unlisten path also works for frozen objects
+        chart.destroy();
+      }
+
+      expect(createChart).not.toThrow();
+    });
+
+    it('should handle an unextendable data object', function() {
+      function createChart() {
+        var data = Object.preventExtensions([0, 1, 2, 3, 4, 5]);
+        expect(Object.isExtensible(data)).toBeFalsy();
+
+        var chart = acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: data
+            }]
+          }
+        });
+
+        var dataset = chart.data.datasets[0];
+        dataset.data = Object.preventExtensions([5, 4, 3, 2, 1, 0]);
+        expect(Object.isExtensible(dataset.data)).toBeFalsy();
+        chart.update();
+
+        // Tests that the unlisten path also works for frozen objects
+        chart.destroy();
+      }
+
+      expect(createChart).not.toThrow();
+    });
+  });
+
+  it('should parse data using correct scales', function() {
+    const data1 = [0, 1, 2, 3, 4, 5];
+    const data2 = ['a', 'b', 'c', 'd', 'a'];
+    const chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [
+          {data: data1},
+          {data: data2, xAxisID: 'x2', yAxisID: 'y2'}
+        ]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            labels: ['one', 'two', 'three', 'four', 'five', 'six']
+          },
+          x2: {
+            type: 'logarithmic',
+            labels: ['1', '10', '100', '1000', '2000']
+          },
+          y: {
+            type: 'linear'
+          },
+          y2: {
+            type: 'category',
+            labels: ['a', 'b', 'c', 'd', 'e']
+          }
+        }
+      }
+    });
+
+    const meta1 = chart.getDatasetMeta(0);
+    const parsedXValues1 = meta1._parsed.map(p => p.x);
+    const parsedYValues1 = meta1._parsed.map(p => p.y);
+
+    expect(meta1.data.length).toBe(6);
+    expect(parsedXValues1).toEqual([0, 1, 2, 3, 4, 5]); // label indices
+    expect(parsedYValues1).toEqual(data1);
+
+    const meta2 = chart.getDatasetMeta(1);
+    const parsedXValues2 = meta2._parsed.map(p => p.x);
+    const parsedYValues2 = meta2._parsed.map(p => p.y);
+
+    expect(meta2.data.length).toBe(5);
+    expect(parsedXValues2).toEqual([1, 10, 100, 1000, 2000]); // logarithmic scale labels
+    expect(parsedYValues2).toEqual([0, 1, 2, 3, 0]); // label indices
+  });
+
+  it('should parse using provided keys', function() {
+    const chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [
+            {x: 1, data: {key: 'one', value: 20}},
+            {data: {key: 'two', value: 30}}
+          ]
+        }]
+      },
+      options: {
+        parsing: {
+          xAxisKey: 'data.key',
+          yAxisKey: 'data.value'
+        },
+        scales: {
+          x: {
+            type: 'category',
+            labels: ['one', 'two']
+          },
+          y: {
+            type: 'linear'
+          },
+        }
+      }
+    });
+
+    const meta = chart.getDatasetMeta(0);
+    const parsedXValues = meta._parsed.map(p => p.x);
+    const parsedYValues = meta._parsed.map(p => p.y);
+
+    expect(meta.data.length).toBe(2);
+    expect(parsedXValues).toEqual([0, 1]); // label indices
+    expect(parsedYValues).toEqual([20, 30]);
+  });
+
+  it('should synchronize metadata when data are inserted or removed and parsing is on', function() {
+    const data = [0, 1, 2, 3, 4, 5];
+    const chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data
+        }]
+      }
+    });
+
+    const meta = chart.getDatasetMeta(0);
+    const parsedYValues = () => meta._parsed.map(p => p.y);
+    let first, second, last;
+
+    first = meta.data[0];
+    last = meta.data[5];
+    data.push(6, 7, 8);
+    data.push(9);
+    expect(meta.data.length).toBe(10);
+    expect(meta.data[0]).toBe(first);
+    expect(meta.data[5]).toBe(last);
+    expect(parsedYValues()).toEqual(data);
+
+    last = meta.data[9];
+    data.pop();
+    expect(meta.data.length).toBe(9);
+    expect(meta.data[0]).toBe(first);
+    expect(meta.data.indexOf(last)).toBe(-1);
+    expect(parsedYValues()).toEqual(data);
+
+    last = meta.data[8];
+    data.shift();
+    data.shift();
+    data.shift();
+    expect(meta.data.length).toBe(6);
+    expect(meta.data.indexOf(first)).toBe(-1);
+    expect(meta.data[5]).toBe(last);
+    expect(parsedYValues()).toEqual(data);
+
+    first = meta.data[0];
+    second = meta.data[1];
+    last = meta.data[5];
+    data.splice(1, 4, 10, 11);
+    expect(meta.data.length).toBe(4);
+    expect(meta.data[0]).toBe(first);
+    expect(meta.data[3]).toBe(last);
+    expect(meta.data.indexOf(second)).toBe(-1);
+    expect(parsedYValues()).toEqual(data);
+
+    data.unshift(12, 13, 14, 15);
+    data.unshift(16, 17);
+    expect(meta.data.length).toBe(10);
+    expect(meta.data[6]).toBe(first);
+    expect(meta.data[9]).toBe(last);
+    expect(parsedYValues()).toEqual(data);
+  });
+
+  it('should synchronize metadata when data are inserted or removed and parsing is off', function() {
+    var data = [{x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}, {x: 3, y: 3}, {x: 4, y: 4}, {x: 5, y: 5}];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data
+        }]
+      },
+      options: {
+        parsing: false,
+        scales: {
+          x: {type: 'linear'},
+          y: {type: 'linear'}
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    var controller = meta.controller;
+    var first, last;
+
+    first = controller.getParsed(0);
+    last = controller.getParsed(5);
+    data.push({x: 6, y: 6}, {x: 7, y: 7}, {x: 8, y: 8});
+    data.push({x: 9, y: 9});
+    expect(meta.data.length).toBe(10);
+    expect(controller.getParsed(0)).toBe(first);
+    expect(controller.getParsed(5)).toBe(last);
+
+    last = controller.getParsed(9);
+    data.pop();
+    expect(meta.data.length).toBe(9);
+    expect(controller.getParsed(0)).toBe(first);
+    expect(controller.getParsed(9)).toBe(undefined);
+    expect(controller.getParsed(8)).toEqual({x: 8, y: 8});
+
+    last = controller.getParsed(8);
+    data.shift();
+    data.shift();
+    data.shift();
+    expect(meta.data.length).toBe(6);
+    expect(controller.getParsed(5)).toBe(last);
+
+    first = controller.getParsed(0);
+    last = controller.getParsed(5);
+    data.splice(1, 4, {x: 10, y: 10}, {x: 11, y: 11});
+    expect(meta.data.length).toBe(4);
+    expect(controller.getParsed(0)).toBe(first);
+    expect(controller.getParsed(3)).toBe(last);
+    expect(controller.getParsed(1)).toEqual({x: 10, y: 10});
+
+    data.unshift({x: 12, y: 12}, {x: 13, y: 13}, {x: 14, y: 14}, {x: 15, y: 15});
+    data.unshift({x: 16, y: 16}, {x: 17, y: 17});
+    expect(meta.data.length).toBe(10);
+    expect(controller.getParsed(6)).toBe(first);
+    expect(controller.getParsed(9)).toBe(last);
+  });
+
+  it('should re-synchronize metadata when the data object reference changes', function() {
+    var data0 = [0, 1, 2, 3, 4, 5];
+    var data1 = [6, 7, 8];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data0
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(6);
+    expect(meta._parsed.map(p => p.y)).toEqual(data0);
+
+    chart.data.datasets[0].data = data1;
+    chart.update();
+
+    expect(meta.data.length).toBe(3);
+    expect(meta._parsed.map(p => p.y)).toEqual(data1);
+
+    data1.push(9);
+    expect(meta.data.length).toBe(4);
+
+    chart.data.datasets[0].data = data0;
+    chart.update();
+
+    expect(meta.data.length).toBe(6);
+    expect(meta._parsed.map(p => p.y)).toEqual(data0);
+  });
+
+  it('should re-synchronize metadata when data are unusually altered', function() {
+    var data = [0, 1, 2, 3, 4, 5];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(6);
+
+    data.length = 2;
+    chart.update();
+
+    expect(meta.data.length).toBe(2);
+
+    data.length = 42;
+    chart.update();
+
+    expect(meta.data.length).toBe(42);
+  });
+
+  // https://github.com/chartjs/Chart.js/issues/7243
+  it('should re-synchronize metadata when data is moved and values are equal', function() {
+    var data = [10, 10, 10, 10, 10, 10];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        labels: ['a', 'b', 'c', 'd', 'e', 'f'],
+        datasets: [{
+          data,
+          fill: true
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(6);
+    const firstX = meta.data[0].x;
+
+    data.push(data.shift());
+    chart.update();
+
+    expect(meta.data.length).toBe(6);
+    expect(meta.data[0].x).toEqual(firstX);
+  });
+
+  // https://github.com/chartjs/Chart.js/issues/7445
+  it('should re-synchronize metadata when data is objects and directly altered', function() {
+    var data = [{x: 'a', y: 1}, {x: 'b', y: 2}, {x: 'c', y: 3}];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        labels: ['a', 'b', 'c'],
+        datasets: [{
+          data,
+          fill: true
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.data.length).toBe(3);
+    const y3 = meta.data[2].y;
+
+    data[0].y = 3;
+    chart.update();
+    expect(meta.data[0].y).toEqual(y3);
+  });
+
+  it('should re-synchronize metadata when scaleID changes', function() {
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [],
+          xAxisID: 'firstXScaleID',
+          yAxisID: 'firstYScaleID',
+        }]
+      },
+      options: {
+        scales: {
+          firstXScaleID: {
+            type: 'category',
+            position: 'bottom'
+          },
+          secondXScaleID: {
+            type: 'category',
+            position: 'bottom'
+          },
+          firstYScaleID: {
+            type: 'linear',
+            position: 'left'
+          },
+          secondYScaleID: {
+            type: 'linear',
+            position: 'left'
+          },
+        }
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+
+    expect(meta.xAxisID).toBe('firstXScaleID');
+    expect(meta.yAxisID).toBe('firstYScaleID');
+
+    chart.data.datasets[0].xAxisID = 'secondXScaleID';
+    chart.data.datasets[0].yAxisID = 'secondYScaleID';
+    chart.update();
+
+    expect(meta.xAxisID).toBe('secondXScaleID');
+    expect(meta.yAxisID).toBe('secondYScaleID');
+  });
+
+  it('should re-synchronize stacks when stack is changed', function() {
+    var chart = acquireChart({
+      type: 'bar',
+      data: {
+        labels: ['a', 'b'],
+        datasets: [{
+          data: [1, 10],
+          stack: '1'
+        }, {
+          data: [2, 20],
+          stack: '2'
+        }, {
+          data: [3, 30],
+          stack: '1'
+        }]
+      }
+    });
+
+    expect(chart._stacks).toEqual({
+      'x.y.1.bar': {
+        0: {0: 1, 2: 3},
+        1: {0: 10, 2: 30}
+      },
+      'x.y.2.bar': {
+        0: {1: 2},
+        1: {1: 20}
+      }
+    });
+
+    chart.data.datasets[2].stack = '2';
+    chart.update();
+
+    expect(chart._stacks).toEqual({
+      'x.y.1.bar': {
+        0: {0: 1},
+        1: {0: 10}
+      },
+      'x.y.2.bar': {
+        0: {1: 2, 2: 3},
+        1: {1: 20, 2: 30}
+      }
+    });
+  });
+
+  it('should re-synchronize stacks when data is removed', function() {
+    var chart = acquireChart({
+      type: 'bar',
+      data: {
+        labels: ['a', 'b'],
+        datasets: [{
+          data: [1, 10],
+          stack: '1'
+        }, {
+          data: [2, 20],
+          stack: '2'
+        }, {
+          data: [3, 30],
+          stack: '1'
+        }]
+      }
+    });
+
+    expect(chart._stacks).toEqual({
+      'x.y.1.bar': {
+        0: {0: 1, 2: 3},
+        1: {0: 10, 2: 30}
+      },
+      'x.y.2.bar': {
+        0: {1: 2},
+        1: {1: 20}
+      }
+    });
+
+    chart.data.datasets[2].data = [4];
+    chart.update();
+
+    expect(chart._stacks).toEqual({
+      'x.y.1.bar': {
+        0: {0: 1, 2: 4},
+        1: {0: 10}
+      },
+      'x.y.2.bar': {
+        0: {1: 2},
+        1: {1: 20}
+      }
+    });
+  });
+
+  it('should cleanup attached properties when the reference changes or when the chart is destroyed', function() {
+    var data0 = [0, 1, 2, 3, 4, 5];
+    var data1 = [6, 7, 8];
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data0
+        }]
+      }
+    });
+
+    var hooks = ['push', 'pop', 'shift', 'splice', 'unshift'];
+
+    expect(data0._chartjs).toBeDefined();
+    hooks.forEach(function(hook) {
+      expect(data0[hook]).not.toBe(Array.prototype[hook]);
+    });
+
+    expect(data1._chartjs).not.toBeDefined();
+    hooks.forEach(function(hook) {
+      expect(data1[hook]).toBe(Array.prototype[hook]);
+    });
+
+    chart.data.datasets[0].data = data1;
+    chart.update();
+
+    expect(data0._chartjs).not.toBeDefined();
+    hooks.forEach(function(hook) {
+      expect(data0[hook]).toBe(Array.prototype[hook]);
+    });
+
+    expect(data1._chartjs).toBeDefined();
+    hooks.forEach(function(hook) {
+      expect(data1[hook]).not.toBe(Array.prototype[hook]);
+    });
+
+    chart.destroy();
+
+    expect(data1._chartjs).not.toBeDefined();
+    hooks.forEach(function(hook) {
+      expect(data1[hook]).toBe(Array.prototype[hook]);
+    });
+  });
+
+  it('should resolve data element options to the default color', function() {
+    var data0 = [0, 1, 2, 3, 4, 5];
+    var oldColor = Chart.defaults.borderColor;
+    Chart.defaults.borderColor = 'red';
+    var chart = acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: data0
+        }]
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    expect(meta.dataset.options.borderColor).toBe('red');
+    expect(meta.data[0].options.borderColor).toBe('red');
+
+    // Reset old shared state
+    Chart.defaults.borderColor = oldColor;
+  });
+
+  describe('_resolveOptions', function() {
+    it('should resove names in array notation', function() {
+      Chart.defaults.elements.line.globalTest = 'global';
+
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1],
+            datasetTest: 'dataset'
+          }]
+        },
+        options: {
+          elements: {
+            line: {
+              elementTest: 'element'
+            }
+          }
+        }
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller._resolveOptions(
+        [
+          'datasetTest',
+          'elementTest',
+          'globalTest'
+        ],
+        {type: 'line'})
+      ).toEqual({
+        datasetTest: 'dataset',
+        elementTest: 'element',
+        globalTest: 'global'
+      });
+
+      // Remove test from global defaults
+      delete Chart.defaults.elements.line.globalTest;
+    });
+
+    it('should resove names in object notation', function() {
+      Chart.defaults.elements.line.global = 'global';
+
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1],
+            datasetTest: 'dataset'
+          }]
+        },
+        options: {
+          elements: {
+            line: {
+              element: 'element'
+            }
+          }
+        }
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller._resolveOptions(
+        {
+          dataset: 'datasetTest',
+          element: 'elementTest',
+          global: 'globalTest'},
+        {type: 'line'})
+      ).toEqual({
+        dataset: 'dataset',
+        element: 'element',
+        global: 'global'
+      });
+
+      // Remove test from global defaults
+      delete Chart.defaults.elements.line.global;
+    });
+  });
+
+  describe('resolveDataElementOptions', function() {
+    it('should cache options when possible', function() {
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1, 2, 3],
+          }]
+        },
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller.enableOptionSharing).toBeTrue();
+
+      const opts0 = controller.resolveDataElementOptions(0);
+      const opts1 = controller.resolveDataElementOptions(1);
+
+      expect(opts0 === opts1).toBeTrue();
+      expect(opts0.$shared).toBeTrue();
+      expect(Object.isFrozen(opts0)).toBeTrue();
+    });
+
+    it('should not cache options when option sharing is disabled', function() {
+      const chart = acquireChart({
+        type: 'radar',
+        data: {
+          datasets: [{
+            data: [1, 2, 3],
+          }]
+        },
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller.enableOptionSharing).toBeFalse();
+
+      const opts0 = controller.resolveDataElementOptions(0);
+      const opts1 = controller.resolveDataElementOptions(1);
+
+      expect(opts0 === opts1).toBeFalse();
+      expect(opts0.$shared).not.toBeTrue();
+      expect(Object.isFrozen(opts0)).toBeFalse();
+    });
+
+    it('should not cache options when functions are used', function() {
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1, 2, 3],
+            backgroundColor: () => 'red'
+          }]
+        },
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      const opts0 = controller.resolveDataElementOptions(0);
+      const opts1 = controller.resolveDataElementOptions(1);
+
+      expect(opts0 === opts1).toBeFalse();
+      expect(opts0.$shared).not.toBeTrue();
+      expect(Object.isFrozen(opts0)).toBeFalse();
+    });
+  });
+
+  describe('_resolveAnimations', function() {
+    it('should resolve to empty Animations when globally disabled', function() {
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1],
+            animation: {
+              test: {duration: 10}
+            }
+          }]
+        },
+        options: {
+          animation: false
+        }
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller._resolveAnimations(0)._properties.size).toEqual(0);
+    });
+
+    it('should resolve to empty Animations when disabled at dataset level', function() {
+      const chart = acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: [1],
+            animation: false
+          }]
+        }
+      });
+
+      const controller = chart.getDatasetMeta(0).controller;
+
+      expect(controller._resolveAnimations(0)._properties.size).toEqual(0);
+    });
+  });
 });
index 9c1a7152814bea542efef0e8d742589a0d657dc3..5b22439bc619ef654730a8be1a535d1b0b9b9685 100644 (file)
@@ -1,38 +1,38 @@
 describe('Chart.defaults', function() {
-       describe('.set', function() {
-               it('Should set defaults directly to root when scope is not provided', function() {
-                       expect(Chart.defaults.test).toBeUndefined();
-                       Chart.defaults.set({test: true});
-                       expect(Chart.defaults.test).toEqual(true);
-                       delete Chart.defaults.test;
-               });
+  describe('.set', function() {
+    it('Should set defaults directly to root when scope is not provided', function() {
+      expect(Chart.defaults.test).toBeUndefined();
+      Chart.defaults.set({test: true});
+      expect(Chart.defaults.test).toEqual(true);
+      delete Chart.defaults.test;
+    });
 
-               it('Should create scope when it does not exist', function() {
-                       expect(Chart.defaults.test).toBeUndefined();
-                       Chart.defaults.set('test', {value: true});
-                       expect(Chart.defaults.test.value).toEqual(true);
-                       delete Chart.defaults.test;
-               });
-       });
+    it('Should create scope when it does not exist', function() {
+      expect(Chart.defaults.test).toBeUndefined();
+      Chart.defaults.set('test', {value: true});
+      expect(Chart.defaults.test.value).toEqual(true);
+      delete Chart.defaults.test;
+    });
+  });
 
-       describe('.route', function() {
-               it('Should read the source, but not change it', function() {
-                       expect(Chart.defaults.testscope).toBeUndefined();
+  describe('.route', function() {
+    it('Should read the source, but not change it', function() {
+      expect(Chart.defaults.testscope).toBeUndefined();
 
-                       Chart.defaults.set('testscope', {test: true});
-                       Chart.defaults.route('testscope', 'test2', 'testscope', 'test');
+      Chart.defaults.set('testscope', {test: true});
+      Chart.defaults.route('testscope', 'test2', 'testscope', 'test');
 
-                       expect(Chart.defaults.testscope.test).toEqual(true);
-                       expect(Chart.defaults.testscope.test2).toEqual(true);
+      expect(Chart.defaults.testscope.test).toEqual(true);
+      expect(Chart.defaults.testscope.test2).toEqual(true);
 
-                       Chart.defaults.set('testscope', {test2: false});
-                       expect(Chart.defaults.testscope.test).toEqual(true);
-                       expect(Chart.defaults.testscope.test2).toEqual(false);
+      Chart.defaults.set('testscope', {test2: false});
+      expect(Chart.defaults.testscope.test).toEqual(true);
+      expect(Chart.defaults.testscope.test2).toEqual(false);
 
-                       Chart.defaults.set('testscope', {test2: undefined});
-                       expect(Chart.defaults.testscope.test2).toEqual(true);
+      Chart.defaults.set('testscope', {test2: undefined});
+      expect(Chart.defaults.testscope.test2).toEqual(true);
 
-                       delete Chart.defaults.testscope;
-               });
-       });
+      delete Chart.defaults.testscope;
+    });
+  });
 });
index e3f0f1aba55e61e9698469985a8d7d66053d5a1f..07e8adbf0738c2de0a40144d2ab6b5bebae8a9f2 100644 (file)
@@ -1,16 +1,16 @@
 describe('Chart.element', function() {
-       describe('getProps', function() {
-               it('should return requested properties', function() {
-                       const elem = new Chart.Element();
-                       elem.x = 10;
-                       elem.y = 1.5;
+  describe('getProps', function() {
+    it('should return requested properties', function() {
+      const elem = new Chart.Element();
+      elem.x = 10;
+      elem.y = 1.5;
 
-                       expect(elem.getProps(['x', 'y'])).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
-                       expect(elem.getProps(['x', 'y'], true)).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
+      expect(elem.getProps(['x', 'y'])).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
+      expect(elem.getProps(['x', 'y'], true)).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
 
-                       elem.$animations = {x: {active: () => true, _to: 20}};
-                       expect(elem.getProps(['x', 'y'])).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
-                       expect(elem.getProps(['x', 'y'], true)).toEqual(jasmine.objectContaining({x: 20, y: 1.5}));
-               });
-       });
+      elem.$animations = {x: {active: () => true, _to: 20}};
+      expect(elem.getProps(['x', 'y'])).toEqual(jasmine.objectContaining({x: 10, y: 1.5}));
+      expect(elem.getProps(['x', 'y'], true)).toEqual(jasmine.objectContaining({x: 20, y: 1.5}));
+    });
+  });
 });
index d48a3a06184de64a3dae71f4b7647c1c504362fe..30dcb98bff60b6e3425d2104b4c134c7d9c83cce 100644 (file)
@@ -1,24 +1,24 @@
 describe('Core helper tests', function() {
 
-       var helpers;
+  var helpers;
 
-       beforeAll(function() {
-               helpers = window.Chart.helpers;
-       });
+  beforeAll(function() {
+    helpers = window.Chart.helpers;
+  });
 
-       it('should generate integer ids', function() {
-               var uid = helpers.uid();
-               expect(uid).toEqual(jasmine.any(Number));
-               expect(helpers.uid()).toBe(uid + 1);
-               expect(helpers.uid()).toBe(uid + 2);
-               expect(helpers.uid()).toBe(uid + 3);
-       });
+  it('should generate integer ids', function() {
+    var uid = helpers.uid();
+    expect(uid).toEqual(jasmine.any(Number));
+    expect(helpers.uid()).toBe(uid + 1);
+    expect(helpers.uid()).toBe(uid + 2);
+    expect(helpers.uid()).toBe(uid + 3);
+  });
 
-       describe('clone', function() {
-               it('should not allow prototype pollution', function() {
-                       const test = helpers.clone(JSON.parse('{"__proto__":{"polluted": true}}'));
-                       expect(test.prototype).toBeUndefined();
-                       expect(Object.prototype.polluted).toBeUndefined();
-               });
-       });
+  describe('clone', function() {
+    it('should not allow prototype pollution', function() {
+      const test = helpers.clone(JSON.parse('{"__proto__":{"polluted": true}}'));
+      expect(test.prototype).toBeUndefined();
+      expect(Object.prototype.polluted).toBeUndefined();
+    });
+  });
 });
index 0f3504fb20134def06176e7981a273e961bcb77f..a3ce810db7f6c1c882674bc69332620a0177fda0 100644 (file)
 
 // Test the rectangle element
 describe('Core.Interaction', function() {
-       describe('point mode', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 20, 40],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               }
-                       });
-               });
-
-               it ('should return all items under the point', function() {
-                       var chart = this.chart;
-                       var meta0 = chart.getDatasetMeta(0);
-                       var meta1 = chart.getDatasetMeta(1);
-                       var point = meta0.data[1];
-
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: point.x,
-                               y: point.y,
-                       };
-
-                       var elements = Chart.Interaction.modes.point(chart, evt, {}).map(item => item.element);
-                       expect(elements).toEqual([point, meta1.data[1]]);
-               });
-
-               it ('should return an empty array when no items are found', function() {
-                       var chart = this.chart;
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: 0,
-                               y: 0
-                       };
-
-                       var elements = Chart.Interaction.modes.point(chart, evt, {}).map(item => item.element);
-                       expect(elements).toEqual([]);
-               });
-       });
-
-       describe('index mode', function() {
-               describe('intersect: true', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       label: 'Dataset 1',
-                                                       data: [10, 20, 30],
-                                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                               }, {
-                                                       label: 'Dataset 2',
-                                                       data: [40, 40, 40],
-                                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                               }],
-                                               labels: ['Point 1', 'Point 2', 'Point 3']
-                                       }
-                               });
-                       });
-
-                       it ('gets correct items', function() {
-                               var chart = this.chart;
-                               var meta0 = chart.getDatasetMeta(0);
-                               var meta1 = chart.getDatasetMeta(1);
-                               var point = meta0.data[1];
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: point.x,
-                                       y: point.y,
-                               };
-
-                               var elements = Chart.Interaction.modes.index(chart, evt, {intersect: true}).map(item => item.element);
-                               expect(elements).toEqual([point, meta1.data[1]]);
-                       });
-
-                       it ('returns empty array when nothing found', function() {
-                               var chart = this.chart;
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: 0,
-                                       y: 0,
-                               };
-
-                               var elements = Chart.Interaction.modes.index(chart, evt, {intersect: true}).map(item => item.element);
-                               expect(elements).toEqual([]);
-                       });
-               });
-
-               describe ('intersect: false', function() {
-                       var data = {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       };
-
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: data
-                               });
-                       });
-
-                       it ('axis: x gets correct items', function() {
-                               var chart = this.chart;
-                               var meta0 = chart.getDatasetMeta(0);
-                               var meta1 = chart.getDatasetMeta(1);
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: chart.chartArea.left,
-                                       y: chart.chartArea.top
-                               };
-
-                               var elements = Chart.Interaction.modes.index(chart, evt, {intersect: false}).map(item => item.element);
-                               expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
-                       });
-
-                       it ('axis: y gets correct items', function() {
-                               var chart = window.acquireChart({
-                                       type: 'bar',
-                                       data: data,
-                                       options: {
-                                               indexAxis: 'y',
-                                       }
-                               });
-
-                               var meta0 = chart.getDatasetMeta(0);
-                               var meta1 = chart.getDatasetMeta(1);
-                               var center = meta0.data[0].getCenterPoint();
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: center.x,
-                                       y: center.y + 30,
-                               };
-
-                               var elements = Chart.Interaction.modes.index(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
-                               expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
-                       });
-
-                       it ('axis: xy gets correct items', function() {
-                               var chart = this.chart;
-                               var meta0 = chart.getDatasetMeta(0);
-                               var meta1 = chart.getDatasetMeta(1);
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: chart.chartArea.left,
-                                       y: chart.chartArea.top
-                               };
-
-                               var elements = Chart.Interaction.modes.index(chart, evt, {axis: 'xy', intersect: false}).map(item => item.element);
-                               expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
-                       });
-               });
-       });
-
-       describe('dataset mode', function() {
-               describe('intersect: true', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       label: 'Dataset 1',
-                                                       data: [10, 20, 30],
-                                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                               }, {
-                                                       label: 'Dataset 2',
-                                                       data: [40, 40, 40],
-                                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                               }],
-                                               labels: ['Point 1', 'Point 2', 'Point 3']
-                                       }
-                               });
-                       });
-
-                       it ('should return all items in the dataset of the first item found', function() {
-                               var chart = this.chart;
-                               var meta = chart.getDatasetMeta(0);
-                               var point = meta.data[1];
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: point.x,
-                                       y: point.y
-                               };
-
-                               var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: true}).map(item => item.element);
-                               expect(elements).toEqual(meta.data);
-                       });
-
-                       it ('should return an empty array if nothing found', function() {
-                               var chart = this.chart;
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: 0,
-                                       y: 0
-                               };
-
-                               var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: true});
-                               expect(elements).toEqual([]);
-                       });
-               });
-
-               describe('intersect: false', function() {
-                       var data = {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       };
-
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: data
-                               });
-                       });
-
-                       it ('axis: x gets correct items', function() {
-                               var chart = window.acquireChart({
-                                       type: 'bar',
-                                       data: data,
-                                       options: {
-                                               indexAxis: 'y',
-                                       }
-                               });
-
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: chart.chartArea.left,
-                                       y: chart.chartArea.top
-                               };
-
-                               var elements = Chart.Interaction.modes.dataset(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
-                               expect(elements).toEqual(chart.getDatasetMeta(0).data);
-                       });
-
-                       it ('axis: y gets correct items', function() {
-                               var chart = this.chart;
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: chart.chartArea.left,
-                                       y: chart.chartArea.top
-                               };
-
-                               var elements = Chart.Interaction.modes.dataset(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
-                               expect(elements).toEqual(chart.getDatasetMeta(1).data);
-                       });
-
-                       it ('axis: xy gets correct items', function() {
-                               var chart = this.chart;
-                               var evt = {
-                                       type: 'click',
-                                       chart: chart,
-                                       native: true, // needed otherwise things its a DOM event
-                                       x: chart.chartArea.left,
-                                       y: chart.chartArea.top
-                               };
-
-                               var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: false}).map(item => item.element);
-                               expect(elements).toEqual(chart.getDatasetMeta(1).data);
-                       });
-               });
-       });
-
-       describe('nearest mode', function() {
-               describe('intersect: false', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       label: 'Dataset 1',
-                                                       data: [10, 40, 30],
-                                                       pointRadius: [5, 5, 5],
-                                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                               }, {
-                                                       label: 'Dataset 2',
-                                                       data: [40, 40, 40],
-                                                       pointRadius: [10, 10, 10],
-                                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                               }],
-                                               labels: ['Point 1', 'Point 2', 'Point 3']
-                                       }
-                               });
-                       });
-
-                       describe('axis: xy', function() {
-                               it ('should return the nearest item', function() {
-                                       var chart = this.chart;
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: chart.chartArea.left,
-                                               y: chart.chartArea.top
-                                       };
-
-                                       // Nearest to 0,0 (top left) will be first point of dataset 2
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: false}).map(item => item.element);
-                                       var meta = chart.getDatasetMeta(1);
-                                       expect(elements).toEqual([meta.data[0]]);
-                               });
-
-                               it ('should return all items at the same nearest distance', function() {
-                                       var chart = this.chart;
-                                       var meta0 = chart.getDatasetMeta(0);
-                                       var meta1 = chart.getDatasetMeta(1);
-
-                                       // Halfway between 2 mid points
-                                       var pt = {
-                                               x: meta0.data[1].x,
-                                               y: (meta0.data[1].y + meta1.data[1].y) / 2
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       // Both points are nearest
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: false}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
-                               });
-                       });
-
-                       describe('axis: x', function() {
-                               it ('should return all items at current x', function() {
-                                       var chart = this.chart;
-                                       var meta0 = chart.getDatasetMeta(0);
-                                       var meta1 = chart.getDatasetMeta(1);
-
-                                       // At 'Point 2', 10
-                                       var pt = {
-                                               x: meta0.data[1].x,
-                                               y: meta0.data[0].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       // Middle point from both series are nearest
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
-                               });
-
-                               it ('should return all items at nearest x-distance', function() {
-                                       var chart = this.chart;
-                                       var meta0 = chart.getDatasetMeta(0);
-                                       var meta1 = chart.getDatasetMeta(1);
-
-                                       // Haflway between 'Point 1' and 'Point 2', y=10
-                                       var pt = {
-                                               x: (meta0.data[0].x + meta0.data[1].x) / 2,
-                                               y: meta0.data[0].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       // Should return all (4) points from 'Point 1' and 'Point 2'
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[0], meta0.data[1], meta1.data[0], meta1.data[1]]);
-                               });
-                       });
-
-                       describe('axis: y', function() {
-                               it ('should return item with value 30', function() {
-                                       var chart = this.chart;
-                                       var meta0 = chart.getDatasetMeta(0);
-
-                                       // 'Point 1', y = 30
-                                       var pt = {
-                                               x: meta0.data[0].x,
-                                               y: meta0.data[2].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       // Middle point from both series are nearest
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[2]]);
-                               });
-
-                               it ('should return all items at value 40', function() {
-                                       var chart = this.chart;
-                                       var meta0 = chart.getDatasetMeta(0);
-                                       var meta1 = chart.getDatasetMeta(1);
-
-                                       // 'Point 1', y = 40
-                                       var pt = {
-                                               x: meta0.data[0].x,
-                                               y: meta0.data[1].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       // Should return points with value 40
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
-                               });
-                       });
-               });
-
-               describe('intersect: true', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       label: 'Dataset 1',
-                                                       data: [10, 20, 30],
-                                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                               }, {
-                                                       label: 'Dataset 2',
-                                                       data: [40, 40, 40],
-                                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                               }],
-                                               labels: ['Point 1', 'Point 2', 'Point 3']
-                                       }
-                               });
-                       });
-
-                       describe('axis=xy', function() {
-                               it ('should return the nearest item', function() {
-                                       var chart = this.chart;
-                                       var meta = chart.getDatasetMeta(1);
-                                       var point = meta.data[1];
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: point.x + 15,
-                                               y: point.y
-                                       };
-
-                                       // Nothing intersects so find nothing
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
-                                       expect(elements).toEqual([]);
-
-                                       evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true,
-                                               x: point.x,
-                                               y: point.y
-                                       };
-                                       elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
-                                       expect(elements).toEqual([point]);
-                               });
-
-                               it ('should return the nearest item even if 2 intersect', function() {
-                                       var chart = this.chart;
-                                       chart.data.datasets[0].pointRadius = [5, 30, 5];
-                                       chart.data.datasets[0].data[1] = 39;
-
-                                       chart.data.datasets[1].pointRadius = [10, 10, 10];
-
-                                       chart.update();
-
-                                       // Trigger an event over top of the
-                                       var meta0 = chart.getDatasetMeta(0);
-
-                                       // Halfway between 2 mid points
-                                       var pt = {
-                                               x: meta0.data[1].x,
-                                               y: meta0.data[1].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[1]]);
-                               });
-
-                               it ('should return the all items if more than 1 are at the same distance', function() {
-                                       var chart = this.chart;
-                                       chart.data.datasets[0].pointRadius = [5, 5, 5];
-                                       chart.data.datasets[0].data[1] = 40;
-
-                                       chart.data.datasets[1].pointRadius = [10, 10, 10];
-
-                                       chart.update();
-
-                                       var meta0 = chart.getDatasetMeta(0);
-                                       var meta1 = chart.getDatasetMeta(1);
-
-                                       // Halfway between 2 mid points
-                                       var pt = {
-                                               x: meta0.data[1].x,
-                                               y: meta0.data[1].y
-                                       };
-
-                                       var evt = {
-                                               type: 'click',
-                                               chart: chart,
-                                               native: true, // needed otherwise things its a DOM event
-                                               x: pt.x,
-                                               y: pt.y
-                                       };
-
-                                       var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
-                                       expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
-                               });
-                       });
-               });
-       });
-
-       describe('x mode', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 40, 30],
-                                               pointRadius: [5, 10, 5],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointRadius: [10, 10, 10],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               }
-                       });
-               });
-
-               it('should return items at the same x value when intersect is false', function() {
-                       var chart = this.chart;
-                       var meta0 = chart.getDatasetMeta(0);
-                       var meta1 = chart.getDatasetMeta(1);
-
-                       // Halfway between 2 mid points
-                       var pt = {
-                               x: meta0.data[1].x,
-                               y: meta0.data[1].y
-                       };
-
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: pt.x,
-                               y: 0
-                       };
-
-                       var elements = Chart.Interaction.modes.x(chart, evt, {intersect: false}).map(item => item.element);
-                       expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
-
-                       evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: pt.x + 20,
-                               y: 0
-                       };
-
-                       elements = Chart.Interaction.modes.x(chart, evt, {intersect: false}).map(item => item.element);
-                       expect(elements).toEqual([]);
-               });
-
-               it('should return items at the same x value when intersect is true', function() {
-                       var chart = this.chart;
-                       var meta0 = chart.getDatasetMeta(0);
-                       var meta1 = chart.getDatasetMeta(1);
-
-                       // Halfway between 2 mid points
-                       var pt = {
-                               x: meta0.data[1].x,
-                               y: meta0.data[1].y
-                       };
-
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: pt.x,
-                               y: 0
-                       };
-
-                       var elements = Chart.Interaction.modes.x(chart, evt, {intersect: true}).map(item => item.element);
-                       expect(elements).toEqual([]); // we don't intersect anything
-
-                       evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true, // needed otherwise things its a DOM event
-                               x: pt.x,
-                               y: pt.y
-                       };
-
-                       elements = Chart.Interaction.modes.x(chart, evt, {intersect: true}).map(item => item.element);
-                       expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
-               });
-       });
-
-       describe('y mode', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 40, 30],
-                                               pointRadius: [5, 10, 5],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointRadius: [10, 10, 10],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               }
-                       });
-               });
-
-               it('should return items at the same y value when intersect is false', function() {
-                       var chart = this.chart;
-                       var meta0 = chart.getDatasetMeta(0);
-                       var meta1 = chart.getDatasetMeta(1);
-
-                       // Halfway between 2 mid points
-                       var pt = {
-                               x: meta0.data[1].x,
-                               y: meta0.data[1].y
-                       };
-
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true,
-                               x: 0,
-                               y: pt.y,
-                       };
-
-                       var elements = Chart.Interaction.modes.y(chart, evt, {intersect: false}).map(item => item.element);
-                       expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
-
-                       evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true,
-                               x: pt.x,
-                               y: pt.y + 20, // out of range
-                       };
-
-                       elements = Chart.Interaction.modes.y(chart, evt, {intersect: false}).map(item => item.element);
-                       expect(elements).toEqual([]);
-               });
-
-               it('should return items at the same y value when intersect is true', function() {
-                       var chart = this.chart;
-                       var meta0 = chart.getDatasetMeta(0);
-                       var meta1 = chart.getDatasetMeta(1);
-
-                       // Halfway between 2 mid points
-                       var pt = {
-                               x: meta0.data[1].x,
-                               y: meta0.data[1].y
-                       };
-
-                       var evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true,
-                               x: 0,
-                               y: pt.y
-                       };
-
-                       var elements = Chart.Interaction.modes.y(chart, evt, {intersect: true}).map(item => item.element);
-                       expect(elements).toEqual([]); // we don't intersect anything
-
-                       evt = {
-                               type: 'click',
-                               chart: chart,
-                               native: true,
-                               x: pt.x,
-                               y: pt.y,
-                       };
-
-                       elements = Chart.Interaction.modes.y(chart, evt, {intersect: true}).map(item => item.element);
-                       expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
-               });
-       });
+  describe('point mode', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 20, 40],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        }
+      });
+    });
+
+    it ('should return all items under the point', function() {
+      var chart = this.chart;
+      var meta0 = chart.getDatasetMeta(0);
+      var meta1 = chart.getDatasetMeta(1);
+      var point = meta0.data[1];
+
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: point.x,
+        y: point.y,
+      };
+
+      var elements = Chart.Interaction.modes.point(chart, evt, {}).map(item => item.element);
+      expect(elements).toEqual([point, meta1.data[1]]);
+    });
+
+    it ('should return an empty array when no items are found', function() {
+      var chart = this.chart;
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: 0,
+        y: 0
+      };
+
+      var elements = Chart.Interaction.modes.point(chart, evt, {}).map(item => item.element);
+      expect(elements).toEqual([]);
+    });
+  });
+
+  describe('index mode', function() {
+    describe('intersect: true', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              label: 'Dataset 1',
+              data: [10, 20, 30],
+              pointHoverBorderColor: 'rgb(255, 0, 0)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+            }, {
+              label: 'Dataset 2',
+              data: [40, 40, 40],
+              pointHoverBorderColor: 'rgb(0, 0, 255)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+            }],
+            labels: ['Point 1', 'Point 2', 'Point 3']
+          }
+        });
+      });
+
+      it ('gets correct items', function() {
+        var chart = this.chart;
+        var meta0 = chart.getDatasetMeta(0);
+        var meta1 = chart.getDatasetMeta(1);
+        var point = meta0.data[1];
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: point.x,
+          y: point.y,
+        };
+
+        var elements = Chart.Interaction.modes.index(chart, evt, {intersect: true}).map(item => item.element);
+        expect(elements).toEqual([point, meta1.data[1]]);
+      });
+
+      it ('returns empty array when nothing found', function() {
+        var chart = this.chart;
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: 0,
+          y: 0,
+        };
+
+        var elements = Chart.Interaction.modes.index(chart, evt, {intersect: true}).map(item => item.element);
+        expect(elements).toEqual([]);
+      });
+    });
+
+    describe ('intersect: false', function() {
+      var data = {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      };
+
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: data
+        });
+      });
+
+      it ('axis: x gets correct items', function() {
+        var chart = this.chart;
+        var meta0 = chart.getDatasetMeta(0);
+        var meta1 = chart.getDatasetMeta(1);
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: chart.chartArea.left,
+          y: chart.chartArea.top
+        };
+
+        var elements = Chart.Interaction.modes.index(chart, evt, {intersect: false}).map(item => item.element);
+        expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
+      });
+
+      it ('axis: y gets correct items', function() {
+        var chart = window.acquireChart({
+          type: 'bar',
+          data: data,
+          options: {
+            indexAxis: 'y',
+          }
+        });
+
+        var meta0 = chart.getDatasetMeta(0);
+        var meta1 = chart.getDatasetMeta(1);
+        var center = meta0.data[0].getCenterPoint();
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: center.x,
+          y: center.y + 30,
+        };
+
+        var elements = Chart.Interaction.modes.index(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
+        expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
+      });
+
+      it ('axis: xy gets correct items', function() {
+        var chart = this.chart;
+        var meta0 = chart.getDatasetMeta(0);
+        var meta1 = chart.getDatasetMeta(1);
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: chart.chartArea.left,
+          y: chart.chartArea.top
+        };
+
+        var elements = Chart.Interaction.modes.index(chart, evt, {axis: 'xy', intersect: false}).map(item => item.element);
+        expect(elements).toEqual([meta0.data[0], meta1.data[0]]);
+      });
+    });
+  });
+
+  describe('dataset mode', function() {
+    describe('intersect: true', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              label: 'Dataset 1',
+              data: [10, 20, 30],
+              pointHoverBorderColor: 'rgb(255, 0, 0)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+            }, {
+              label: 'Dataset 2',
+              data: [40, 40, 40],
+              pointHoverBorderColor: 'rgb(0, 0, 255)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+            }],
+            labels: ['Point 1', 'Point 2', 'Point 3']
+          }
+        });
+      });
+
+      it ('should return all items in the dataset of the first item found', function() {
+        var chart = this.chart;
+        var meta = chart.getDatasetMeta(0);
+        var point = meta.data[1];
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: point.x,
+          y: point.y
+        };
+
+        var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: true}).map(item => item.element);
+        expect(elements).toEqual(meta.data);
+      });
+
+      it ('should return an empty array if nothing found', function() {
+        var chart = this.chart;
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: 0,
+          y: 0
+        };
+
+        var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: true});
+        expect(elements).toEqual([]);
+      });
+    });
+
+    describe('intersect: false', function() {
+      var data = {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      };
+
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: data
+        });
+      });
+
+      it ('axis: x gets correct items', function() {
+        var chart = window.acquireChart({
+          type: 'bar',
+          data: data,
+          options: {
+            indexAxis: 'y',
+          }
+        });
+
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: chart.chartArea.left,
+          y: chart.chartArea.top
+        };
+
+        var elements = Chart.Interaction.modes.dataset(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
+        expect(elements).toEqual(chart.getDatasetMeta(0).data);
+      });
+
+      it ('axis: y gets correct items', function() {
+        var chart = this.chart;
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: chart.chartArea.left,
+          y: chart.chartArea.top
+        };
+
+        var elements = Chart.Interaction.modes.dataset(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
+        expect(elements).toEqual(chart.getDatasetMeta(1).data);
+      });
+
+      it ('axis: xy gets correct items', function() {
+        var chart = this.chart;
+        var evt = {
+          type: 'click',
+          chart: chart,
+          native: true, // needed otherwise things its a DOM event
+          x: chart.chartArea.left,
+          y: chart.chartArea.top
+        };
+
+        var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: false}).map(item => item.element);
+        expect(elements).toEqual(chart.getDatasetMeta(1).data);
+      });
+    });
+  });
+
+  describe('nearest mode', function() {
+    describe('intersect: false', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              label: 'Dataset 1',
+              data: [10, 40, 30],
+              pointRadius: [5, 5, 5],
+              pointHoverBorderColor: 'rgb(255, 0, 0)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+            }, {
+              label: 'Dataset 2',
+              data: [40, 40, 40],
+              pointRadius: [10, 10, 10],
+              pointHoverBorderColor: 'rgb(0, 0, 255)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+            }],
+            labels: ['Point 1', 'Point 2', 'Point 3']
+          }
+        });
+      });
+
+      describe('axis: xy', function() {
+        it ('should return the nearest item', function() {
+          var chart = this.chart;
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: chart.chartArea.left,
+            y: chart.chartArea.top
+          };
+
+          // Nearest to 0,0 (top left) will be first point of dataset 2
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: false}).map(item => item.element);
+          var meta = chart.getDatasetMeta(1);
+          expect(elements).toEqual([meta.data[0]]);
+        });
+
+        it ('should return all items at the same nearest distance', function() {
+          var chart = this.chart;
+          var meta0 = chart.getDatasetMeta(0);
+          var meta1 = chart.getDatasetMeta(1);
+
+          // Halfway between 2 mid points
+          var pt = {
+            x: meta0.data[1].x,
+            y: (meta0.data[1].y + meta1.data[1].y) / 2
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          // Both points are nearest
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: false}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
+        });
+      });
+
+      describe('axis: x', function() {
+        it ('should return all items at current x', function() {
+          var chart = this.chart;
+          var meta0 = chart.getDatasetMeta(0);
+          var meta1 = chart.getDatasetMeta(1);
+
+          // At 'Point 2', 10
+          var pt = {
+            x: meta0.data[1].x,
+            y: meta0.data[0].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          // Middle point from both series are nearest
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
+        });
+
+        it ('should return all items at nearest x-distance', function() {
+          var chart = this.chart;
+          var meta0 = chart.getDatasetMeta(0);
+          var meta1 = chart.getDatasetMeta(1);
+
+          // Haflway between 'Point 1' and 'Point 2', y=10
+          var pt = {
+            x: (meta0.data[0].x + meta0.data[1].x) / 2,
+            y: meta0.data[0].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          // Should return all (4) points from 'Point 1' and 'Point 2'
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'x', intersect: false}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[0], meta0.data[1], meta1.data[0], meta1.data[1]]);
+        });
+      });
+
+      describe('axis: y', function() {
+        it ('should return item with value 30', function() {
+          var chart = this.chart;
+          var meta0 = chart.getDatasetMeta(0);
+
+          // 'Point 1', y = 30
+          var pt = {
+            x: meta0.data[0].x,
+            y: meta0.data[2].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          // Middle point from both series are nearest
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[2]]);
+        });
+
+        it ('should return all items at value 40', function() {
+          var chart = this.chart;
+          var meta0 = chart.getDatasetMeta(0);
+          var meta1 = chart.getDatasetMeta(1);
+
+          // 'Point 1', y = 40
+          var pt = {
+            x: meta0.data[0].x,
+            y: meta0.data[1].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          // Should return points with value 40
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {axis: 'y', intersect: false}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
+        });
+      });
+    });
+
+    describe('intersect: true', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              label: 'Dataset 1',
+              data: [10, 20, 30],
+              pointHoverBorderColor: 'rgb(255, 0, 0)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+            }, {
+              label: 'Dataset 2',
+              data: [40, 40, 40],
+              pointHoverBorderColor: 'rgb(0, 0, 255)',
+              pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+            }],
+            labels: ['Point 1', 'Point 2', 'Point 3']
+          }
+        });
+      });
+
+      describe('axis=xy', function() {
+        it ('should return the nearest item', function() {
+          var chart = this.chart;
+          var meta = chart.getDatasetMeta(1);
+          var point = meta.data[1];
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: point.x + 15,
+            y: point.y
+          };
+
+          // Nothing intersects so find nothing
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
+          expect(elements).toEqual([]);
+
+          evt = {
+            type: 'click',
+            chart: chart,
+            native: true,
+            x: point.x,
+            y: point.y
+          };
+          elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
+          expect(elements).toEqual([point]);
+        });
+
+        it ('should return the nearest item even if 2 intersect', function() {
+          var chart = this.chart;
+          chart.data.datasets[0].pointRadius = [5, 30, 5];
+          chart.data.datasets[0].data[1] = 39;
+
+          chart.data.datasets[1].pointRadius = [10, 10, 10];
+
+          chart.update();
+
+          // Trigger an event over top of the
+          var meta0 = chart.getDatasetMeta(0);
+
+          // Halfway between 2 mid points
+          var pt = {
+            x: meta0.data[1].x,
+            y: meta0.data[1].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[1]]);
+        });
+
+        it ('should return the all items if more than 1 are at the same distance', function() {
+          var chart = this.chart;
+          chart.data.datasets[0].pointRadius = [5, 5, 5];
+          chart.data.datasets[0].data[1] = 40;
+
+          chart.data.datasets[1].pointRadius = [10, 10, 10];
+
+          chart.update();
+
+          var meta0 = chart.getDatasetMeta(0);
+          var meta1 = chart.getDatasetMeta(1);
+
+          // Halfway between 2 mid points
+          var pt = {
+            x: meta0.data[1].x,
+            y: meta0.data[1].y
+          };
+
+          var evt = {
+            type: 'click',
+            chart: chart,
+            native: true, // needed otherwise things its a DOM event
+            x: pt.x,
+            y: pt.y
+          };
+
+          var elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
+          expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
+        });
+      });
+    });
+  });
+
+  describe('x mode', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 40, 30],
+            pointRadius: [5, 10, 5],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointRadius: [10, 10, 10],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        }
+      });
+    });
+
+    it('should return items at the same x value when intersect is false', function() {
+      var chart = this.chart;
+      var meta0 = chart.getDatasetMeta(0);
+      var meta1 = chart.getDatasetMeta(1);
+
+      // Halfway between 2 mid points
+      var pt = {
+        x: meta0.data[1].x,
+        y: meta0.data[1].y
+      };
+
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: pt.x,
+        y: 0
+      };
+
+      var elements = Chart.Interaction.modes.x(chart, evt, {intersect: false}).map(item => item.element);
+      expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
+
+      evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: pt.x + 20,
+        y: 0
+      };
+
+      elements = Chart.Interaction.modes.x(chart, evt, {intersect: false}).map(item => item.element);
+      expect(elements).toEqual([]);
+    });
+
+    it('should return items at the same x value when intersect is true', function() {
+      var chart = this.chart;
+      var meta0 = chart.getDatasetMeta(0);
+      var meta1 = chart.getDatasetMeta(1);
+
+      // Halfway between 2 mid points
+      var pt = {
+        x: meta0.data[1].x,
+        y: meta0.data[1].y
+      };
+
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: pt.x,
+        y: 0
+      };
+
+      var elements = Chart.Interaction.modes.x(chart, evt, {intersect: true}).map(item => item.element);
+      expect(elements).toEqual([]); // we don't intersect anything
+
+      evt = {
+        type: 'click',
+        chart: chart,
+        native: true, // needed otherwise things its a DOM event
+        x: pt.x,
+        y: pt.y
+      };
+
+      elements = Chart.Interaction.modes.x(chart, evt, {intersect: true}).map(item => item.element);
+      expect(elements).toEqual([meta0.data[1], meta1.data[1]]);
+    });
+  });
+
+  describe('y mode', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 40, 30],
+            pointRadius: [5, 10, 5],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointRadius: [10, 10, 10],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        }
+      });
+    });
+
+    it('should return items at the same y value when intersect is false', function() {
+      var chart = this.chart;
+      var meta0 = chart.getDatasetMeta(0);
+      var meta1 = chart.getDatasetMeta(1);
+
+      // Halfway between 2 mid points
+      var pt = {
+        x: meta0.data[1].x,
+        y: meta0.data[1].y
+      };
+
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true,
+        x: 0,
+        y: pt.y,
+      };
+
+      var elements = Chart.Interaction.modes.y(chart, evt, {intersect: false}).map(item => item.element);
+      expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
+
+      evt = {
+        type: 'click',
+        chart: chart,
+        native: true,
+        x: pt.x,
+        y: pt.y + 20, // out of range
+      };
+
+      elements = Chart.Interaction.modes.y(chart, evt, {intersect: false}).map(item => item.element);
+      expect(elements).toEqual([]);
+    });
+
+    it('should return items at the same y value when intersect is true', function() {
+      var chart = this.chart;
+      var meta0 = chart.getDatasetMeta(0);
+      var meta1 = chart.getDatasetMeta(1);
+
+      // Halfway between 2 mid points
+      var pt = {
+        x: meta0.data[1].x,
+        y: meta0.data[1].y
+      };
+
+      var evt = {
+        type: 'click',
+        chart: chart,
+        native: true,
+        x: 0,
+        y: pt.y
+      };
+
+      var elements = Chart.Interaction.modes.y(chart, evt, {intersect: true}).map(item => item.element);
+      expect(elements).toEqual([]); // we don't intersect anything
+
+      evt = {
+        type: 'click',
+        chart: chart,
+        native: true,
+        x: pt.x,
+        y: pt.y,
+      };
+
+      elements = Chart.Interaction.modes.y(chart, evt, {intersect: true}).map(item => item.element);
+      expect(elements).toEqual([meta0.data[1], meta1.data[0], meta1.data[1], meta1.data[2]]);
+    });
+  });
 });
index cf70ddda63e290a11dba2e0332852f1d734ae11f..ee70b2ea79ba02732d92609e84a75cc60e1b0cb8 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Chart.layouts', function() {
-       describe('auto', jasmine.fixture.specs('core.layouts'));
-
-       it('should be exposed through Chart.layouts', function() {
-               expect(Chart.layouts).toBeDefined();
-               expect(typeof Chart.layouts).toBe('object');
-               expect(Chart.layouts.addBox).toBeDefined();
-               expect(Chart.layouts.removeBox).toBeDefined();
-               expect(Chart.layouts.configure).toBeDefined();
-               expect(Chart.layouts.update).toBeDefined();
-       });
-
-       it('should fit a simple chart with 2 scales', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [10, 5, 0, 25, 78, -10]}
-                               ],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       }
-               }, {
-                       canvas: {
-                               height: 150,
-                               width: 250
-                       }
-               });
-
-               expect(chart.chartArea.bottom).toBeCloseToPixel(120);
-               expect(chart.chartArea.left).toBeCloseToPixel(34);
-               expect(chart.chartArea.right).toBeCloseToPixel(247);
-               expect(chart.chartArea.top).toBeCloseToPixel(32);
-
-               // Is xScale at the right spot
-               expect(chart.scales.x.bottom).toBeCloseToPixel(150);
-               expect(chart.scales.x.left).toBeCloseToPixel(34);
-               expect(chart.scales.x.right).toBeCloseToPixel(247);
-               expect(chart.scales.x.top).toBeCloseToPixel(120);
-               expect(chart.scales.x.labelRotation).toBeCloseTo(0);
-
-               // Is yScale at the right spot
-               expect(chart.scales.y.bottom).toBeCloseToPixel(120);
-               expect(chart.scales.y.left).toBeCloseToPixel(0);
-               expect(chart.scales.y.right).toBeCloseToPixel(34);
-               expect(chart.scales.y.top).toBeCloseToPixel(32);
-               expect(chart.scales.y.labelRotation).toBeCloseTo(0);
-       });
-
-       it('should fit scales that are in the top and right positions', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [10, 5, 0, 25, 78, -10]}
-                               ],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'top'
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               position: 'right'
-                                       }
-                               }
-                       }
-               }, {
-                       canvas: {
-                               height: 150,
-                               width: 250
-                       }
-               });
-
-               expect(chart.chartArea.bottom).toBeCloseToPixel(142);
-               expect(chart.chartArea.left).toBeCloseToPixel(3);
-               expect(chart.chartArea.right).toBeCloseToPixel(216);
-               expect(chart.chartArea.top).toBeCloseToPixel(62);
-
-               // Is xScale at the right spot
-               expect(chart.scales.x.bottom).toBeCloseToPixel(62);
-               expect(chart.scales.x.left).toBeCloseToPixel(3);
-               expect(chart.scales.x.right).toBeCloseToPixel(216);
-               expect(chart.scales.x.top).toBeCloseToPixel(32);
-               expect(chart.scales.x.labelRotation).toBeCloseTo(0);
-
-               // Is yScale at the right spot
-               expect(chart.scales.y.bottom).toBeCloseToPixel(142);
-               expect(chart.scales.y.left).toBeCloseToPixel(216);
-               expect(chart.scales.y.right).toBeCloseToPixel(250);
-               expect(chart.scales.y.top).toBeCloseToPixel(62);
-               expect(chart.scales.y.labelRotation).toBeCloseTo(0);
-       });
-
-       it('should fit scales that overlap the chart area', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78, -10]
-                               }, {
-                                       data: [-19, -20, 0, -99, -50, 0]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       }
-               });
-
-               expect(chart.chartArea.bottom).toBeCloseToPixel(512);
-               expect(chart.chartArea.left).toBeCloseToPixel(0);
-               expect(chart.chartArea.right).toBeCloseToPixel(512);
-               expect(chart.chartArea.top).toBeCloseToPixel(32);
-
-               var scale = chart.scales.r;
-               expect(scale.bottom).toBeCloseToPixel(512);
-               expect(scale.left).toBeCloseToPixel(0);
-               expect(scale.right).toBeCloseToPixel(512);
-               expect(scale.top).toBeCloseToPixel(32);
-               expect(scale.width).toBeCloseToPixel(512);
-               expect(scale.height).toBeCloseToPixel(480);
-       });
-
-       it('should fit multiple axes in the same position', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78, -10]
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [-19, -20, 0, -99, -50, 0]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       },
-                                       y2: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               }, {
-                       canvas: {
-                               height: 150,
-                               width: 250
-                       }
-               });
-
-               expect(chart.chartArea.bottom).toBeCloseToPixel(118);
-               expect(chart.chartArea.left).toBeCloseToPixel(73);
-               expect(chart.chartArea.right).toBeCloseToPixel(247);
-               expect(chart.chartArea.top).toBeCloseToPixel(32);
-
-               // Is xScale at the right spot
-               expect(chart.scales.x.bottom).toBeCloseToPixel(150);
-               expect(chart.scales.x.left).toBeCloseToPixel(73);
-               expect(chart.scales.x.right).toBeCloseToPixel(247);
-               expect(chart.scales.x.top).toBeCloseToPixel(118);
-               expect(chart.scales.x.labelRotation).toBeCloseTo(40, -1);
-
-               // Are yScales at the right spot
-               expect(chart.scales.y.bottom).toBeCloseToPixel(118);
-               expect(chart.scales.y.left).toBeCloseToPixel(41);
-               expect(chart.scales.y.right).toBeCloseToPixel(73);
-               expect(chart.scales.y.top).toBeCloseToPixel(32);
-               expect(chart.scales.y.labelRotation).toBeCloseTo(0);
-
-               expect(chart.scales.y2.bottom).toBeCloseToPixel(118);
-               expect(chart.scales.y2.left).toBeCloseToPixel(0);
-               expect(chart.scales.y2.right).toBeCloseToPixel(41);
-               expect(chart.scales.y2.top).toBeCloseToPixel(32);
-               expect(chart.scales.y2.labelRotation).toBeCloseTo(0);
-       });
-
-       it ('should fit a full width box correctly', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: [10, 5, 0, 25, 78, -10]
-                               }, {
-                                       xAxisID: 'x2',
-                                       data: [-19, -20, 0, -99, -50, 0]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               offset: false
-                                       },
-                                       x2: {
-                                               type: 'category',
-                                               position: 'top',
-                                               fullSize: true,
-                                               offset: false
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.chartArea.bottom).toBeCloseToPixel(484);
-               expect(chart.chartArea.left).toBeCloseToPixel(40);
-               expect(chart.chartArea.right).toBeCloseToPixel(496);
-               expect(chart.chartArea.top).toBeCloseToPixel(62);
-
-               // Are xScales at the right spot
-               expect(chart.scales.x.bottom).toBeCloseToPixel(512);
-               expect(chart.scales.x.left).toBeCloseToPixel(40);
-               expect(chart.scales.x.right).toBeCloseToPixel(496);
-               expect(chart.scales.x.top).toBeCloseToPixel(484);
-
-               expect(chart.scales.x2.bottom).toBeCloseToPixel(62);
-               expect(chart.scales.x2.left).toBeCloseToPixel(0);
-               expect(chart.scales.x2.right).toBeCloseToPixel(512);
-               expect(chart.scales.x2.top).toBeCloseToPixel(32);
-
-               // Is yScale at the right spot
-               expect(chart.scales.y.bottom).toBeCloseToPixel(484);
-               expect(chart.scales.y.left).toBeCloseToPixel(0);
-               expect(chart.scales.y.right).toBeCloseToPixel(40);
-               expect(chart.scales.y.top).toBeCloseToPixel(62);
-       });
-
-       describe('padding settings', function() {
-               it('should apply a single padding to all dimensions', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {
-                                                       data: [10, 5, 0, 25, 78, -10]
-                                               }
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       display: false
-                                               },
-                                               y: {
-                                                       type: 'linear',
-                                                       display: false
-                                               }
-                                       },
-                                       plugins: {
-                                               legend: false,
-                                               title: false
-                                       },
-                                       layout: {
-                                               padding: 10
-                                       }
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               }
-                       });
-
-                       expect(chart.chartArea.bottom).toBeCloseToPixel(140);
-                       expect(chart.chartArea.left).toBeCloseToPixel(10);
-                       expect(chart.chartArea.right).toBeCloseToPixel(240);
-                       expect(chart.chartArea.top).toBeCloseToPixel(10);
-               });
-
-               it('should apply padding in all positions', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {
-                                                       data: [10, 5, 0, 25, 78, -10]
-                                               }
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       display: false
-                                               },
-                                               y: {
-                                                       type: 'linear',
-                                                       display: false
-                                               }
-                                       },
-                                       plugins: {
-                                               legend: false,
-                                               title: false
-                                       },
-                                       layout: {
-                                               padding: {
-                                                       left: 5,
-                                                       right: 15,
-                                                       top: 8,
-                                                       bottom: 12
-                                               }
-                                       }
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               }
-                       });
-
-                       expect(chart.chartArea.bottom).toBeCloseToPixel(138);
-                       expect(chart.chartArea.left).toBeCloseToPixel(5);
-                       expect(chart.chartArea.right).toBeCloseToPixel(235);
-                       expect(chart.chartArea.top).toBeCloseToPixel(8);
-               });
-
-               it('should default to 0 padding if no dimensions specified', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {
-                                                       data: [10, 5, 0, 25, 78, -10]
-                                               }
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       display: false
-                                               },
-                                               y: {
-                                                       type: 'linear',
-                                                       display: false
-                                               }
-                                       },
-                                       plugins: {
-                                               legend: false,
-                                               title: false
-                                       },
-                                       layout: {
-                                               padding: {}
-                                       }
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               }
-                       });
-
-                       expect(chart.chartArea.bottom).toBeCloseToPixel(150);
-                       expect(chart.chartArea.left).toBeCloseToPixel(0);
-                       expect(chart.chartArea.right).toBeCloseToPixel(250);
-                       expect(chart.chartArea.top).toBeCloseToPixel(0);
-               });
-       });
-
-       describe('ordering by weight', function() {
-               it('should keep higher weights outside', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {
-                                                       data: [10, 5, 0, 25, 78, -10]
-                                               }
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       display: true,
-                                                       position: 'left',
-                                               },
-                                               title: {
-                                                       display: true,
-                                                       position: 'bottom',
-                                               },
-                                       }
-                               },
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               }
-                       });
-
-                       var xAxis = chart.scales.x;
-                       var yAxis = chart.scales.y;
-                       var legend = chart.legend;
-                       var title = chart.titleBlock;
-
-                       expect(yAxis.left).toBe(legend.right);
-                       expect(xAxis.bottom).toBe(title.top);
-               });
-
-               it('should correctly set weights of scales and order them', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {
-                                                       data: [10, 5, 0, 25, 78, -10]
-                                               }
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       position: 'bottom',
-                                                       display: true,
-                                                       weight: 1
-                                               },
-                                               x1: {
-                                                       type: 'category',
-                                                       position: 'bottom',
-                                                       display: true,
-                                                       weight: 2
-                                               },
-                                               x2: {
-                                                       type: 'category',
-                                                       position: 'bottom',
-                                                       display: true
-                                               },
-                                               x3: {
-                                                       type: 'category',
-                                                       display: true,
-                                                       position: 'top',
-                                                       weight: 1
-                                               },
-                                               x4: {
-                                                       type: 'category',
-                                                       display: true,
-                                                       position: 'top',
-                                                       weight: 2
-                                               },
-                                               y: {
-                                                       type: 'linear',
-                                                       display: true,
-                                                       weight: 1
-                                               },
-                                               y1: {
-                                                       type: 'linear',
-                                                       position: 'left',
-                                                       display: true,
-                                                       weight: 2
-                                               },
-                                               y2: {
-                                                       type: 'linear',
-                                                       position: 'left',
-                                                       display: true
-                                               },
-                                               y3: {
-                                                       type: 'linear',
-                                                       display: true,
-                                                       position: 'right',
-                                                       weight: 1
-                                               },
-                                               y4: {
-                                                       type: 'linear',
-                                                       display: true,
-                                                       position: 'right',
-                                                       weight: 2
-                                               }
-                                       }
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               }
-                       });
-
-                       var xScale0 = chart.scales.x;
-                       var xScale1 = chart.scales.x1;
-                       var xScale2 = chart.scales.x2;
-                       var xScale3 = chart.scales.x3;
-                       var xScale4 = chart.scales.x4;
-
-                       var yScale0 = chart.scales.y;
-                       var yScale1 = chart.scales.y1;
-                       var yScale2 = chart.scales.y2;
-                       var yScale3 = chart.scales.y3;
-                       var yScale4 = chart.scales.y4;
-
-                       expect(xScale0.weight).toBe(1);
-                       expect(xScale1.weight).toBe(2);
-                       expect(xScale2.weight).toBe(0);
-
-                       expect(xScale3.weight).toBe(1);
-                       expect(xScale4.weight).toBe(2);
-
-                       expect(yScale0.weight).toBe(1);
-                       expect(yScale1.weight).toBe(2);
-                       expect(yScale2.weight).toBe(0);
-
-                       expect(yScale3.weight).toBe(1);
-                       expect(yScale4.weight).toBe(2);
-
-                       var isOrderCorrect = false;
-
-                       // bottom axes
-                       isOrderCorrect = xScale2.top < xScale0.top && xScale0.top < xScale1.top;
-                       expect(isOrderCorrect).toBe(true);
-
-                       // top axes
-                       isOrderCorrect = xScale4.top < xScale3.top;
-                       expect(isOrderCorrect).toBe(true);
-
-                       // left axes
-                       isOrderCorrect = yScale1.left < yScale0.left && yScale0.left < yScale2.left;
-                       expect(isOrderCorrect).toBe(true);
-
-                       // right axes
-                       isOrderCorrect = yScale3.left < yScale4.left;
-                       expect(isOrderCorrect).toBe(true);
-               });
-       });
-
-       describe('box sizing', function() {
-               it('should correctly compute y-axis width to fit labels', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       labels: ['tick 1', 'tick 2', 'tick 3', 'tick 4', 'tick 5'],
-                                       datasets: [{
-                                               data: [0, 2.25, 1.5, 1.25, 2.5]
-                                       }],
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: false
-                                       },
-                               },
-                       }, {
-                               canvas: {
-                                       height: 256,
-                                       width: 256
-                               }
-                       });
-                       var yAxis = chart.scales.y;
-
-                       // issue #4441: y-axis labels partially hidden.
-                       // minimum horizontal space required to fit labels
-                       expect(yAxis.width).toBeCloseToPixel(33);
-                       expect(getLabels(yAxis)).toEqual(['0', '0.5', '1.0', '1.5', '2.0', '2.5']);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('core.layouts'));
+
+  it('should be exposed through Chart.layouts', function() {
+    expect(Chart.layouts).toBeDefined();
+    expect(typeof Chart.layouts).toBe('object');
+    expect(Chart.layouts.addBox).toBeDefined();
+    expect(Chart.layouts.removeBox).toBeDefined();
+    expect(Chart.layouts.configure).toBeDefined();
+    expect(Chart.layouts.update).toBeDefined();
+  });
+
+  it('should fit a simple chart with 2 scales', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [10, 5, 0, 25, 78, -10]}
+        ],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      }
+    }, {
+      canvas: {
+        height: 150,
+        width: 250
+      }
+    });
+
+    expect(chart.chartArea.bottom).toBeCloseToPixel(120);
+    expect(chart.chartArea.left).toBeCloseToPixel(34);
+    expect(chart.chartArea.right).toBeCloseToPixel(247);
+    expect(chart.chartArea.top).toBeCloseToPixel(32);
+
+    // Is xScale at the right spot
+    expect(chart.scales.x.bottom).toBeCloseToPixel(150);
+    expect(chart.scales.x.left).toBeCloseToPixel(34);
+    expect(chart.scales.x.right).toBeCloseToPixel(247);
+    expect(chart.scales.x.top).toBeCloseToPixel(120);
+    expect(chart.scales.x.labelRotation).toBeCloseTo(0);
+
+    // Is yScale at the right spot
+    expect(chart.scales.y.bottom).toBeCloseToPixel(120);
+    expect(chart.scales.y.left).toBeCloseToPixel(0);
+    expect(chart.scales.y.right).toBeCloseToPixel(34);
+    expect(chart.scales.y.top).toBeCloseToPixel(32);
+    expect(chart.scales.y.labelRotation).toBeCloseTo(0);
+  });
+
+  it('should fit scales that are in the top and right positions', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [
+          {data: [10, 5, 0, 25, 78, -10]}
+        ],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'top'
+          },
+          y: {
+            type: 'linear',
+            position: 'right'
+          }
+        }
+      }
+    }, {
+      canvas: {
+        height: 150,
+        width: 250
+      }
+    });
+
+    expect(chart.chartArea.bottom).toBeCloseToPixel(142);
+    expect(chart.chartArea.left).toBeCloseToPixel(3);
+    expect(chart.chartArea.right).toBeCloseToPixel(216);
+    expect(chart.chartArea.top).toBeCloseToPixel(62);
+
+    // Is xScale at the right spot
+    expect(chart.scales.x.bottom).toBeCloseToPixel(62);
+    expect(chart.scales.x.left).toBeCloseToPixel(3);
+    expect(chart.scales.x.right).toBeCloseToPixel(216);
+    expect(chart.scales.x.top).toBeCloseToPixel(32);
+    expect(chart.scales.x.labelRotation).toBeCloseTo(0);
+
+    // Is yScale at the right spot
+    expect(chart.scales.y.bottom).toBeCloseToPixel(142);
+    expect(chart.scales.y.left).toBeCloseToPixel(216);
+    expect(chart.scales.y.right).toBeCloseToPixel(250);
+    expect(chart.scales.y.top).toBeCloseToPixel(62);
+    expect(chart.scales.y.labelRotation).toBeCloseTo(0);
+  });
+
+  it('should fit scales that overlap the chart area', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78, -10]
+        }, {
+          data: [-19, -20, 0, -99, -50, 0]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      }
+    });
+
+    expect(chart.chartArea.bottom).toBeCloseToPixel(512);
+    expect(chart.chartArea.left).toBeCloseToPixel(0);
+    expect(chart.chartArea.right).toBeCloseToPixel(512);
+    expect(chart.chartArea.top).toBeCloseToPixel(32);
+
+    var scale = chart.scales.r;
+    expect(scale.bottom).toBeCloseToPixel(512);
+    expect(scale.left).toBeCloseToPixel(0);
+    expect(scale.right).toBeCloseToPixel(512);
+    expect(scale.top).toBeCloseToPixel(32);
+    expect(scale.width).toBeCloseToPixel(512);
+    expect(scale.height).toBeCloseToPixel(480);
+  });
+
+  it('should fit multiple axes in the same position', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78, -10]
+        }, {
+          yAxisID: 'y2',
+          data: [-19, -20, 0, -99, -50, 0]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category'
+          },
+          y: {
+            type: 'linear'
+          },
+          y2: {
+            type: 'linear'
+          }
+        }
+      }
+    }, {
+      canvas: {
+        height: 150,
+        width: 250
+      }
+    });
+
+    expect(chart.chartArea.bottom).toBeCloseToPixel(118);
+    expect(chart.chartArea.left).toBeCloseToPixel(73);
+    expect(chart.chartArea.right).toBeCloseToPixel(247);
+    expect(chart.chartArea.top).toBeCloseToPixel(32);
+
+    // Is xScale at the right spot
+    expect(chart.scales.x.bottom).toBeCloseToPixel(150);
+    expect(chart.scales.x.left).toBeCloseToPixel(73);
+    expect(chart.scales.x.right).toBeCloseToPixel(247);
+    expect(chart.scales.x.top).toBeCloseToPixel(118);
+    expect(chart.scales.x.labelRotation).toBeCloseTo(40, -1);
+
+    // Are yScales at the right spot
+    expect(chart.scales.y.bottom).toBeCloseToPixel(118);
+    expect(chart.scales.y.left).toBeCloseToPixel(41);
+    expect(chart.scales.y.right).toBeCloseToPixel(73);
+    expect(chart.scales.y.top).toBeCloseToPixel(32);
+    expect(chart.scales.y.labelRotation).toBeCloseTo(0);
+
+    expect(chart.scales.y2.bottom).toBeCloseToPixel(118);
+    expect(chart.scales.y2.left).toBeCloseToPixel(0);
+    expect(chart.scales.y2.right).toBeCloseToPixel(41);
+    expect(chart.scales.y2.top).toBeCloseToPixel(32);
+    expect(chart.scales.y2.labelRotation).toBeCloseTo(0);
+  });
+
+  it ('should fit a full width box correctly', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          data: [10, 5, 0, 25, 78, -10]
+        }, {
+          xAxisID: 'x2',
+          data: [-19, -20, 0, -99, -50, 0]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            offset: false
+          },
+          x2: {
+            type: 'category',
+            position: 'top',
+            fullSize: true,
+            offset: false
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    expect(chart.chartArea.bottom).toBeCloseToPixel(484);
+    expect(chart.chartArea.left).toBeCloseToPixel(40);
+    expect(chart.chartArea.right).toBeCloseToPixel(496);
+    expect(chart.chartArea.top).toBeCloseToPixel(62);
+
+    // Are xScales at the right spot
+    expect(chart.scales.x.bottom).toBeCloseToPixel(512);
+    expect(chart.scales.x.left).toBeCloseToPixel(40);
+    expect(chart.scales.x.right).toBeCloseToPixel(496);
+    expect(chart.scales.x.top).toBeCloseToPixel(484);
+
+    expect(chart.scales.x2.bottom).toBeCloseToPixel(62);
+    expect(chart.scales.x2.left).toBeCloseToPixel(0);
+    expect(chart.scales.x2.right).toBeCloseToPixel(512);
+    expect(chart.scales.x2.top).toBeCloseToPixel(32);
+
+    // Is yScale at the right spot
+    expect(chart.scales.y.bottom).toBeCloseToPixel(484);
+    expect(chart.scales.y.left).toBeCloseToPixel(0);
+    expect(chart.scales.y.right).toBeCloseToPixel(40);
+    expect(chart.scales.y.top).toBeCloseToPixel(62);
+  });
+
+  describe('padding settings', function() {
+    it('should apply a single padding to all dimensions', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {
+              data: [10, 5, 0, 25, 78, -10]
+            }
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              display: false
+            },
+            y: {
+              type: 'linear',
+              display: false
+            }
+          },
+          plugins: {
+            legend: false,
+            title: false
+          },
+          layout: {
+            padding: 10
+          }
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        }
+      });
+
+      expect(chart.chartArea.bottom).toBeCloseToPixel(140);
+      expect(chart.chartArea.left).toBeCloseToPixel(10);
+      expect(chart.chartArea.right).toBeCloseToPixel(240);
+      expect(chart.chartArea.top).toBeCloseToPixel(10);
+    });
+
+    it('should apply padding in all positions', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {
+              data: [10, 5, 0, 25, 78, -10]
+            }
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              display: false
+            },
+            y: {
+              type: 'linear',
+              display: false
+            }
+          },
+          plugins: {
+            legend: false,
+            title: false
+          },
+          layout: {
+            padding: {
+              left: 5,
+              right: 15,
+              top: 8,
+              bottom: 12
+            }
+          }
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        }
+      });
+
+      expect(chart.chartArea.bottom).toBeCloseToPixel(138);
+      expect(chart.chartArea.left).toBeCloseToPixel(5);
+      expect(chart.chartArea.right).toBeCloseToPixel(235);
+      expect(chart.chartArea.top).toBeCloseToPixel(8);
+    });
+
+    it('should default to 0 padding if no dimensions specified', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {
+              data: [10, 5, 0, 25, 78, -10]
+            }
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              display: false
+            },
+            y: {
+              type: 'linear',
+              display: false
+            }
+          },
+          plugins: {
+            legend: false,
+            title: false
+          },
+          layout: {
+            padding: {}
+          }
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        }
+      });
+
+      expect(chart.chartArea.bottom).toBeCloseToPixel(150);
+      expect(chart.chartArea.left).toBeCloseToPixel(0);
+      expect(chart.chartArea.right).toBeCloseToPixel(250);
+      expect(chart.chartArea.top).toBeCloseToPixel(0);
+    });
+  });
+
+  describe('ordering by weight', function() {
+    it('should keep higher weights outside', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {
+              data: [10, 5, 0, 25, 78, -10]
+            }
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        },
+        options: {
+          plugins: {
+            legend: {
+              display: true,
+              position: 'left',
+            },
+            title: {
+              display: true,
+              position: 'bottom',
+            },
+          }
+        },
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        }
+      });
+
+      var xAxis = chart.scales.x;
+      var yAxis = chart.scales.y;
+      var legend = chart.legend;
+      var title = chart.titleBlock;
+
+      expect(yAxis.left).toBe(legend.right);
+      expect(xAxis.bottom).toBe(title.top);
+    });
+
+    it('should correctly set weights of scales and order them', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {
+              data: [10, 5, 0, 25, 78, -10]
+            }
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              position: 'bottom',
+              display: true,
+              weight: 1
+            },
+            x1: {
+              type: 'category',
+              position: 'bottom',
+              display: true,
+              weight: 2
+            },
+            x2: {
+              type: 'category',
+              position: 'bottom',
+              display: true
+            },
+            x3: {
+              type: 'category',
+              display: true,
+              position: 'top',
+              weight: 1
+            },
+            x4: {
+              type: 'category',
+              display: true,
+              position: 'top',
+              weight: 2
+            },
+            y: {
+              type: 'linear',
+              display: true,
+              weight: 1
+            },
+            y1: {
+              type: 'linear',
+              position: 'left',
+              display: true,
+              weight: 2
+            },
+            y2: {
+              type: 'linear',
+              position: 'left',
+              display: true
+            },
+            y3: {
+              type: 'linear',
+              display: true,
+              position: 'right',
+              weight: 1
+            },
+            y4: {
+              type: 'linear',
+              display: true,
+              position: 'right',
+              weight: 2
+            }
+          }
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        }
+      });
+
+      var xScale0 = chart.scales.x;
+      var xScale1 = chart.scales.x1;
+      var xScale2 = chart.scales.x2;
+      var xScale3 = chart.scales.x3;
+      var xScale4 = chart.scales.x4;
+
+      var yScale0 = chart.scales.y;
+      var yScale1 = chart.scales.y1;
+      var yScale2 = chart.scales.y2;
+      var yScale3 = chart.scales.y3;
+      var yScale4 = chart.scales.y4;
+
+      expect(xScale0.weight).toBe(1);
+      expect(xScale1.weight).toBe(2);
+      expect(xScale2.weight).toBe(0);
+
+      expect(xScale3.weight).toBe(1);
+      expect(xScale4.weight).toBe(2);
+
+      expect(yScale0.weight).toBe(1);
+      expect(yScale1.weight).toBe(2);
+      expect(yScale2.weight).toBe(0);
+
+      expect(yScale3.weight).toBe(1);
+      expect(yScale4.weight).toBe(2);
+
+      var isOrderCorrect = false;
+
+      // bottom axes
+      isOrderCorrect = xScale2.top < xScale0.top && xScale0.top < xScale1.top;
+      expect(isOrderCorrect).toBe(true);
+
+      // top axes
+      isOrderCorrect = xScale4.top < xScale3.top;
+      expect(isOrderCorrect).toBe(true);
+
+      // left axes
+      isOrderCorrect = yScale1.left < yScale0.left && yScale0.left < yScale2.left;
+      expect(isOrderCorrect).toBe(true);
+
+      // right axes
+      isOrderCorrect = yScale3.left < yScale4.left;
+      expect(isOrderCorrect).toBe(true);
+    });
+  });
+
+  describe('box sizing', function() {
+    it('should correctly compute y-axis width to fit labels', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          labels: ['tick 1', 'tick 2', 'tick 3', 'tick 4', 'tick 5'],
+          datasets: [{
+            data: [0, 2.25, 1.5, 1.25, 2.5]
+          }],
+        },
+        options: {
+          plugins: {
+            legend: false
+          },
+        },
+      }, {
+        canvas: {
+          height: 256,
+          width: 256
+        }
+      });
+      var yAxis = chart.scales.y;
+
+      // issue #4441: y-axis labels partially hidden.
+      // minimum horizontal space required to fit labels
+      expect(yAxis.width).toBeCloseToPixel(33);
+      expect(getLabels(yAxis)).toEqual(['0', '0.5', '1.0', '1.5', '2.0', '2.5']);
+    });
+  });
 });
index af93dc53af3f5b237c84729b25a7d811c7ebe897..d38e55619d8b15eb7088da649db0002a6dfd8d2a 100644 (file)
 describe('Chart.plugins', function() {
-       describe('Chart.notifyPlugins', function() {
-               it('should call inline plugins with arguments', function() {
-                       var plugin = {hook: function() {}};
-                       var chart = window.acquireChart({
-                               plugins: [plugin]
-                       });
-                       var args = {value: 42};
-
-                       spyOn(plugin, 'hook');
-
-                       chart.notifyPlugins('hook', args);
-                       expect(plugin.hook.calls.count()).toBe(1);
-                       expect(plugin.hook.calls.first().args[0]).toBe(chart);
-                       expect(plugin.hook.calls.first().args[1]).toBe(args);
-                       expect(plugin.hook.calls.first().args[2]).toEqual({});
-               });
-
-               it('should call global plugins with arguments', function() {
-                       var plugin = {id: 'a', hook: function() {}};
-                       var chart = window.acquireChart({});
-                       var args = {value: 42};
-
-                       spyOn(plugin, 'hook');
-
-                       Chart.register(plugin);
-                       chart.notifyPlugins('hook', args);
-                       expect(plugin.hook.calls.count()).toBe(1);
-                       expect(plugin.hook.calls.first().args[0]).toBe(chart);
-                       expect(plugin.hook.calls.first().args[1]).toBe(args);
-                       expect(plugin.hook.calls.first().args[2]).toEqual({});
-                       Chart.unregister(plugin);
-               });
-
-               it('should call plugin only once even if registered multiple times', function() {
-                       var plugin = {id: 'test', hook: function() {}};
-                       var chart = window.acquireChart({
-                               plugins: [plugin, plugin]
-                       });
-
-                       spyOn(plugin, 'hook');
-
-                       Chart.register([plugin, plugin]);
-                       chart.notifyPlugins('hook');
-                       expect(plugin.hook.calls.count()).toBe(1);
-                       Chart.unregister(plugin);
-               });
-
-               it('should call plugins in the correct order (global first)', function() {
-                       var results = [];
-                       var chart = window.acquireChart({
-                               plugins: [{
-                                       hook: function() {
-                                               results.push(1);
-                                       }
-                               }, {
-                                       hook: function() {
-                                               results.push(2);
-                                       }
-                               }, {
-                                       hook: function() {
-                                               results.push(3);
-                                       }
-                               }]
-                       });
-
-                       var plugins = [{
-                               id: 'a',
-                               hook: function() {
-                                       results.push(4);
-                               }
-                       }, {
-                               id: 'b',
-                               hook: function() {
-                                       results.push(5);
-                               }
-                       }, {
-                               id: 'c',
-                               hook: function() {
-                                       results.push(6);
-                               }
-                       }];
-                       Chart.register(plugins);
-
-                       var ret = chart.notifyPlugins('hook');
-                       expect(ret).toBeTruthy();
-                       expect(results).toEqual([4, 5, 6, 1, 2, 3]);
-                       Chart.unregister(plugins);
-               });
-
-               it('should return TRUE if no plugin explicitly returns FALSE', function() {
-                       var chart = window.acquireChart({
-                               plugins: [{
-                                       hook: function() {}
-                               }, {
-                                       hook: function() {
-                                               return null;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return 0;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return true;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return 1;
-                                       }
-                               }]
-                       });
-
-                       var plugins = chart.config.plugins;
-                       plugins.forEach(function(plugin) {
-                               spyOn(plugin, 'hook').and.callThrough();
-                       });
-
-                       var ret = chart.notifyPlugins('hook');
-                       expect(ret).toBeTruthy();
-                       plugins.forEach(function(plugin) {
-                               expect(plugin.hook).toHaveBeenCalled();
-                       });
-               });
-
-               it('should return FALSE if any plugin explicitly returns FALSE', function() {
-                       var chart = window.acquireChart({
-                               plugins: [{
-                                       hook: function() {}
-                               }, {
-                                       hook: function() {
-                                               return null;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return false;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return 42;
-                                       }
-                               }, {
-                                       hook: function() {
-                                               return 'bar';
-                                       }
-                               }]
-                       });
-
-                       var plugins = chart.config.plugins;
-                       plugins.forEach(function(plugin) {
-                               spyOn(plugin, 'hook').and.callThrough();
-                       });
-
-                       var ret = chart.notifyPlugins('hook', {cancelable: true});
-                       expect(ret).toBeFalsy();
-                       expect(plugins[0].hook).toHaveBeenCalled();
-                       expect(plugins[1].hook).toHaveBeenCalled();
-                       expect(plugins[2].hook).toHaveBeenCalled();
-                       expect(plugins[3].hook).not.toHaveBeenCalled();
-                       expect(plugins[4].hook).not.toHaveBeenCalled();
-               });
-       });
-
-       describe('config.options.plugins', function() {
-               it('should call plugins with options at last argument', function() {
-                       var plugin = {id: 'foo', hook: function() {}};
-
-                       var chart = window.acquireChart({
-                               options: {
-                                       plugins: {
-                                               foo: {a: '123'},
-                                       }
-                               }
-                       });
-
-                       spyOn(plugin, 'hook');
-
-                       Chart.register(plugin);
-                       chart.notifyPlugins('hook');
-                       chart.notifyPlugins('hook', {arg1: 'bla'});
-                       chart.notifyPlugins('hook', {arg1: 'bla', arg2: 42});
-
-                       expect(plugin.hook.calls.count()).toBe(3);
-                       expect(plugin.hook.calls.argsFor(0)[2]).toEqual({a: '123'});
-                       expect(plugin.hook.calls.argsFor(1)[2]).toEqual({a: '123'});
-                       expect(plugin.hook.calls.argsFor(2)[2]).toEqual({a: '123'});
-
-                       Chart.unregister(plugin);
-               });
-
-               it('should call plugins with options associated to their identifier', function() {
-                       var plugins = {
-                               a: {id: 'a', hook: function() {}},
-                               b: {id: 'b', hook: function() {}},
-                               c: {id: 'c', hook: function() {}}
-                       };
-
-                       Chart.register(plugins.a);
-
-                       var chart = window.acquireChart({
-                               plugins: [plugins.b, plugins.c],
-                               options: {
-                                       plugins: {
-                                               a: {a: '123'},
-                                               b: {b: '456'},
-                                               c: {c: '789'}
-                                       }
-                               }
-                       });
-
-                       spyOn(plugins.a, 'hook');
-                       spyOn(plugins.b, 'hook');
-                       spyOn(plugins.c, 'hook');
-
-                       chart.notifyPlugins('hook');
-
-                       expect(plugins.a.hook).toHaveBeenCalled();
-                       expect(plugins.b.hook).toHaveBeenCalled();
-                       expect(plugins.c.hook).toHaveBeenCalled();
-                       expect(plugins.a.hook.calls.first().args[2]).toEqual({a: '123'});
-                       expect(plugins.b.hook.calls.first().args[2]).toEqual({b: '456'});
-                       expect(plugins.c.hook.calls.first().args[2]).toEqual({c: '789'});
-
-                       Chart.unregister(plugins.a);
-               });
-
-               it('should not called plugins when config.options.plugins.{id} is FALSE', function() {
-                       var plugins = {
-                               a: {id: 'a', hook: function() {}},
-                               b: {id: 'b', hook: function() {}},
-                               c: {id: 'c', hook: function() {}}
-                       };
-
-                       Chart.register(plugins.a);
-
-                       var chart = window.acquireChart({
-                               plugins: [plugins.b, plugins.c],
-                               options: {
-                                       plugins: {
-                                               a: false,
-                                               b: false
-                                       }
-                               }
-                       });
-
-                       spyOn(plugins.a, 'hook');
-                       spyOn(plugins.b, 'hook');
-                       spyOn(plugins.c, 'hook');
-
-                       chart.notifyPlugins('hook');
-
-                       expect(plugins.a.hook).not.toHaveBeenCalled();
-                       expect(plugins.b.hook).not.toHaveBeenCalled();
-                       expect(plugins.c.hook).toHaveBeenCalled();
-
-                       Chart.unregister(plugins.a);
-               });
-
-               it('should call plugins with default options when plugin options is TRUE', function() {
-                       var plugin = {id: 'a', hook: function() {}, defaults: {a: 42}};
-
-                       Chart.register(plugin);
-
-                       var chart = window.acquireChart({
-                               options: {
-                                       plugins: {
-                                               a: true
-                                       }
-                               }
-                       });
-
-                       spyOn(plugin, 'hook');
-
-                       chart.notifyPlugins('hook');
-
-                       expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[2]).toEqual({a: 42});
-
-                       Chart.unregister(plugin);
-               });
+  describe('Chart.notifyPlugins', function() {
+    it('should call inline plugins with arguments', function() {
+      var plugin = {hook: function() {}};
+      var chart = window.acquireChart({
+        plugins: [plugin]
+      });
+      var args = {value: 42};
+
+      spyOn(plugin, 'hook');
+
+      chart.notifyPlugins('hook', args);
+      expect(plugin.hook.calls.count()).toBe(1);
+      expect(plugin.hook.calls.first().args[0]).toBe(chart);
+      expect(plugin.hook.calls.first().args[1]).toBe(args);
+      expect(plugin.hook.calls.first().args[2]).toEqual({});
+    });
+
+    it('should call global plugins with arguments', function() {
+      var plugin = {id: 'a', hook: function() {}};
+      var chart = window.acquireChart({});
+      var args = {value: 42};
+
+      spyOn(plugin, 'hook');
+
+      Chart.register(plugin);
+      chart.notifyPlugins('hook', args);
+      expect(plugin.hook.calls.count()).toBe(1);
+      expect(plugin.hook.calls.first().args[0]).toBe(chart);
+      expect(plugin.hook.calls.first().args[1]).toBe(args);
+      expect(plugin.hook.calls.first().args[2]).toEqual({});
+      Chart.unregister(plugin);
+    });
+
+    it('should call plugin only once even if registered multiple times', function() {
+      var plugin = {id: 'test', hook: function() {}};
+      var chart = window.acquireChart({
+        plugins: [plugin, plugin]
+      });
+
+      spyOn(plugin, 'hook');
+
+      Chart.register([plugin, plugin]);
+      chart.notifyPlugins('hook');
+      expect(plugin.hook.calls.count()).toBe(1);
+      Chart.unregister(plugin);
+    });
+
+    it('should call plugins in the correct order (global first)', function() {
+      var results = [];
+      var chart = window.acquireChart({
+        plugins: [{
+          hook: function() {
+            results.push(1);
+          }
+        }, {
+          hook: function() {
+            results.push(2);
+          }
+        }, {
+          hook: function() {
+            results.push(3);
+          }
+        }]
+      });
+
+      var plugins = [{
+        id: 'a',
+        hook: function() {
+          results.push(4);
+        }
+      }, {
+        id: 'b',
+        hook: function() {
+          results.push(5);
+        }
+      }, {
+        id: 'c',
+        hook: function() {
+          results.push(6);
+        }
+      }];
+      Chart.register(plugins);
+
+      var ret = chart.notifyPlugins('hook');
+      expect(ret).toBeTruthy();
+      expect(results).toEqual([4, 5, 6, 1, 2, 3]);
+      Chart.unregister(plugins);
+    });
+
+    it('should return TRUE if no plugin explicitly returns FALSE', function() {
+      var chart = window.acquireChart({
+        plugins: [{
+          hook: function() {}
+        }, {
+          hook: function() {
+            return null;
+          }
+        }, {
+          hook: function() {
+            return 0;
+          }
+        }, {
+          hook: function() {
+            return true;
+          }
+        }, {
+          hook: function() {
+            return 1;
+          }
+        }]
+      });
+
+      var plugins = chart.config.plugins;
+      plugins.forEach(function(plugin) {
+        spyOn(plugin, 'hook').and.callThrough();
+      });
+
+      var ret = chart.notifyPlugins('hook');
+      expect(ret).toBeTruthy();
+      plugins.forEach(function(plugin) {
+        expect(plugin.hook).toHaveBeenCalled();
+      });
+    });
+
+    it('should return FALSE if any plugin explicitly returns FALSE', function() {
+      var chart = window.acquireChart({
+        plugins: [{
+          hook: function() {}
+        }, {
+          hook: function() {
+            return null;
+          }
+        }, {
+          hook: function() {
+            return false;
+          }
+        }, {
+          hook: function() {
+            return 42;
+          }
+        }, {
+          hook: function() {
+            return 'bar';
+          }
+        }]
+      });
+
+      var plugins = chart.config.plugins;
+      plugins.forEach(function(plugin) {
+        spyOn(plugin, 'hook').and.callThrough();
+      });
+
+      var ret = chart.notifyPlugins('hook', {cancelable: true});
+      expect(ret).toBeFalsy();
+      expect(plugins[0].hook).toHaveBeenCalled();
+      expect(plugins[1].hook).toHaveBeenCalled();
+      expect(plugins[2].hook).toHaveBeenCalled();
+      expect(plugins[3].hook).not.toHaveBeenCalled();
+      expect(plugins[4].hook).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('config.options.plugins', function() {
+    it('should call plugins with options at last argument', function() {
+      var plugin = {id: 'foo', hook: function() {}};
+
+      var chart = window.acquireChart({
+        options: {
+          plugins: {
+            foo: {a: '123'},
+          }
+        }
+      });
+
+      spyOn(plugin, 'hook');
+
+      Chart.register(plugin);
+      chart.notifyPlugins('hook');
+      chart.notifyPlugins('hook', {arg1: 'bla'});
+      chart.notifyPlugins('hook', {arg1: 'bla', arg2: 42});
+
+      expect(plugin.hook.calls.count()).toBe(3);
+      expect(plugin.hook.calls.argsFor(0)[2]).toEqual({a: '123'});
+      expect(plugin.hook.calls.argsFor(1)[2]).toEqual({a: '123'});
+      expect(plugin.hook.calls.argsFor(2)[2]).toEqual({a: '123'});
+
+      Chart.unregister(plugin);
+    });
+
+    it('should call plugins with options associated to their identifier', function() {
+      var plugins = {
+        a: {id: 'a', hook: function() {}},
+        b: {id: 'b', hook: function() {}},
+        c: {id: 'c', hook: function() {}}
+      };
+
+      Chart.register(plugins.a);
+
+      var chart = window.acquireChart({
+        plugins: [plugins.b, plugins.c],
+        options: {
+          plugins: {
+            a: {a: '123'},
+            b: {b: '456'},
+            c: {c: '789'}
+          }
+        }
+      });
+
+      spyOn(plugins.a, 'hook');
+      spyOn(plugins.b, 'hook');
+      spyOn(plugins.c, 'hook');
+
+      chart.notifyPlugins('hook');
+
+      expect(plugins.a.hook).toHaveBeenCalled();
+      expect(plugins.b.hook).toHaveBeenCalled();
+      expect(plugins.c.hook).toHaveBeenCalled();
+      expect(plugins.a.hook.calls.first().args[2]).toEqual({a: '123'});
+      expect(plugins.b.hook.calls.first().args[2]).toEqual({b: '456'});
+      expect(plugins.c.hook.calls.first().args[2]).toEqual({c: '789'});
+
+      Chart.unregister(plugins.a);
+    });
+
+    it('should not called plugins when config.options.plugins.{id} is FALSE', function() {
+      var plugins = {
+        a: {id: 'a', hook: function() {}},
+        b: {id: 'b', hook: function() {}},
+        c: {id: 'c', hook: function() {}}
+      };
+
+      Chart.register(plugins.a);
+
+      var chart = window.acquireChart({
+        plugins: [plugins.b, plugins.c],
+        options: {
+          plugins: {
+            a: false,
+            b: false
+          }
+        }
+      });
+
+      spyOn(plugins.a, 'hook');
+      spyOn(plugins.b, 'hook');
+      spyOn(plugins.c, 'hook');
+
+      chart.notifyPlugins('hook');
+
+      expect(plugins.a.hook).not.toHaveBeenCalled();
+      expect(plugins.b.hook).not.toHaveBeenCalled();
+      expect(plugins.c.hook).toHaveBeenCalled();
+
+      Chart.unregister(plugins.a);
+    });
+
+    it('should call plugins with default options when plugin options is TRUE', function() {
+      var plugin = {id: 'a', hook: function() {}, defaults: {a: 42}};
+
+      Chart.register(plugin);
+
+      var chart = window.acquireChart({
+        options: {
+          plugins: {
+            a: true
+          }
+        }
+      });
+
+      spyOn(plugin, 'hook');
+
+      chart.notifyPlugins('hook');
+
+      expect(plugin.hook).toHaveBeenCalled();
+      expect(plugin.hook.calls.first().args[2]).toEqual({a: 42});
+
+      Chart.unregister(plugin);
+    });
 
 
-               it('should call plugins with default options if plugin config options is undefined', function() {
-                       var plugin = {id: 'a', hook: function() {}, defaults: {a: 'foobar'}};
-
-                       Chart.register(plugin);
-                       spyOn(plugin, 'hook');
-
-                       var chart = window.acquireChart();
+    it('should call plugins with default options if plugin config options is undefined', function() {
+      var plugin = {id: 'a', hook: function() {}, defaults: {a: 'foobar'}};
+
+      Chart.register(plugin);
+      spyOn(plugin, 'hook');
+
+      var chart = window.acquireChart();
 
-                       chart.notifyPlugins('hook');
-
-                       expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[2]).toEqual({a: 'foobar'});
+      chart.notifyPlugins('hook');
+
+      expect(plugin.hook).toHaveBeenCalled();
+      expect(plugin.hook.calls.first().args[2]).toEqual({a: 'foobar'});
 
-                       Chart.unregister(plugin);
-               });
+      Chart.unregister(plugin);
+    });
 
-               // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
-               it('should update plugin options', function() {
-                       var plugin = {id: 'a', hook: function() {}};
-                       var chart = window.acquireChart({
-                               plugins: [plugin],
-                               options: {
-                                       plugins: {
-                                               a: {
-                                                       foo: 'foo'
-                                               }
-                                       }
-                               },
-                       });
+    // https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
+    it('should update plugin options', function() {
+      var plugin = {id: 'a', hook: function() {}};
+      var chart = window.acquireChart({
+        plugins: [plugin],
+        options: {
+          plugins: {
+            a: {
+              foo: 'foo'
+            }
+          }
+        },
+      });
 
-                       spyOn(plugin, 'hook');
+      spyOn(plugin, 'hook');
 
-                       chart.notifyPlugins('hook');
+      chart.notifyPlugins('hook');
 
-                       expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[2]).toEqual({foo: 'foo'});
+      expect(plugin.hook).toHaveBeenCalled();
+      expect(plugin.hook.calls.first().args[2]).toEqual({foo: 'foo'});
 
-                       chart.options.plugins.a = {bar: 'bar'};
-                       chart.update();
+      chart.options.plugins.a = {bar: 'bar'};
+      chart.update();
 
-                       plugin.hook.calls.reset();
-                       chart.notifyPlugins('hook');
+      plugin.hook.calls.reset();
+      chart.notifyPlugins('hook');
 
-                       expect(plugin.hook).toHaveBeenCalled();
-                       expect(plugin.hook.calls.first().args[2]).toEqual({bar: 'bar'});
-               });
+      expect(plugin.hook).toHaveBeenCalled();
+      expect(plugin.hook.calls.first().args[2]).toEqual({bar: 'bar'});
+    });
 
-               it('should disable all plugins', function() {
-                       var plugin = {id: 'a', hook: function() {}};
-                       var chart = window.acquireChart({
-                               plugins: [plugin],
-                               options: {
-                                       plugins: false
-                               }
-                       });
+    it('should disable all plugins', function() {
+      var plugin = {id: 'a', hook: function() {}};
+      var chart = window.acquireChart({
+        plugins: [plugin],
+        options: {
+          plugins: false
+        }
+      });
 
-                       spyOn(plugin, 'hook');
+      spyOn(plugin, 'hook');
 
-                       chart.notifyPlugins('hook');
+      chart.notifyPlugins('hook');
 
-                       expect(plugin.hook).not.toHaveBeenCalled();
-               });
+      expect(plugin.hook).not.toHaveBeenCalled();
+    });
 
-               it('should not restart plugins when a double register occurs', function() {
-                       var results = [];
-                       var chart = window.acquireChart({
-                               plugins: [{
-                                       start: function() {
-                                               results.push(1);
-                                       }
-                               }]
-                       });
+    it('should not restart plugins when a double register occurs', function() {
+      var results = [];
+      var chart = window.acquireChart({
+        plugins: [{
+          start: function() {
+            results.push(1);
+          }
+        }]
+      });
 
-                       Chart.register({id: 'abc', hook: function() {}});
-                       Chart.register({id: 'def', hook: function() {}});
+      Chart.register({id: 'abc', hook: function() {}});
+      Chart.register({id: 'def', hook: function() {}});
 
-                       chart.update();
+      chart.update();
 
-                       // The plugin on the chart should only be started once
-                       expect(results).toEqual([1]);
-               });
-       });
+      // The plugin on the chart should only be started once
+      expect(results).toEqual([1]);
+    });
+  });
 });
index 05540390e38310679f2f24eee87cf883f6073973..ade0ffdb33a77dd3cb8fad7885c963aa4a4e8ab5 100644 (file)
 describe('Chart.registry', function() {
-       it('should handle an ES6 controller extension', function() {
-               class CustomController extends Chart.DatasetController {}
-               CustomController.id = 'custom';
-               CustomController.defaults = {
-                       foo: 'bar'
-               };
-               Chart.register(CustomController);
-
-               expect(Chart.registry.getController('custom')).toEqual(CustomController);
-               expect(Chart.defaults.controllers.custom).toEqual(CustomController.defaults);
-
-               Chart.unregister(CustomController);
-
-               expect(function() {
-                       Chart.registry.getController('custom');
-               }).toThrow(new Error('"custom" is not a registered controller.'));
-               expect(Chart.defaults.controllers.custom).not.toBeDefined();
-       });
-
-       it('should handle an ES6 scale extension', function() {
-               class CustomScale extends Chart.Scale {}
-               CustomScale.id = 'es6Scale';
-               CustomScale.defaults = {
-                       foo: 'bar'
-               };
-               Chart.register(CustomScale);
-
-               expect(Chart.registry.getScale('es6Scale')).toEqual(CustomScale);
-               expect(Chart.defaults.scales.es6Scale).toEqual(CustomScale.defaults);
-
-               Chart.unregister(CustomScale);
-
-               expect(function() {
-                       Chart.registry.getScale('es6Scale');
-               }).toThrow(new Error('"es6Scale" is not a registered scale.'));
-               expect(Chart.defaults.controllers.custom).not.toBeDefined();
-       });
-
-       it('should handle an ES6 element extension', function() {
-               class CustomElement extends Chart.Element {}
-               CustomElement.id = 'es6element';
-               CustomElement.defaults = {
-                       foo: 'bar'
-               };
-               Chart.register(CustomElement);
-
-               expect(Chart.registry.getElement('es6element')).toEqual(CustomElement);
-               expect(Chart.defaults.elements.es6element).toEqual(CustomElement.defaults);
-
-               Chart.unregister(CustomElement);
-
-               expect(function() {
-                       Chart.registry.getElement('es6element');
-               }).toThrow(new Error('"es6element" is not a registered element.'));
-               expect(Chart.defaults.elements.es6element).not.toBeDefined();
-       });
-
-       it('should handle an ES6 plugin', function() {
-               class CustomPlugin {}
-               CustomPlugin.id = 'es6plugin';
-               CustomPlugin.defaults = {
-                       foo: 'bar'
-               };
-               Chart.register(CustomPlugin);
-
-               expect(Chart.registry.getPlugin('es6plugin')).toEqual(CustomPlugin);
-               expect(Chart.defaults.plugins.es6plugin).toEqual(CustomPlugin.defaults);
-
-               Chart.unregister(CustomPlugin);
-
-               expect(function() {
-                       Chart.registry.getPlugin('es6plugin');
-               }).toThrow(new Error('"es6plugin" is not a registered plugin.'));
-               expect(Chart.defaults.plugins.es6plugin).not.toBeDefined();
-       });
-
-       it('should not accept an object without id', function() {
-               expect(function() {
-                       Chart.register({foo: 'bar'});
-               }).toThrow(new Error('class does not have id: bar'));
-
-               class FaultyPlugin {}
-
-               expect(function() {
-                       Chart.register(FaultyPlugin);
-               }).toThrow(new Error('class does not have id: class FaultyPlugin {}'));
-       });
-
-       it('should not fail when unregistering an object that is not registered', function() {
-               expect(function() {
-                       Chart.unregister({id: 'foo'});
-               }).not.toThrow();
-       });
-
-       describe('Should allow registering explicitly', function() {
-               class customExtension {}
-               customExtension.id = 'custom';
-               customExtension.defaults = {
-                       prop: true
-               };
-
-               it('as controller', function() {
-                       Chart.registry.addControllers(customExtension);
-
-                       expect(Chart.registry.getController('custom')).toEqual(customExtension);
-                       expect(Chart.defaults.controllers.custom).toEqual(customExtension.defaults);
-
-                       Chart.registry.removeControllers(customExtension);
-
-                       expect(function() {
-                               Chart.registry.getController('custom');
-                       }).toThrow(new Error('"custom" is not a registered controller.'));
-                       expect(Chart.defaults.controllers.custom).not.toBeDefined();
-               });
-
-               it('as scale', function() {
-                       Chart.registry.addScales(customExtension);
-
-                       expect(Chart.registry.getScale('custom')).toEqual(customExtension);
-                       expect(Chart.defaults.scales.custom).toEqual(customExtension.defaults);
-
-                       Chart.registry.removeScales(customExtension);
-
-                       expect(function() {
-                               Chart.registry.getScale('custom');
-                       }).toThrow(new Error('"custom" is not a registered scale.'));
-                       expect(Chart.defaults.scales.custom).not.toBeDefined();
-               });
-
-               it('as element', function() {
-                       Chart.registry.addElements(customExtension);
-
-                       expect(Chart.registry.getElement('custom')).toEqual(customExtension);
-                       expect(Chart.defaults.elements.custom).toEqual(customExtension.defaults);
-
-                       Chart.registry.removeElements(customExtension);
-
-                       expect(function() {
-                               Chart.registry.getElement('custom');
-                       }).toThrow(new Error('"custom" is not a registered element.'));
-                       expect(Chart.defaults.elements.custom).not.toBeDefined();
-               });
-
-               it('as plugin', function() {
-                       Chart.registry.addPlugins(customExtension);
-
-                       expect(Chart.registry.getPlugin('custom')).toEqual(customExtension);
-                       expect(Chart.defaults.plugins.custom).toEqual(customExtension.defaults);
-
-                       Chart.registry.removePlugins(customExtension);
-
-                       expect(function() {
-                               Chart.registry.getPlugin('custom');
-                       }).toThrow(new Error('"custom" is not a registered plugin.'));
-                       expect(Chart.defaults.plugins.custom).not.toBeDefined();
-               });
-       });
-
-       it('should fire before/after callbacks', function() {
-               let beforeRegisterCount = 0;
-               let afterRegisterCount = 0;
-               let beforeUnregisterCount = 0;
-               let afterUnregisterCount = 0;
-               class custom {}
-               custom.id = 'custom';
-               custom.beforeRegister = () => beforeRegisterCount++;
-               custom.afterRegister = () => afterRegisterCount++;
-               custom.beforeUnregister = () => beforeUnregisterCount++;
-               custom.afterUnregister = () => afterUnregisterCount++;
-
-               Chart.registry.addControllers(custom);
-               expect(beforeRegisterCount).withContext('beforeRegister').toBe(1);
-               expect(afterRegisterCount).withContext('afterRegister').toBe(1);
-               Chart.registry.removeControllers(custom);
-               expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(1);
-               expect(afterUnregisterCount).withContext('afterUnregister').toBe(1);
-
-               Chart.registry.addScales(custom);
-               expect(beforeRegisterCount).withContext('beforeRegister').toBe(2);
-               expect(afterRegisterCount).withContext('afterRegister').toBe(2);
-               Chart.registry.removeScales(custom);
-               expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(2);
-               expect(afterUnregisterCount).withContext('afterUnregister').toBe(2);
-
-               Chart.registry.addElements(custom);
-               expect(beforeRegisterCount).withContext('beforeRegister').toBe(3);
-               expect(afterRegisterCount).withContext('afterRegister').toBe(3);
-               Chart.registry.removeElements(custom);
-               expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(3);
-               expect(afterUnregisterCount).withContext('afterUnregister').toBe(3);
-
-               Chart.register(custom);
-               expect(beforeRegisterCount).withContext('beforeRegister').toBe(4);
-               expect(afterRegisterCount).withContext('afterRegister').toBe(4);
-               Chart.unregister(custom);
-               expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(4);
-               expect(afterUnregisterCount).withContext('afterUnregister').toBe(4);
-       });
-
-       it('should preserve existing defaults', function() {
-               Chart.defaults.controllers.test = {test1: true};
-
-               class testController extends Chart.DatasetController {}
-               testController.id = 'test';
-               testController.defaults = {test1: false, test2: true};
-
-               Chart.register(testController);
-               expect(Chart.defaults.controllers.test).toEqual({test1: true, test2: true});
-
-               Chart.unregister(testController);
-               expect(Chart.defaults.controllers.test).not.toBeDefined();
-       });
-
-       describe('should handle multiple items', function() {
-               class test1 extends Chart.DatasetController {}
-               test1.id = 'test1';
-               class test2 extends Chart.Scale {}
-               test2.id = 'test2';
-
-               it('separately', function() {
-                       Chart.register(test1, test2);
-                       expect(Chart.registry.getController('test1')).toEqual(test1);
-                       expect(Chart.registry.getScale('test2')).toEqual(test2);
-                       Chart.unregister(test1, test2);
-                       expect(function() {
-                               Chart.registry.getController('test1');
-                       }).toThrow();
-                       expect(function() {
-                               Chart.registry.getScale('test2');
-                       }).toThrow();
-               });
-
-               it('as array', function() {
-                       Chart.register([test1, test2]);
-                       expect(Chart.registry.getController('test1')).toEqual(test1);
-                       expect(Chart.registry.getScale('test2')).toEqual(test2);
-                       Chart.unregister([test1, test2]);
-                       expect(function() {
-                               Chart.registry.getController('test1');
-                       }).toThrow();
-                       expect(function() {
-                               Chart.registry.getScale('test2');
-                       }).toThrow();
-               });
-
-               it('as object', function() {
-                       Chart.register({test1, test2});
-                       expect(Chart.registry.getController('test1')).toEqual(test1);
-                       expect(Chart.registry.getScale('test2')).toEqual(test2);
-                       Chart.unregister({test1, test2});
-                       expect(function() {
-                               Chart.registry.getController('test1');
-                       }).toThrow();
-                       expect(function() {
-                               Chart.registry.getScale('test2');
-                       }).toThrow();
-               });
-       });
+  it('should handle an ES6 controller extension', function() {
+    class CustomController extends Chart.DatasetController {}
+    CustomController.id = 'custom';
+    CustomController.defaults = {
+      foo: 'bar'
+    };
+    Chart.register(CustomController);
+
+    expect(Chart.registry.getController('custom')).toEqual(CustomController);
+    expect(Chart.defaults.controllers.custom).toEqual(CustomController.defaults);
+
+    Chart.unregister(CustomController);
+
+    expect(function() {
+      Chart.registry.getController('custom');
+    }).toThrow(new Error('"custom" is not a registered controller.'));
+    expect(Chart.defaults.controllers.custom).not.toBeDefined();
+  });
+
+  it('should handle an ES6 scale extension', function() {
+    class CustomScale extends Chart.Scale {}
+    CustomScale.id = 'es6Scale';
+    CustomScale.defaults = {
+      foo: 'bar'
+    };
+    Chart.register(CustomScale);
+
+    expect(Chart.registry.getScale('es6Scale')).toEqual(CustomScale);
+    expect(Chart.defaults.scales.es6Scale).toEqual(CustomScale.defaults);
+
+    Chart.unregister(CustomScale);
+
+    expect(function() {
+      Chart.registry.getScale('es6Scale');
+    }).toThrow(new Error('"es6Scale" is not a registered scale.'));
+    expect(Chart.defaults.controllers.custom).not.toBeDefined();
+  });
+
+  it('should handle an ES6 element extension', function() {
+    class CustomElement extends Chart.Element {}
+    CustomElement.id = 'es6element';
+    CustomElement.defaults = {
+      foo: 'bar'
+    };
+    Chart.register(CustomElement);
+
+    expect(Chart.registry.getElement('es6element')).toEqual(CustomElement);
+    expect(Chart.defaults.elements.es6element).toEqual(CustomElement.defaults);
+
+    Chart.unregister(CustomElement);
+
+    expect(function() {
+      Chart.registry.getElement('es6element');
+    }).toThrow(new Error('"es6element" is not a registered element.'));
+    expect(Chart.defaults.elements.es6element).not.toBeDefined();
+  });
+
+  it('should handle an ES6 plugin', function() {
+    class CustomPlugin {}
+    CustomPlugin.id = 'es6plugin';
+    CustomPlugin.defaults = {
+      foo: 'bar'
+    };
+    Chart.register(CustomPlugin);
+
+    expect(Chart.registry.getPlugin('es6plugin')).toEqual(CustomPlugin);
+    expect(Chart.defaults.plugins.es6plugin).toEqual(CustomPlugin.defaults);
+
+    Chart.unregister(CustomPlugin);
+
+    expect(function() {
+      Chart.registry.getPlugin('es6plugin');
+    }).toThrow(new Error('"es6plugin" is not a registered plugin.'));
+    expect(Chart.defaults.plugins.es6plugin).not.toBeDefined();
+  });
+
+  it('should not accept an object without id', function() {
+    expect(function() {
+      Chart.register({foo: 'bar'});
+    }).toThrow(new Error('class does not have id: bar'));
+
+    class FaultyPlugin {}
+
+    expect(function() {
+      Chart.register(FaultyPlugin);
+    }).toThrow(new Error('class does not have id: class FaultyPlugin {}'));
+  });
+
+  it('should not fail when unregistering an object that is not registered', function() {
+    expect(function() {
+      Chart.unregister({id: 'foo'});
+    }).not.toThrow();
+  });
+
+  describe('Should allow registering explicitly', function() {
+    class customExtension {}
+    customExtension.id = 'custom';
+    customExtension.defaults = {
+      prop: true
+    };
+
+    it('as controller', function() {
+      Chart.registry.addControllers(customExtension);
+
+      expect(Chart.registry.getController('custom')).toEqual(customExtension);
+      expect(Chart.defaults.controllers.custom).toEqual(customExtension.defaults);
+
+      Chart.registry.removeControllers(customExtension);
+
+      expect(function() {
+        Chart.registry.getController('custom');
+      }).toThrow(new Error('"custom" is not a registered controller.'));
+      expect(Chart.defaults.controllers.custom).not.toBeDefined();
+    });
+
+    it('as scale', function() {
+      Chart.registry.addScales(customExtension);
+
+      expect(Chart.registry.getScale('custom')).toEqual(customExtension);
+      expect(Chart.defaults.scales.custom).toEqual(customExtension.defaults);
+
+      Chart.registry.removeScales(customExtension);
+
+      expect(function() {
+        Chart.registry.getScale('custom');
+      }).toThrow(new Error('"custom" is not a registered scale.'));
+      expect(Chart.defaults.scales.custom).not.toBeDefined();
+    });
+
+    it('as element', function() {
+      Chart.registry.addElements(customExtension);
+
+      expect(Chart.registry.getElement('custom')).toEqual(customExtension);
+      expect(Chart.defaults.elements.custom).toEqual(customExtension.defaults);
+
+      Chart.registry.removeElements(customExtension);
+
+      expect(function() {
+        Chart.registry.getElement('custom');
+      }).toThrow(new Error('"custom" is not a registered element.'));
+      expect(Chart.defaults.elements.custom).not.toBeDefined();
+    });
+
+    it('as plugin', function() {
+      Chart.registry.addPlugins(customExtension);
+
+      expect(Chart.registry.getPlugin('custom')).toEqual(customExtension);
+      expect(Chart.defaults.plugins.custom).toEqual(customExtension.defaults);
+
+      Chart.registry.removePlugins(customExtension);
+
+      expect(function() {
+        Chart.registry.getPlugin('custom');
+      }).toThrow(new Error('"custom" is not a registered plugin.'));
+      expect(Chart.defaults.plugins.custom).not.toBeDefined();
+    });
+  });
+
+  it('should fire before/after callbacks', function() {
+    let beforeRegisterCount = 0;
+    let afterRegisterCount = 0;
+    let beforeUnregisterCount = 0;
+    let afterUnregisterCount = 0;
+    class custom {}
+    custom.id = 'custom';
+    custom.beforeRegister = () => beforeRegisterCount++;
+    custom.afterRegister = () => afterRegisterCount++;
+    custom.beforeUnregister = () => beforeUnregisterCount++;
+    custom.afterUnregister = () => afterUnregisterCount++;
+
+    Chart.registry.addControllers(custom);
+    expect(beforeRegisterCount).withContext('beforeRegister').toBe(1);
+    expect(afterRegisterCount).withContext('afterRegister').toBe(1);
+    Chart.registry.removeControllers(custom);
+    expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(1);
+    expect(afterUnregisterCount).withContext('afterUnregister').toBe(1);
+
+    Chart.registry.addScales(custom);
+    expect(beforeRegisterCount).withContext('beforeRegister').toBe(2);
+    expect(afterRegisterCount).withContext('afterRegister').toBe(2);
+    Chart.registry.removeScales(custom);
+    expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(2);
+    expect(afterUnregisterCount).withContext('afterUnregister').toBe(2);
+
+    Chart.registry.addElements(custom);
+    expect(beforeRegisterCount).withContext('beforeRegister').toBe(3);
+    expect(afterRegisterCount).withContext('afterRegister').toBe(3);
+    Chart.registry.removeElements(custom);
+    expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(3);
+    expect(afterUnregisterCount).withContext('afterUnregister').toBe(3);
+
+    Chart.register(custom);
+    expect(beforeRegisterCount).withContext('beforeRegister').toBe(4);
+    expect(afterRegisterCount).withContext('afterRegister').toBe(4);
+    Chart.unregister(custom);
+    expect(beforeUnregisterCount).withContext('beforeUnregister').toBe(4);
+    expect(afterUnregisterCount).withContext('afterUnregister').toBe(4);
+  });
+
+  it('should preserve existing defaults', function() {
+    Chart.defaults.controllers.test = {test1: true};
+
+    class testController extends Chart.DatasetController {}
+    testController.id = 'test';
+    testController.defaults = {test1: false, test2: true};
+
+    Chart.register(testController);
+    expect(Chart.defaults.controllers.test).toEqual({test1: true, test2: true});
+
+    Chart.unregister(testController);
+    expect(Chart.defaults.controllers.test).not.toBeDefined();
+  });
+
+  describe('should handle multiple items', function() {
+    class test1 extends Chart.DatasetController {}
+    test1.id = 'test1';
+    class test2 extends Chart.Scale {}
+    test2.id = 'test2';
+
+    it('separately', function() {
+      Chart.register(test1, test2);
+      expect(Chart.registry.getController('test1')).toEqual(test1);
+      expect(Chart.registry.getScale('test2')).toEqual(test2);
+      Chart.unregister(test1, test2);
+      expect(function() {
+        Chart.registry.getController('test1');
+      }).toThrow();
+      expect(function() {
+        Chart.registry.getScale('test2');
+      }).toThrow();
+    });
+
+    it('as array', function() {
+      Chart.register([test1, test2]);
+      expect(Chart.registry.getController('test1')).toEqual(test1);
+      expect(Chart.registry.getScale('test2')).toEqual(test2);
+      Chart.unregister([test1, test2]);
+      expect(function() {
+        Chart.registry.getController('test1');
+      }).toThrow();
+      expect(function() {
+        Chart.registry.getScale('test2');
+      }).toThrow();
+    });
+
+    it('as object', function() {
+      Chart.register({test1, test2});
+      expect(Chart.registry.getController('test1')).toEqual(test1);
+      expect(Chart.registry.getScale('test2')).toEqual(test2);
+      Chart.unregister({test1, test2});
+      expect(function() {
+        Chart.registry.getController('test1');
+      }).toThrow();
+      expect(function() {
+        Chart.registry.getScale('test2');
+      }).toThrow();
+    });
+  });
 });
index e4b8fb8224105817edf78c0f1d315ea3ac1cc1a6..58560745d50913f84075533386ba6d245dc0affa 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Core.scale', function() {
-       describe('auto', jasmine.fixture.specs('core.scale'));
-
-       it('should provide default scale label options', function() {
-               expect(Chart.defaults.scale.scaleLabel).toEqual({
-                       color: Chart.defaults.color,
-                       display: false,
-                       labelString: '',
-                       padding: {
-                               top: 4,
-                               bottom: 4
-                       }
-               });
-       });
-
-       describe('displaying xAxis ticks with autoSkip=true', function() {
-               function getChart(data) {
-                       return window.acquireChart({
-                               type: 'line',
-                               data: data,
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       ticks: {
-                                                               autoSkip: true
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-               }
-
-               function lastTick(chart) {
-                       var xAxis = chart.scales.x;
-                       var ticks = xAxis.getTicks();
-                       return ticks[ticks.length - 1];
-               }
-
-               it('should display the last tick if it fits evenly with other ticks', function() {
-                       var chart = getChart({
-                               labels: [
-                                       'January 2018', 'February 2018', 'March 2018', 'April 2018',
-                                       'May 2018', 'June 2018', 'July 2018', 'August 2018',
-                                       'September 2018'
-                               ],
-                               datasets: [{
-                                       data: [12, 19, 3, 5, 2, 3, 7, 8, 9]
-                               }]
-                       });
-
-                       expect(lastTick(chart).label).toEqual('September 2018');
-               });
-
-               it('should not display the last tick if it does not fit evenly', function() {
-                       var chart = getChart({
-                               labels: [
-                                       'January 2018', 'February 2018', 'March 2018', 'April 2018',
-                                       'May 2018', 'June 2018', 'July 2018', 'August 2018',
-                                       'September 2018', 'October 2018', 'November 2018', 'December 2018',
-                                       'January 2019', 'February 2019', 'March 2019', 'April 2019',
-                                       'May 2019', 'June 2019', 'July 2019', 'August 2019',
-                                       'September 2019', 'October 2019', 'November 2019', 'December 2019',
-                                       'January 2020', 'February 2020'
-                               ],
-                               datasets: [{
-                                       data: [12, 19, 3, 5, 2, 3, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
-                               }]
-                       });
-
-                       expect(lastTick(chart).label).toEqual('January 2020');
-               });
-       });
-
-       var gridLineTests = [{
-               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-               offsetGridLines: false,
-               offset: false,
-               expected: [0.5, 128.5, 256.5, 384.5, 512.5]
-       }, {
-               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-               offsetGridLines: false,
-               offset: true,
-               expected: [51.5, 153.5, 256.5, 358.5, 460.5]
-       }, {
-               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-               offsetGridLines: true,
-               offset: false,
-               expected: [64.5, 192.5, 320.5, 448.5]
-       }, {
-               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-               offsetGridLines: true,
-               offset: true,
-               expected: [0.5, 102.5, 204.5, 307.5, 409.5, 512.5]
-       }, {
-               labels: ['tick1'],
-               offsetGridLines: false,
-               offset: false,
-               expected: [0.5]
-       }, {
-               labels: ['tick1'],
-               offsetGridLines: false,
-               offset: true,
-               expected: [256.5]
-       }, {
-               labels: ['tick1'],
-               offsetGridLines: true,
-               offset: false,
-               expected: [512.5]
-       }, {
-               labels: ['tick1'],
-               offsetGridLines: true,
-               offset: true,
-               expected: [0.5, 512.5]
-       }];
-
-       gridLineTests.forEach(function(test) {
-               it('should get the correct pixels for gridLine(s) for the horizontal scale when offsetGridLines is ' + test.offsetGridLines + ' and offset is ' + test.offset, function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: []
-                                       }],
-                                       labels: test.labels
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       gridLines: {
-                                                               offsetGridLines: test.offsetGridLines,
-                                                               drawTicks: false
-                                                       },
-                                                       ticks: {
-                                                               display: false
-                                                       },
-                                                       offset: test.offset
-                                               },
-                                               y: {
-                                                       display: false
-                                               }
-                                       },
-                                       plugins: {
-                                               legend: false
-                                       }
-                               }
-                       });
-
-                       var xScale = chart.scales.x;
-                       xScale.ctx = window.createMockContext();
-                       chart.draw();
-
-                       expect(xScale.ctx.getCalls().filter(function(x) {
-                               return x.name === 'moveTo' && x.args[1] === 0;
-                       }).map(function(x) {
-                               return x.args[0];
-                       })).toEqual(test.expected);
-               });
-       });
-
-       gridLineTests.forEach(function(test) {
-               it('should get the correct pixels for gridLine(s) for the vertical scale when offsetGridLines is ' + test.offsetGridLines + ' and offset is ' + test.offset, function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               data: []
-                                       }],
-                                       labels: test.labels
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       display: false
-                                               },
-                                               y: {
-                                                       type: 'category',
-                                                       gridLines: {
-                                                               offsetGridLines: test.offsetGridLines,
-                                                               drawTicks: false
-                                                       },
-                                                       ticks: {
-                                                               display: false
-                                                       },
-                                                       offset: test.offset
-                                               }
-                                       },
-                                       plugins: {
-                                               legend: false
-                                       }
-                               }
-                       });
-
-                       var yScale = chart.scales.y;
-                       yScale.ctx = window.createMockContext();
-                       chart.draw();
-
-                       expect(yScale.ctx.getCalls().filter(function(x) {
-                               return x.name === 'moveTo' && x.args[0] === 1;
-                       }).map(function(x) {
-                               return x.args[1];
-                       })).toEqual(test.expected);
-               });
-       });
-
-       it('should add the correct padding for long tick labels', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: [
-                                       'This is a very long label',
-                                       'This is a very long label'
-                               ],
-                               datasets: [{
-                                       data: [0, 1]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               display: false
-                                       }
-                               },
-                               plugins: {
-                                       legend: false
-                               }
-                       }
-               }, {
-                       canvas: {
-                               height: 100,
-                               width: 200
-                       }
-               });
-
-               var scale = chart.scales.x;
-               expect(scale.left).toBeGreaterThan(100);
-               expect(scale.right).toBeGreaterThan(190);
-       });
-
-       describe('given the axes display option is set to auto', function() {
-               describe('for the x axes', function() {
-                       it('should draw the axes if at least one associated dataset is visible', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: [100, 200, 100, 50],
-                                                       xAxisId: 'foo',
-                                                       hidden: true,
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }, {
-                                                       data: [100, 200, 100, 50],
-                                                       xAxisId: 'foo',
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               display: 'auto'
-                                                       },
-                                                       y: {
-                                                               type: 'category',
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.x;
-                               scale.ctx = window.createMockContext();
-                               chart.draw();
-
-                               expect(scale.ctx.getCalls().length).toBeGreaterThan(0);
-                               expect(scale.height).toBeGreaterThan(0);
-                       });
-
-                       it('should not draw the axes if no associated datasets are visible', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: [100, 200, 100, 50],
-                                                       xAxisId: 'foo',
-                                                       hidden: true,
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               display: 'auto'
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.x;
-                               scale.ctx = window.createMockContext();
-                               chart.draw();
-
-                               expect(scale.ctx.getCalls().length).toBe(0);
-                               expect(scale.height).toBe(0);
-                       });
-               });
-
-               describe('for the y axes', function() {
-                       it('should draw the axes if at least one associated dataset is visible', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: [100, 200, 100, 50],
-                                                       yAxisId: 'foo',
-                                                       hidden: true,
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }, {
-                                                       data: [100, 200, 100, 50],
-                                                       yAxisId: 'foo',
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       y: {
-                                                               display: 'auto'
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.y;
-                               scale.ctx = window.createMockContext();
-                               chart.draw();
-
-                               expect(scale.ctx.getCalls().length).toBeGreaterThan(0);
-                               expect(scale.width).toBeGreaterThan(0);
-                       });
-
-                       it('should not draw the axes if no associated datasets are visible', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               datasets: [{
-                                                       data: [100, 200, 100, 50],
-                                                       yAxisId: 'foo',
-                                                       hidden: true,
-                                                       labels: ['Q1', 'Q2', 'Q3', 'Q4']
-                                               }]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       y: {
-                                                               display: 'auto'
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.y;
-                               scale.ctx = window.createMockContext();
-                               chart.draw();
-
-                               expect(scale.ctx.getCalls().length).toBe(0);
-                               expect(scale.width).toBe(0);
-                       });
-               });
-       });
-
-       describe('afterBuildTicks', function() {
-               it('should allow filtering of ticks', function() {
-                       var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       labels: labels,
-                                                       afterBuildTicks: function(scale) {
-                                                               scale.ticks = scale.ticks.slice(1);
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(getLabels(scale)).toEqual(labels.slice(1));
-               });
-
-               it('should allow no return value from callback', function() {
-                       var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       labels: labels,
-                                                       afterBuildTicks: function() { }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(getLabels(scale)).toEqual(labels);
-               });
-
-               it('should allow empty ticks', function() {
-                       var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'category',
-                                                       labels: labels,
-                                                       afterBuildTicks: function(scale) {
-                                                               scale.ticks = [];
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(scale.ticks.length).toBe(0);
-               });
-       });
-
-       describe('_layers', function() {
-               it('should default to one layer', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(scale._layers().length).toEqual(1);
-               });
-
-               it('should default to one layer for custom scales', function() {
-                       class CustomScale extends Chart.Scale {
-                               draw() {}
-                               convertTicksToLabels() {
-                                       return ['tick'];
-                               }
-                       }
-                       CustomScale.id = 'customScale';
-                       CustomScale.defaults = {};
-                       Chart.register(CustomScale);
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'customScale',
-                                                       gridLines: {
-                                                               z: 10
-                                                       },
-                                                       ticks: {
-                                                               z: 20
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(scale._layers().length).toEqual(1);
-                       expect(scale._layers()[0].z).toEqual(20);
-               });
-
-               it('should default to one layer when z is equal between ticks and grid', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                                       ticks: {
-                                                               z: 10
-                                                       },
-                                                       gridLines: {
-                                                               z: 10
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var scale = chart.scales.x;
-                       expect(scale._layers().length).toEqual(1);
-               });
-
-
-               it('should return 2 layers when z is not equal between ticks and grid', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                                       ticks: {
-                                                               z: 10
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.x._layers().length).toEqual(2);
-
-                       chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                                       gridLines: {
-                                                               z: 11
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.x._layers().length).toEqual(2);
-
-                       chart = window.acquireChart({
-                               type: 'line',
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'linear',
-                                                       ticks: {
-                                                               z: 10
-                                                       },
-                                                       gridLines: {
-                                                               z: 11
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.x._layers().length).toEqual(2);
-
-               });
-
-       });
-
-       describe('min and max', function() {
-               it('should be limited to visible data', function() {
-                       var chart = window.acquireChart({
-                               type: 'scatter',
-                               data: {
-                                       datasets: [{
-                                               data: [{x: 100, y: 100}, {x: -100, y: -100}]
-                                       }, {
-                                               data: [{x: 10, y: 10}, {x: -10, y: -10}]
-                                       }]
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       id: 'x',
-                                                       type: 'linear',
-                                                       min: -20,
-                                                       max: 20
-                                               },
-                                               y: {
-                                                       id: 'y',
-                                                       type: 'linear'
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.x.min).toEqual(-20);
-                       expect(chart.scales.x.max).toEqual(20);
-                       expect(chart.scales.y.min).toEqual(-10);
-                       expect(chart.scales.y.max).toEqual(10);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('core.scale'));
+
+  it('should provide default scale label options', function() {
+    expect(Chart.defaults.scale.scaleLabel).toEqual({
+      color: Chart.defaults.color,
+      display: false,
+      labelString: '',
+      padding: {
+        top: 4,
+        bottom: 4
+      }
+    });
+  });
+
+  describe('displaying xAxis ticks with autoSkip=true', function() {
+    function getChart(data) {
+      return window.acquireChart({
+        type: 'line',
+        data: data,
+        options: {
+          scales: {
+            x: {
+              ticks: {
+                autoSkip: true
+              }
+            }
+          }
+        }
+      });
+    }
+
+    function lastTick(chart) {
+      var xAxis = chart.scales.x;
+      var ticks = xAxis.getTicks();
+      return ticks[ticks.length - 1];
+    }
+
+    it('should display the last tick if it fits evenly with other ticks', function() {
+      var chart = getChart({
+        labels: [
+          'January 2018', 'February 2018', 'March 2018', 'April 2018',
+          'May 2018', 'June 2018', 'July 2018', 'August 2018',
+          'September 2018'
+        ],
+        datasets: [{
+          data: [12, 19, 3, 5, 2, 3, 7, 8, 9]
+        }]
+      });
+
+      expect(lastTick(chart).label).toEqual('September 2018');
+    });
+
+    it('should not display the last tick if it does not fit evenly', function() {
+      var chart = getChart({
+        labels: [
+          'January 2018', 'February 2018', 'March 2018', 'April 2018',
+          'May 2018', 'June 2018', 'July 2018', 'August 2018',
+          'September 2018', 'October 2018', 'November 2018', 'December 2018',
+          'January 2019', 'February 2019', 'March 2019', 'April 2019',
+          'May 2019', 'June 2019', 'July 2019', 'August 2019',
+          'September 2019', 'October 2019', 'November 2019', 'December 2019',
+          'January 2020', 'February 2020'
+        ],
+        datasets: [{
+          data: [12, 19, 3, 5, 2, 3, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
+        }]
+      });
+
+      expect(lastTick(chart).label).toEqual('January 2020');
+    });
+  });
+
+  var gridLineTests = [{
+    labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+    offsetGridLines: false,
+    offset: false,
+    expected: [0.5, 128.5, 256.5, 384.5, 512.5]
+  }, {
+    labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+    offsetGridLines: false,
+    offset: true,
+    expected: [51.5, 153.5, 256.5, 358.5, 460.5]
+  }, {
+    labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+    offsetGridLines: true,
+    offset: false,
+    expected: [64.5, 192.5, 320.5, 448.5]
+  }, {
+    labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+    offsetGridLines: true,
+    offset: true,
+    expected: [0.5, 102.5, 204.5, 307.5, 409.5, 512.5]
+  }, {
+    labels: ['tick1'],
+    offsetGridLines: false,
+    offset: false,
+    expected: [0.5]
+  }, {
+    labels: ['tick1'],
+    offsetGridLines: false,
+    offset: true,
+    expected: [256.5]
+  }, {
+    labels: ['tick1'],
+    offsetGridLines: true,
+    offset: false,
+    expected: [512.5]
+  }, {
+    labels: ['tick1'],
+    offsetGridLines: true,
+    offset: true,
+    expected: [0.5, 512.5]
+  }];
+
+  gridLineTests.forEach(function(test) {
+    it('should get the correct pixels for gridLine(s) for the horizontal scale when offsetGridLines is ' + test.offsetGridLines + ' and offset is ' + test.offset, function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: []
+          }],
+          labels: test.labels
+        },
+        options: {
+          scales: {
+            x: {
+              gridLines: {
+                offsetGridLines: test.offsetGridLines,
+                drawTicks: false
+              },
+              ticks: {
+                display: false
+              },
+              offset: test.offset
+            },
+            y: {
+              display: false
+            }
+          },
+          plugins: {
+            legend: false
+          }
+        }
+      });
+
+      var xScale = chart.scales.x;
+      xScale.ctx = window.createMockContext();
+      chart.draw();
+
+      expect(xScale.ctx.getCalls().filter(function(x) {
+        return x.name === 'moveTo' && x.args[1] === 0;
+      }).map(function(x) {
+        return x.args[0];
+      })).toEqual(test.expected);
+    });
+  });
+
+  gridLineTests.forEach(function(test) {
+    it('should get the correct pixels for gridLine(s) for the vertical scale when offsetGridLines is ' + test.offsetGridLines + ' and offset is ' + test.offset, function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            data: []
+          }],
+          labels: test.labels
+        },
+        options: {
+          scales: {
+            x: {
+              display: false
+            },
+            y: {
+              type: 'category',
+              gridLines: {
+                offsetGridLines: test.offsetGridLines,
+                drawTicks: false
+              },
+              ticks: {
+                display: false
+              },
+              offset: test.offset
+            }
+          },
+          plugins: {
+            legend: false
+          }
+        }
+      });
+
+      var yScale = chart.scales.y;
+      yScale.ctx = window.createMockContext();
+      chart.draw();
+
+      expect(yScale.ctx.getCalls().filter(function(x) {
+        return x.name === 'moveTo' && x.args[0] === 1;
+      }).map(function(x) {
+        return x.args[1];
+      })).toEqual(test.expected);
+    });
+  });
+
+  it('should add the correct padding for long tick labels', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: [
+          'This is a very long label',
+          'This is a very long label'
+        ],
+        datasets: [{
+          data: [0, 1]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            display: false
+          }
+        },
+        plugins: {
+          legend: false
+        }
+      }
+    }, {
+      canvas: {
+        height: 100,
+        width: 200
+      }
+    });
+
+    var scale = chart.scales.x;
+    expect(scale.left).toBeGreaterThan(100);
+    expect(scale.right).toBeGreaterThan(190);
+  });
+
+  describe('given the axes display option is set to auto', function() {
+    describe('for the x axes', function() {
+      it('should draw the axes if at least one associated dataset is visible', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: [100, 200, 100, 50],
+              xAxisId: 'foo',
+              hidden: true,
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }, {
+              data: [100, 200, 100, 50],
+              xAxisId: 'foo',
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }]
+          },
+          options: {
+            scales: {
+              x: {
+                display: 'auto'
+              },
+              y: {
+                type: 'category',
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.x;
+        scale.ctx = window.createMockContext();
+        chart.draw();
+
+        expect(scale.ctx.getCalls().length).toBeGreaterThan(0);
+        expect(scale.height).toBeGreaterThan(0);
+      });
+
+      it('should not draw the axes if no associated datasets are visible', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: [100, 200, 100, 50],
+              xAxisId: 'foo',
+              hidden: true,
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }]
+          },
+          options: {
+            scales: {
+              x: {
+                display: 'auto'
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.x;
+        scale.ctx = window.createMockContext();
+        chart.draw();
+
+        expect(scale.ctx.getCalls().length).toBe(0);
+        expect(scale.height).toBe(0);
+      });
+    });
+
+    describe('for the y axes', function() {
+      it('should draw the axes if at least one associated dataset is visible', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: [100, 200, 100, 50],
+              yAxisId: 'foo',
+              hidden: true,
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }, {
+              data: [100, 200, 100, 50],
+              yAxisId: 'foo',
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }]
+          },
+          options: {
+            scales: {
+              y: {
+                display: 'auto'
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.y;
+        scale.ctx = window.createMockContext();
+        chart.draw();
+
+        expect(scale.ctx.getCalls().length).toBeGreaterThan(0);
+        expect(scale.width).toBeGreaterThan(0);
+      });
+
+      it('should not draw the axes if no associated datasets are visible', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            datasets: [{
+              data: [100, 200, 100, 50],
+              yAxisId: 'foo',
+              hidden: true,
+              labels: ['Q1', 'Q2', 'Q3', 'Q4']
+            }]
+          },
+          options: {
+            scales: {
+              y: {
+                display: 'auto'
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.y;
+        scale.ctx = window.createMockContext();
+        chart.draw();
+
+        expect(scale.ctx.getCalls().length).toBe(0);
+        expect(scale.width).toBe(0);
+      });
+    });
+  });
+
+  describe('afterBuildTicks', function() {
+    it('should allow filtering of ticks', function() {
+      var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              labels: labels,
+              afterBuildTicks: function(scale) {
+                scale.ticks = scale.ticks.slice(1);
+              }
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(getLabels(scale)).toEqual(labels.slice(1));
+    });
+
+    it('should allow no return value from callback', function() {
+      var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              labels: labels,
+              afterBuildTicks: function() { }
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(getLabels(scale)).toEqual(labels);
+    });
+
+    it('should allow empty ticks', function() {
+      var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'category',
+              labels: labels,
+              afterBuildTicks: function(scale) {
+                scale.ticks = [];
+              }
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(scale.ticks.length).toBe(0);
+    });
+  });
+
+  describe('_layers', function() {
+    it('should default to one layer', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'linear',
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(scale._layers().length).toEqual(1);
+    });
+
+    it('should default to one layer for custom scales', function() {
+      class CustomScale extends Chart.Scale {
+        draw() {}
+        convertTicksToLabels() {
+          return ['tick'];
+        }
+      }
+      CustomScale.id = 'customScale';
+      CustomScale.defaults = {};
+      Chart.register(CustomScale);
+
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'customScale',
+              gridLines: {
+                z: 10
+              },
+              ticks: {
+                z: 20
+              }
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(scale._layers().length).toEqual(1);
+      expect(scale._layers()[0].z).toEqual(20);
+    });
+
+    it('should default to one layer when z is equal between ticks and grid', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'linear',
+              ticks: {
+                z: 10
+              },
+              gridLines: {
+                z: 10
+              }
+            }
+          }
+        }
+      });
+
+      var scale = chart.scales.x;
+      expect(scale._layers().length).toEqual(1);
+    });
+
+
+    it('should return 2 layers when z is not equal between ticks and grid', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'linear',
+              ticks: {
+                z: 10
+              }
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.x._layers().length).toEqual(2);
+
+      chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'linear',
+              gridLines: {
+                z: 11
+              }
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.x._layers().length).toEqual(2);
+
+      chart = window.acquireChart({
+        type: 'line',
+        options: {
+          scales: {
+            x: {
+              type: 'linear',
+              ticks: {
+                z: 10
+              },
+              gridLines: {
+                z: 11
+              }
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.x._layers().length).toEqual(2);
+
+    });
+
+  });
+
+  describe('min and max', function() {
+    it('should be limited to visible data', function() {
+      var chart = window.acquireChart({
+        type: 'scatter',
+        data: {
+          datasets: [{
+            data: [{x: 100, y: 100}, {x: -100, y: -100}]
+          }, {
+            data: [{x: 10, y: 10}, {x: -10, y: -10}]
+          }]
+        },
+        options: {
+          scales: {
+            x: {
+              id: 'x',
+              type: 'linear',
+              min: -20,
+              max: 20
+            },
+            y: {
+              id: 'y',
+              type: 'linear'
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.x.min).toEqual(-20);
+      expect(chart.scales.x.max).toEqual(20);
+      expect(chart.scales.y.min).toEqual(-10);
+      expect(chart.scales.y.max).toEqual(10);
+    });
+  });
 });
index 4858c4b803983343702fcbb88dc090f5f1b94dfb..149d19e72e62e40c05acb4eff20b2e28f1ad5b6f 100644 (file)
@@ -1,99 +1,99 @@
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Test tick generators', function() {
-       // formatters are used as default config values so users want to be able to reference them
-       it('Should expose formatters api', function() {
-               expect(typeof Chart.Ticks).toBeDefined();
-               expect(typeof Chart.Ticks.formatters).toBeDefined();
-               expect(typeof Chart.Ticks.formatters.values).toBe('function');
-               expect(typeof Chart.Ticks.formatters.numeric).toBe('function');
-       });
+  // formatters are used as default config values so users want to be able to reference them
+  it('Should expose formatters api', function() {
+    expect(typeof Chart.Ticks).toBeDefined();
+    expect(typeof Chart.Ticks.formatters).toBeDefined();
+    expect(typeof Chart.Ticks.formatters.values).toBe('function');
+    expect(typeof Chart.Ticks.formatters.numeric).toBe('function');
+  });
 
-       it('Should generate linear spaced ticks with correct precision', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom',
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value.toString();
-                                                       }
-                                               }
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
+  it('Should generate linear spaced ticks with correct precision', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: []
+        }],
+      },
+      options: {
+        plugins: {
+          legend: false
+        },
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom',
+            ticks: {
+              callback: function(value) {
+                return value.toString();
+              }
+            }
+          },
+          y: {
+            type: 'linear',
+            ticks: {
+              callback: function(value) {
+                return value.toString();
+              }
+            }
+          }
+        }
+      }
+    });
 
-               var xLabels = getLabels(chart.scales.x);
-               var yLabels = getLabels(chart.scales.y);
+    var xLabels = getLabels(chart.scales.x);
+    var yLabels = getLabels(chart.scales.y);
 
-               expect(xLabels).toEqual(['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
-               expect(yLabels).toEqual(['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
-       });
+    expect(xLabels).toEqual(['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
+    expect(yLabels).toEqual(['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
+  });
 
-       it('Should generate logarithmic spaced ticks with correct precision', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                       },
-                       options: {
-                               plugins: {
-                                       legend: false
-                               },
-                               scales: {
-                                       x: {
-                                               type: 'logarithmic',
-                                               position: 'bottom',
-                                               min: 0.1,
-                                               max: 1,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value.toString();
-                                                       }
-                                               }
-                                       },
-                                       y: {
-                                               type: 'logarithmic',
-                                               min: 0.1,
-                                               max: 1,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
+  it('Should generate logarithmic spaced ticks with correct precision', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: []
+        }],
+      },
+      options: {
+        plugins: {
+          legend: false
+        },
+        scales: {
+          x: {
+            type: 'logarithmic',
+            position: 'bottom',
+            min: 0.1,
+            max: 1,
+            ticks: {
+              callback: function(value) {
+                return value.toString();
+              }
+            }
+          },
+          y: {
+            type: 'logarithmic',
+            min: 0.1,
+            max: 1,
+            ticks: {
+              callback: function(value) {
+                return value.toString();
+              }
+            }
+          }
+        }
+      }
+    });
 
-               var xLabels = getLabels(chart.scales.x);
-               var yLabels = getLabels(chart.scales.y);
+    var xLabels = getLabels(chart.scales.x);
+    var yLabels = getLabels(chart.scales.y);
 
-               expect(xLabels).toEqual(['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
-               expect(yLabels).toEqual(['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
-       });
+    expect(xLabels).toEqual(['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
+    expect(yLabels).toEqual(['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']);
+  });
 });
index 65c03b9913be00f3b70cac8e560a7167b981c2e9..5fe3339deec9e36b5d862d1162e11a4ec7538aec 100644 (file)
 // Test the rectangle element
 
 describe('Arc element tests', function() {
-       it ('should determine if in range', function() {
-               // Mock out the arc as if the controller put it there
-               var arc = new Chart.elements.ArcElement({
-                       startAngle: 0,
-                       endAngle: Math.PI / 2,
-                       x: 0,
-                       y: 0,
-                       innerRadius: 5,
-                       outerRadius: 10,
-               });
+  it ('should determine if in range', function() {
+    // Mock out the arc as if the controller put it there
+    var arc = new Chart.elements.ArcElement({
+      startAngle: 0,
+      endAngle: Math.PI / 2,
+      x: 0,
+      y: 0,
+      innerRadius: 5,
+      outerRadius: 10,
+    });
 
-               expect(arc.inRange(2, 2)).toBe(false);
-               expect(arc.inRange(7, 0)).toBe(true);
-               expect(arc.inRange(0, 11)).toBe(false);
-               expect(arc.inRange(Math.sqrt(32), Math.sqrt(32))).toBe(true);
-               expect(arc.inRange(-1.0 * Math.sqrt(7), Math.sqrt(7))).toBe(false);
-       });
+    expect(arc.inRange(2, 2)).toBe(false);
+    expect(arc.inRange(7, 0)).toBe(true);
+    expect(arc.inRange(0, 11)).toBe(false);
+    expect(arc.inRange(Math.sqrt(32), Math.sqrt(32))).toBe(true);
+    expect(arc.inRange(-1.0 * Math.sqrt(7), Math.sqrt(7))).toBe(false);
+  });
 
-       it ('should determine if in range, when full circle', function() {
-               // Mock out the arc as if the controller put it there
-               var arc = new Chart.elements.ArcElement({
-                       startAngle: -Math.PI,
-                       endAngle: Math.PI * 1.5,
-                       x: 0,
-                       y: 0,
-                       innerRadius: 0,
-                       outerRadius: 10,
-                       circumference: Math.PI * 2
-               });
+  it ('should determine if in range, when full circle', function() {
+    // Mock out the arc as if the controller put it there
+    var arc = new Chart.elements.ArcElement({
+      startAngle: -Math.PI,
+      endAngle: Math.PI * 1.5,
+      x: 0,
+      y: 0,
+      innerRadius: 0,
+      outerRadius: 10,
+      circumference: Math.PI * 2
+    });
 
-               expect(arc.inRange(7, 7)).toBe(true);
-       });
+    expect(arc.inRange(7, 7)).toBe(true);
+  });
 
-       it ('should get the tooltip position', function() {
-               // Mock out the arc as if the controller put it there
-               var arc = new Chart.elements.ArcElement({
-                       startAngle: 0,
-                       endAngle: Math.PI / 2,
-                       x: 0,
-                       y: 0,
-                       innerRadius: 0,
-                       outerRadius: Math.sqrt(2),
-               });
+  it ('should get the tooltip position', function() {
+    // Mock out the arc as if the controller put it there
+    var arc = new Chart.elements.ArcElement({
+      startAngle: 0,
+      endAngle: Math.PI / 2,
+      x: 0,
+      y: 0,
+      innerRadius: 0,
+      outerRadius: Math.sqrt(2),
+    });
 
-               var pos = arc.tooltipPosition();
-               expect(pos.x).toBeCloseTo(0.5);
-               expect(pos.y).toBeCloseTo(0.5);
-       });
+    var pos = arc.tooltipPosition();
+    expect(pos.x).toBeCloseTo(0.5);
+    expect(pos.y).toBeCloseTo(0.5);
+  });
 
-       it ('should get the center', function() {
-               // Mock out the arc as if the controller put it there
-               var arc = new Chart.elements.ArcElement({
-                       startAngle: 0,
-                       endAngle: Math.PI / 2,
-                       x: 0,
-                       y: 0,
-                       innerRadius: 0,
-                       outerRadius: Math.sqrt(2),
-               });
+  it ('should get the center', function() {
+    // Mock out the arc as if the controller put it there
+    var arc = new Chart.elements.ArcElement({
+      startAngle: 0,
+      endAngle: Math.PI / 2,
+      x: 0,
+      y: 0,
+      innerRadius: 0,
+      outerRadius: Math.sqrt(2),
+    });
 
-               var center = arc.getCenterPoint();
-               expect(center.x).toBeCloseTo(0.5, 6);
-               expect(center.y).toBeCloseTo(0.5, 6);
-       });
+    var center = arc.getCenterPoint();
+    expect(center.x).toBeCloseTo(0.5, 6);
+    expect(center.y).toBeCloseTo(0.5, 6);
+  });
 
-       it('should not draw when radius < 0', function() {
-               var ctx = window.createMockContext();
+  it('should not draw when radius < 0', function() {
+    var ctx = window.createMockContext();
 
-               var arc = new Chart.elements.ArcElement({
-                       startAngle: 0,
-                       endAngle: Math.PI / 2,
-                       x: 0,
-                       y: 0,
-                       innerRadius: -0.1,
-                       outerRadius: Math.sqrt(2),
-                       options: {}
-               });
+    var arc = new Chart.elements.ArcElement({
+      startAngle: 0,
+      endAngle: Math.PI / 2,
+      x: 0,
+      y: 0,
+      innerRadius: -0.1,
+      outerRadius: Math.sqrt(2),
+      options: {}
+    });
 
-               arc.draw(ctx);
+    arc.draw(ctx);
 
-               expect(ctx.getCalls().length).toBe(0);
+    expect(ctx.getCalls().length).toBe(0);
 
-               arc = new Chart.elements.ArcElement({
-                       startAngle: 0,
-                       endAngle: Math.PI / 2,
-                       x: 0,
-                       y: 0,
-                       innerRadius: 0,
-                       outerRadius: -1,
-                       options: {}
-               });
+    arc = new Chart.elements.ArcElement({
+      startAngle: 0,
+      endAngle: Math.PI / 2,
+      x: 0,
+      y: 0,
+      innerRadius: 0,
+      outerRadius: -1,
+      options: {}
+    });
 
-               arc.draw(ctx);
+    arc.draw(ctx);
 
-               expect(ctx.getCalls().length).toBe(0);
-       });
+    expect(ctx.getCalls().length).toBe(0);
+  });
 });
index 79e4b7967383b0789b7fb052caca2e5fb61f3a13..128bdddc12e6347670d8355ad327b4c34f66d4e9 100644 (file)
@@ -1,67 +1,67 @@
 // Test the bar element
 
 describe('Bar element tests', function() {
-       it('Should correctly identify as in range', function() {
-               var bar = new Chart.elements.BarElement({
-                       base: 0,
-                       width: 4,
-                       x: 10,
-                       y: 15
-               });
+  it('Should correctly identify as in range', function() {
+    var bar = new Chart.elements.BarElement({
+      base: 0,
+      width: 4,
+      x: 10,
+      y: 15
+    });
 
-               expect(bar.inRange(10, 15)).toBe(true);
-               expect(bar.inRange(10, 10)).toBe(true);
-               expect(bar.inRange(10, 16)).toBe(false);
-               expect(bar.inRange(5, 5)).toBe(false);
+    expect(bar.inRange(10, 15)).toBe(true);
+    expect(bar.inRange(10, 10)).toBe(true);
+    expect(bar.inRange(10, 16)).toBe(false);
+    expect(bar.inRange(5, 5)).toBe(false);
 
-               // Test when the y is below the base (negative bar)
-               var negativeBar = new Chart.elements.BarElement({
-                       base: 0,
-                       width: 4,
-                       x: 10,
-                       y: -15
-               });
+    // Test when the y is below the base (negative bar)
+    var negativeBar = new Chart.elements.BarElement({
+      base: 0,
+      width: 4,
+      x: 10,
+      y: -15
+    });
 
-               expect(negativeBar.inRange(10, -16)).toBe(false);
-               expect(negativeBar.inRange(10, 1)).toBe(false);
-               expect(negativeBar.inRange(10, -5)).toBe(true);
-       });
+    expect(negativeBar.inRange(10, -16)).toBe(false);
+    expect(negativeBar.inRange(10, 1)).toBe(false);
+    expect(negativeBar.inRange(10, -5)).toBe(true);
+  });
 
-       it('should get the correct tooltip position', function() {
-               var bar = new Chart.elements.BarElement({
-                       base: 0,
-                       width: 4,
-                       x: 10,
-                       y: 15
-               });
+  it('should get the correct tooltip position', function() {
+    var bar = new Chart.elements.BarElement({
+      base: 0,
+      width: 4,
+      x: 10,
+      y: 15
+    });
 
-               expect(bar.tooltipPosition()).toEqual({
-                       x: 10,
-                       y: 15,
-               });
+    expect(bar.tooltipPosition()).toEqual({
+      x: 10,
+      y: 15,
+    });
 
-               // Test when the y is below the base (negative bar)
-               var negativeBar = new Chart.elements.BarElement({
-                       base: -10,
-                       width: 4,
-                       x: 10,
-                       y: -15
-               });
+    // Test when the y is below the base (negative bar)
+    var negativeBar = new Chart.elements.BarElement({
+      base: -10,
+      width: 4,
+      x: 10,
+      y: -15
+    });
 
-               expect(negativeBar.tooltipPosition()).toEqual({
-                       x: 10,
-                       y: -15,
-               });
-       });
+    expect(negativeBar.tooltipPosition()).toEqual({
+      x: 10,
+      y: -15,
+    });
+  });
 
-       it('should get the center', function() {
-               var bar = new Chart.elements.BarElement({
-                       base: 0,
-                       width: 4,
-                       x: 10,
-                       y: 15
-               });
+  it('should get the center', function() {
+    var bar = new Chart.elements.BarElement({
+      base: 0,
+      width: 4,
+      x: 10,
+      y: 15
+    });
 
-               expect(bar.getCenterPoint()).toEqual({x: 10, y: 7.5});
-       });
+    expect(bar.getCenterPoint()).toEqual({x: 10, y: 7.5});
+  });
 });
index e29d5c44f6af6415e482cb84701b551d06b92888..b368a3e19aff4297d457976a0b906d20ebb6b852 100644 (file)
@@ -1,35 +1,35 @@
 // Tests for the line element
 describe('Chart.elements.LineElement', function() {
-       describe('auto', jasmine.fixture.specs('element.line'));
+  describe('auto', jasmine.fixture.specs('element.line'));
 
-       it('should be constructed', function() {
-               var line = new Chart.elements.LineElement({
-                       points: [1, 2, 3, 4]
-               });
+  it('should be constructed', function() {
+    var line = new Chart.elements.LineElement({
+      points: [1, 2, 3, 4]
+    });
 
-               expect(line).not.toBe(undefined);
-               expect(line.points).toEqual([1, 2, 3, 4]);
-       });
+    expect(line).not.toBe(undefined);
+    expect(line.points).toEqual([1, 2, 3, 4]);
+  });
 
-       it('should not cache path when animations are enabled', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [0, -1, 0],
-                                       label: 'dataset1',
-                               }],
-                               labels: ['label1', 'label2', 'label3']
-                       },
-                       options: {
-                               animation: {
-                                       duration: 50,
-                                       onComplete: () => {
-                                               expect(chart.getDatasetMeta(0).dataset._path).toBeUndefined();
-                                               done();
-                                       }
-                               }
-                       }
-               });
-       });
+  it('should not cache path when animations are enabled', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [0, -1, 0],
+          label: 'dataset1',
+        }],
+        labels: ['label1', 'label2', 'label3']
+      },
+      options: {
+        animation: {
+          duration: 50,
+          onComplete: () => {
+            expect(chart.getDatasetMeta(0).dataset._path).toBeUndefined();
+            done();
+          }
+        }
+      }
+    });
+  });
 });
index c73c6192c27930c5e9d6a3472ac689ba22222106..90526e6f72faa66fa103bf23e24633cbadb058db 100644 (file)
@@ -1,69 +1,69 @@
 describe('Chart.elements.PointElement', function() {
-       describe('auto', jasmine.fixture.specs('element.point'));
+  describe('auto', jasmine.fixture.specs('element.point'));
 
-       it ('Should correctly identify as in range', function() {
-               // Mock out the point as if we were made by the controller
-               var point = new Chart.elements.PointElement({
-                       options: {
-                               radius: 2,
-                               hitRadius: 3,
-                       },
-                       x: 10,
-                       y: 15
-               });
+  it ('Should correctly identify as in range', function() {
+    // Mock out the point as if we were made by the controller
+    var point = new Chart.elements.PointElement({
+      options: {
+        radius: 2,
+        hitRadius: 3,
+      },
+      x: 10,
+      y: 15
+    });
 
-               expect(point.inRange(10, 15)).toBe(true);
-               expect(point.inRange(10, 10)).toBe(false);
-               expect(point.inRange(10, 5)).toBe(false);
-               expect(point.inRange(5, 5)).toBe(false);
-       });
+    expect(point.inRange(10, 15)).toBe(true);
+    expect(point.inRange(10, 10)).toBe(false);
+    expect(point.inRange(10, 5)).toBe(false);
+    expect(point.inRange(5, 5)).toBe(false);
+  });
 
-       it ('should get the correct tooltip position', function() {
-               // Mock out the point as if we were made by the controller
-               var point = new Chart.elements.PointElement({
-                       options: {
-                               radius: 2,
-                               borderWidth: 6,
-                       },
-                       x: 10,
-                       y: 15
-               });
+  it ('should get the correct tooltip position', function() {
+    // Mock out the point as if we were made by the controller
+    var point = new Chart.elements.PointElement({
+      options: {
+        radius: 2,
+        borderWidth: 6,
+      },
+      x: 10,
+      y: 15
+    });
 
-               expect(point.tooltipPosition()).toEqual({
-                       x: 10,
-                       y: 15
-               });
-       });
+    expect(point.tooltipPosition()).toEqual({
+      x: 10,
+      y: 15
+    });
+  });
 
-       it('should get the correct center point', function() {
-               // Mock out the point as if we were made by the controller
-               var point = new Chart.elements.PointElement({
-                       options: {
-                               radius: 2,
-                       },
-                       x: 10,
-                       y: 10
-               });
+  it('should get the correct center point', function() {
+    // Mock out the point as if we were made by the controller
+    var point = new Chart.elements.PointElement({
+      options: {
+        radius: 2,
+      },
+      x: 10,
+      y: 10
+    });
 
-               expect(point.getCenterPoint()).toEqual({x: 10, y: 10});
-       });
+    expect(point.getCenterPoint()).toEqual({x: 10, y: 10});
+  });
 
-       it ('should not draw if skipped', function() {
-               var mockContext = window.createMockContext();
+  it ('should not draw if skipped', function() {
+    var mockContext = window.createMockContext();
 
-               // Mock out the point as if we were made by the controller
-               var point = new Chart.elements.PointElement({
-                       options: {
-                               radius: 2,
-                               hitRadius: 3,
-                       },
-                       x: 10,
-                       y: 15,
-                       skip: true
-               });
+    // Mock out the point as if we were made by the controller
+    var point = new Chart.elements.PointElement({
+      options: {
+        radius: 2,
+        hitRadius: 3,
+      },
+      x: 10,
+      y: 15,
+      skip: true
+    });
 
-               point.draw(mockContext);
+    point.draw(mockContext);
 
-               expect(mockContext.getCalls()).toEqual([]);
-       });
+    expect(mockContext.getCalls()).toEqual([]);
+  });
 });
index 6974c43bf7a0eb92dd3b7e4e7068088a862f470a..a1fcf4996d1132f0672f2bfd509f81851ac3bf59 100644 (file)
 describe('Default Configs', function() {
-       describe('Bubble Chart', function() {
-               it('should return correct tooltip strings', function() {
-                       var config = Chart.defaults.controllers.bubble;
-                       var chart = window.acquireChart({
-                               type: 'bubble',
-                               data: {
-                                       datasets: [{
-                                               label: 'My dataset',
-                                               data: [{
-                                                       x: 10,
-                                                       y: 12,
-                                                       r: 5
-                                               }]
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       // fake out the tooltip hover and force the tooltip to update
-                       chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[0], datasetIndex: 0, index: 0}];
-                       chart.tooltip.update();
-
-                       // Title is always blank
-                       expect(chart.tooltip.title).toEqual([]);
-                       expect(chart.tooltip.body).toEqual([{
-                               before: [],
-                               lines: ['My dataset: (10, 12, 5)'],
-                               after: []
-                       }]);
-               });
-       });
-
-       describe('Doughnut Chart', function() {
-               it('should return correct tooltip strings', function() {
-                       var config = Chart.defaults.controllers.doughnut;
-                       var chart = window.acquireChart({
-                               type: 'doughnut',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, 30],
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       // fake out the tooltip hover and force the tooltip to update
-                       chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
-                       chart.tooltip.update();
-
-                       // Title is always blank
-                       expect(chart.tooltip.title).toEqual([]);
-                       expect(chart.tooltip.body).toEqual([{
-                               before: [],
-                               lines: ['label2: 20'],
-                               after: []
-                       }]);
-               });
-
-               it('should return correct tooltip string for a multiline label', function() {
-                       var config = Chart.defaults.controllers.doughnut;
-                       var chart = window.acquireChart({
-                               type: 'doughnut',
-                               data: {
-                                       labels: ['label1', ['row1', 'row2', 'row3'], 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, 30],
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       // fake out the tooltip hover and force the tooltip to update
-                       chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
-                       chart.tooltip.update();
-
-                       // Title is always blank
-                       expect(chart.tooltip.title).toEqual([]);
-                       expect(chart.tooltip.body).toEqual([{
-                               before: [],
-                               lines: [
-                                       'row1: 20',
-                                       'row2',
-                                       'row3'
-                               ],
-                               after: []
-                       }]);
-               });
-
-               it('should return correct legend label objects', function() {
-                       var config = Chart.defaults.controllers.doughnut;
-                       var chart = window.acquireChart({
-                               type: 'doughnut',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, NaN],
-                                               backgroundColor: ['red', 'green', 'blue'],
-                                               borderWidth: 2,
-                                               borderColor: '#000'
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       var expected = [{
-                               text: 'label1',
-                               fillStyle: 'red',
-                               hidden: false,
-                               index: 0,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }, {
-                               text: 'label2',
-                               fillStyle: 'green',
-                               hidden: false,
-                               index: 1,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }, {
-                               text: 'label3',
-                               fillStyle: 'blue',
-                               hidden: false,
-                               index: 2,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }];
-                       expect(chart.legend.legendItems).toEqual(expected);
-               });
-
-               it('should hide the correct arc when a legend item is clicked', function() {
-                       var config = Chart.defaults.controllers.doughnut;
-                       var chart = window.acquireChart({
-                               type: 'doughnut',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, NaN],
-                                               backgroundColor: ['red', 'green', 'blue'],
-                                               borderWidth: 2,
-                                               borderColor: '#000'
-                                       }]
-                               },
-                               options: config
-                       });
-                       spyOn(chart, 'update').and.callThrough();
-
-                       var legendItem = chart.legend.legendItems[0];
-                       config.plugins.legend.onClick(null, legendItem, chart.legend);
-
-                       expect(chart.getDataVisibility(0)).toBe(false);
-                       expect(chart.update).toHaveBeenCalled();
-
-                       config.plugins.legend.onClick(null, legendItem, chart.legend);
-                       expect(chart.getDataVisibility(0)).toBe(true);
-               });
-       });
-
-       describe('Polar Area Chart', function() {
-               it('should return correct tooltip strings', function() {
-                       var config = Chart.defaults.controllers.polarArea;
-                       var chart = window.acquireChart({
-                               type: 'polarArea',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, 30],
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       // fake out the tooltip hover and force the tooltip to update
-                       chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
-                       chart.tooltip.update();
-
-                       // Title is always blank
-                       expect(chart.tooltip.title).toEqual([]);
-                       expect(chart.tooltip.body).toEqual([{
-                               before: [],
-                               lines: ['label2: 20'],
-                               after: []
-                       }]);
-               });
-
-               it('should return correct legend label objects', function() {
-                       var config = Chart.defaults.controllers.polarArea;
-                       var chart = window.acquireChart({
-                               type: 'polarArea',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, NaN],
-                                               backgroundColor: ['red', 'green', 'blue'],
-                                               borderWidth: 2,
-                                               borderColor: '#000'
-                                       }]
-                               },
-                               options: config
-                       });
-
-                       var expected = [{
-                               text: 'label1',
-                               fillStyle: 'red',
-                               hidden: false,
-                               index: 0,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }, {
-                               text: 'label2',
-                               fillStyle: 'green',
-                               hidden: false,
-                               index: 1,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }, {
-                               text: 'label3',
-                               fillStyle: 'blue',
-                               hidden: false,
-                               index: 2,
-                               strokeStyle: '#000',
-                               lineWidth: 2
-                       }];
-                       expect(chart.legend.legendItems).toEqual(expected);
-               });
-
-               it('should hide the correct arc when a legend item is clicked', function() {
-                       var config = Chart.defaults.controllers.polarArea;
-                       var chart = window.acquireChart({
-                               type: 'polarArea',
-                               data: {
-                                       labels: ['label1', 'label2', 'label3'],
-                                       datasets: [{
-                                               data: [10, 20, NaN],
-                                               backgroundColor: ['red', 'green', 'blue'],
-                                               borderWidth: 2,
-                                               borderColor: '#000'
-                                       }]
-                               },
-                               options: config
-                       });
-                       spyOn(chart, 'update').and.callThrough();
-
-                       var legendItem = chart.legend.legendItems[0];
-                       config.plugins.legend.onClick(null, legendItem, chart.legend);
-
-                       expect(chart.getDataVisibility(0)).toBe(false);
-                       expect(chart.update).toHaveBeenCalled();
-
-                       config.plugins.legend.onClick(null, legendItem, chart.legend);
-                       expect(chart.getDataVisibility(0)).toBe(true);
-               });
-       });
+  describe('Bubble Chart', function() {
+    it('should return correct tooltip strings', function() {
+      var config = Chart.defaults.controllers.bubble;
+      var chart = window.acquireChart({
+        type: 'bubble',
+        data: {
+          datasets: [{
+            label: 'My dataset',
+            data: [{
+              x: 10,
+              y: 12,
+              r: 5
+            }]
+          }]
+        },
+        options: config
+      });
+
+      // fake out the tooltip hover and force the tooltip to update
+      chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[0], datasetIndex: 0, index: 0}];
+      chart.tooltip.update();
+
+      // Title is always blank
+      expect(chart.tooltip.title).toEqual([]);
+      expect(chart.tooltip.body).toEqual([{
+        before: [],
+        lines: ['My dataset: (10, 12, 5)'],
+        after: []
+      }]);
+    });
+  });
+
+  describe('Doughnut Chart', function() {
+    it('should return correct tooltip strings', function() {
+      var config = Chart.defaults.controllers.doughnut;
+      var chart = window.acquireChart({
+        type: 'doughnut',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, 30],
+          }]
+        },
+        options: config
+      });
+
+      // fake out the tooltip hover and force the tooltip to update
+      chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
+      chart.tooltip.update();
+
+      // Title is always blank
+      expect(chart.tooltip.title).toEqual([]);
+      expect(chart.tooltip.body).toEqual([{
+        before: [],
+        lines: ['label2: 20'],
+        after: []
+      }]);
+    });
+
+    it('should return correct tooltip string for a multiline label', function() {
+      var config = Chart.defaults.controllers.doughnut;
+      var chart = window.acquireChart({
+        type: 'doughnut',
+        data: {
+          labels: ['label1', ['row1', 'row2', 'row3'], 'label3'],
+          datasets: [{
+            data: [10, 20, 30],
+          }]
+        },
+        options: config
+      });
+
+      // fake out the tooltip hover and force the tooltip to update
+      chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
+      chart.tooltip.update();
+
+      // Title is always blank
+      expect(chart.tooltip.title).toEqual([]);
+      expect(chart.tooltip.body).toEqual([{
+        before: [],
+        lines: [
+          'row1: 20',
+          'row2',
+          'row3'
+        ],
+        after: []
+      }]);
+    });
+
+    it('should return correct legend label objects', function() {
+      var config = Chart.defaults.controllers.doughnut;
+      var chart = window.acquireChart({
+        type: 'doughnut',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, NaN],
+            backgroundColor: ['red', 'green', 'blue'],
+            borderWidth: 2,
+            borderColor: '#000'
+          }]
+        },
+        options: config
+      });
+
+      var expected = [{
+        text: 'label1',
+        fillStyle: 'red',
+        hidden: false,
+        index: 0,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }, {
+        text: 'label2',
+        fillStyle: 'green',
+        hidden: false,
+        index: 1,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }, {
+        text: 'label3',
+        fillStyle: 'blue',
+        hidden: false,
+        index: 2,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }];
+      expect(chart.legend.legendItems).toEqual(expected);
+    });
+
+    it('should hide the correct arc when a legend item is clicked', function() {
+      var config = Chart.defaults.controllers.doughnut;
+      var chart = window.acquireChart({
+        type: 'doughnut',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, NaN],
+            backgroundColor: ['red', 'green', 'blue'],
+            borderWidth: 2,
+            borderColor: '#000'
+          }]
+        },
+        options: config
+      });
+      spyOn(chart, 'update').and.callThrough();
+
+      var legendItem = chart.legend.legendItems[0];
+      config.plugins.legend.onClick(null, legendItem, chart.legend);
+
+      expect(chart.getDataVisibility(0)).toBe(false);
+      expect(chart.update).toHaveBeenCalled();
+
+      config.plugins.legend.onClick(null, legendItem, chart.legend);
+      expect(chart.getDataVisibility(0)).toBe(true);
+    });
+  });
+
+  describe('Polar Area Chart', function() {
+    it('should return correct tooltip strings', function() {
+      var config = Chart.defaults.controllers.polarArea;
+      var chart = window.acquireChart({
+        type: 'polarArea',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, 30],
+          }]
+        },
+        options: config
+      });
+
+      // fake out the tooltip hover and force the tooltip to update
+      chart.tooltip._active = [{element: chart.getDatasetMeta(0).data[1], datasetIndex: 0, index: 1}];
+      chart.tooltip.update();
+
+      // Title is always blank
+      expect(chart.tooltip.title).toEqual([]);
+      expect(chart.tooltip.body).toEqual([{
+        before: [],
+        lines: ['label2: 20'],
+        after: []
+      }]);
+    });
+
+    it('should return correct legend label objects', function() {
+      var config = Chart.defaults.controllers.polarArea;
+      var chart = window.acquireChart({
+        type: 'polarArea',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, NaN],
+            backgroundColor: ['red', 'green', 'blue'],
+            borderWidth: 2,
+            borderColor: '#000'
+          }]
+        },
+        options: config
+      });
+
+      var expected = [{
+        text: 'label1',
+        fillStyle: 'red',
+        hidden: false,
+        index: 0,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }, {
+        text: 'label2',
+        fillStyle: 'green',
+        hidden: false,
+        index: 1,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }, {
+        text: 'label3',
+        fillStyle: 'blue',
+        hidden: false,
+        index: 2,
+        strokeStyle: '#000',
+        lineWidth: 2
+      }];
+      expect(chart.legend.legendItems).toEqual(expected);
+    });
+
+    it('should hide the correct arc when a legend item is clicked', function() {
+      var config = Chart.defaults.controllers.polarArea;
+      var chart = window.acquireChart({
+        type: 'polarArea',
+        data: {
+          labels: ['label1', 'label2', 'label3'],
+          datasets: [{
+            data: [10, 20, NaN],
+            backgroundColor: ['red', 'green', 'blue'],
+            borderWidth: 2,
+            borderColor: '#000'
+          }]
+        },
+        options: config
+      });
+      spyOn(chart, 'update').and.callThrough();
+
+      var legendItem = chart.legend.legendItems[0];
+      config.plugins.legend.onClick(null, legendItem, chart.legend);
+
+      expect(chart.getDataVisibility(0)).toBe(false);
+      expect(chart.update).toHaveBeenCalled();
+
+      config.plugins.legend.onClick(null, legendItem, chart.legend);
+      expect(chart.getDataVisibility(0)).toBe(true);
+    });
+  });
 });
index 1dca63dc0351cde183e37721675c34878aa9e446..011bfc21409e9c3378538dc907d360a952ed3cce 100644 (file)
@@ -1,39 +1,39 @@
 describe('Chart namespace', function() {
-       describe('Chart', function() {
-               it('should a function (constructor)', function() {
-                       expect(Chart instanceof Function).toBeTruthy();
-               });
-               it('should define "core" properties', function() {
-                       expect(Chart instanceof Function).toBeTruthy();
-                       expect(Chart.Animation instanceof Object).toBeTruthy();
-                       expect(Chart.Animations instanceof Object).toBeTruthy();
-                       expect(Chart.defaults instanceof Object).toBeTruthy();
-                       expect(Chart.Element instanceof Object).toBeTruthy();
-                       expect(Chart.Interaction instanceof Object).toBeTruthy();
-                       expect(Chart.layouts instanceof Object).toBeTruthy();
+  describe('Chart', function() {
+    it('should a function (constructor)', function() {
+      expect(Chart instanceof Function).toBeTruthy();
+    });
+    it('should define "core" properties', function() {
+      expect(Chart instanceof Function).toBeTruthy();
+      expect(Chart.Animation instanceof Object).toBeTruthy();
+      expect(Chart.Animations instanceof Object).toBeTruthy();
+      expect(Chart.defaults instanceof Object).toBeTruthy();
+      expect(Chart.Element instanceof Object).toBeTruthy();
+      expect(Chart.Interaction instanceof Object).toBeTruthy();
+      expect(Chart.layouts instanceof Object).toBeTruthy();
 
-                       expect(Chart.platforms.BasePlatform instanceof Function).toBeTruthy();
-                       expect(Chart.platforms.BasicPlatform instanceof Function).toBeTruthy();
-                       expect(Chart.platforms.DomPlatform instanceof Function).toBeTruthy();
+      expect(Chart.platforms.BasePlatform instanceof Function).toBeTruthy();
+      expect(Chart.platforms.BasicPlatform instanceof Function).toBeTruthy();
+      expect(Chart.platforms.DomPlatform instanceof Function).toBeTruthy();
 
-                       expect(Chart.registry instanceof Object).toBeTruthy();
-                       expect(Chart.Scale instanceof Object).toBeTruthy();
-                       expect(Chart.Ticks instanceof Object).toBeTruthy();
-               });
-       });
+      expect(Chart.registry instanceof Object).toBeTruthy();
+      expect(Chart.Scale instanceof Object).toBeTruthy();
+      expect(Chart.Ticks instanceof Object).toBeTruthy();
+    });
+  });
 
-       describe('Chart.elements', function() {
-               it('should contains "elements" classes', function() {
-                       expect(Chart.elements.ArcElement instanceof Function).toBeTruthy();
-                       expect(Chart.elements.BarElement instanceof Function).toBeTruthy();
-                       expect(Chart.elements.LineElement instanceof Function).toBeTruthy();
-                       expect(Chart.elements.PointElement instanceof Function).toBeTruthy();
-               });
-       });
+  describe('Chart.elements', function() {
+    it('should contains "elements" classes', function() {
+      expect(Chart.elements.ArcElement instanceof Function).toBeTruthy();
+      expect(Chart.elements.BarElement instanceof Function).toBeTruthy();
+      expect(Chart.elements.LineElement instanceof Function).toBeTruthy();
+      expect(Chart.elements.PointElement instanceof Function).toBeTruthy();
+    });
+  });
 
-       describe('Chart.helpers', function() {
-               it('should be an object', function() {
-                       expect(Chart.helpers instanceof Object).toBeTruthy();
-               });
-       });
+  describe('Chart.helpers', function() {
+    it('should be an object', function() {
+      expect(Chart.helpers instanceof Object).toBeTruthy();
+    });
+  });
 });
index 0008908926d41399d2b79df409ae4956a7748274..e451d7f13314c99778ba090294ef91e6bc036bd9 100644 (file)
 'use strict';
 
 describe('Chart.helpers.canvas', function() {
-       describe('auto', jasmine.fixture.specs('helpers'));
+  describe('auto', jasmine.fixture.specs('helpers'));
 
-       var helpers = Chart.helpers;
+  var helpers = Chart.helpers;
 
-       describe('clearCanvas', function() {
-               it('should clear the chart canvas', function() {
-                       var chart = acquireChart({}, {
-                               canvas: {
-                                       style: 'width: 150px; height: 245px'
-                               }
-                       });
+  describe('clearCanvas', function() {
+    it('should clear the chart canvas', function() {
+      var chart = acquireChart({}, {
+        canvas: {
+          style: 'width: 150px; height: 245px'
+        }
+      });
 
-                       spyOn(chart.ctx, 'clearRect');
+      spyOn(chart.ctx, 'clearRect');
 
-                       helpers.clearCanvas(chart.canvas, chart.ctx);
+      helpers.clearCanvas(chart.canvas, chart.ctx);
 
-                       expect(chart.ctx.clearRect.calls.count()).toBe(1);
-                       expect(chart.ctx.clearRect.calls.first().object).toBe(chart.ctx);
-                       expect(chart.ctx.clearRect.calls.first().args).toEqual([0, 0, 150, 245]);
-               });
-       });
+      expect(chart.ctx.clearRect.calls.count()).toBe(1);
+      expect(chart.ctx.clearRect.calls.first().object).toBe(chart.ctx);
+      expect(chart.ctx.clearRect.calls.first().args).toEqual([0, 0, 150, 245]);
+    });
+  });
 
-       describe('isPointInArea', function() {
-               it('should determine if a point is in the area', function() {
-                       var isPointInArea = helpers._isPointInArea;
-                       var area = {left: 0, top: 0, right: 512, bottom: 256};
+  describe('isPointInArea', function() {
+    it('should determine if a point is in the area', function() {
+      var isPointInArea = helpers._isPointInArea;
+      var area = {left: 0, top: 0, right: 512, bottom: 256};
 
-                       expect(isPointInArea({x: 0, y: 0}, area)).toBe(true);
-                       expect(isPointInArea({x: -1e-12, y: -1e-12}, area)).toBe(true);
-                       expect(isPointInArea({x: 512, y: 256}, area)).toBe(true);
-                       expect(isPointInArea({x: 512 + 1e-12, y: 256 + 1e-12}, area)).toBe(true);
-                       expect(isPointInArea({x: -0.5, y: 0}, area)).toBe(false);
-                       expect(isPointInArea({x: 0, y: 256.5}, area)).toBe(false);
-               });
-       });
+      expect(isPointInArea({x: 0, y: 0}, area)).toBe(true);
+      expect(isPointInArea({x: -1e-12, y: -1e-12}, area)).toBe(true);
+      expect(isPointInArea({x: 512, y: 256}, area)).toBe(true);
+      expect(isPointInArea({x: 512 + 1e-12, y: 256 + 1e-12}, area)).toBe(true);
+      expect(isPointInArea({x: -0.5, y: 0}, area)).toBe(false);
+      expect(isPointInArea({x: 0, y: 256.5}, area)).toBe(false);
+    });
+  });
 
-       it('should return the width of the longest text in an Array and 2D Array', function() {
-               var context = window.createMockContext();
-               var font = "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
-               var arrayOfThings1D = ['FooBar', 'Bar'];
-               var arrayOfThings2D = [['FooBar_1', 'Bar_2'], 'Foo_1'];
+  it('should return the width of the longest text in an Array and 2D Array', function() {
+    var context = window.createMockContext();
+    var font = "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
+    var arrayOfThings1D = ['FooBar', 'Bar'];
+    var arrayOfThings2D = [['FooBar_1', 'Bar_2'], 'Foo_1'];
 
 
-               // Regardless 'FooBar' is the longest label it should return (characters * 10)
-               expect(helpers._longestText(context, font, arrayOfThings1D, {})).toEqual(60);
-               expect(helpers._longestText(context, font, arrayOfThings2D, {})).toEqual(80);
-               // We check to make sure we made the right calls to the canvas.
-               expect(context.getCalls()).toEqual([{
-                       name: 'save',
-                       args: []
-               }, {
-                       name: 'setFont',
-                       args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
-               }, {
-                       name: 'measureText',
-                       args: ['FooBar']
-               }, {
-                       name: 'measureText',
-                       args: ['Bar']
-               }, {
-                       name: 'restore',
-                       args: []
-               }, {
-                       name: 'save',
-                       args: []
-               }, {
-                       name: 'setFont',
-                       args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
-               }, {
-                       name: 'measureText',
-                       args: ['FooBar_1']
-               }, {
-                       name: 'measureText',
-                       args: ['Bar_2']
-               }, {
-                       name: 'measureText',
-                       args: ['Foo_1']
-               }, {
-                       name: 'restore',
-                       args: []
-               }]);
-       });
+    // Regardless 'FooBar' is the longest label it should return (characters * 10)
+    expect(helpers._longestText(context, font, arrayOfThings1D, {})).toEqual(60);
+    expect(helpers._longestText(context, font, arrayOfThings2D, {})).toEqual(80);
+    // We check to make sure we made the right calls to the canvas.
+    expect(context.getCalls()).toEqual([{
+      name: 'save',
+      args: []
+    }, {
+      name: 'setFont',
+      args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
+    }, {
+      name: 'measureText',
+      args: ['FooBar']
+    }, {
+      name: 'measureText',
+      args: ['Bar']
+    }, {
+      name: 'restore',
+      args: []
+    }, {
+      name: 'save',
+      args: []
+    }, {
+      name: 'setFont',
+      args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
+    }, {
+      name: 'measureText',
+      args: ['FooBar_1']
+    }, {
+      name: 'measureText',
+      args: ['Bar_2']
+    }, {
+      name: 'measureText',
+      args: ['Foo_1']
+    }, {
+      name: 'restore',
+      args: []
+    }]);
+  });
 
-       it('compare text with current longest and update', function() {
-               var context = window.createMockContext();
-               var data = {};
-               var gc = [];
-               var longest = 70;
+  it('compare text with current longest and update', function() {
+    var context = window.createMockContext();
+    var data = {};
+    var gc = [];
+    var longest = 70;
 
-               expect(helpers._measureText(context, data, gc, longest, 'foobar')).toEqual(70);
-               expect(helpers._measureText(context, data, gc, longest, 'foobar_')).toEqual(70);
-               expect(helpers._measureText(context, data, gc, longest, 'foobar_1')).toEqual(80);
-               // We check to make sure we made the right calls to the canvas.
-               expect(context.getCalls()).toEqual([{
-                       name: 'measureText',
-                       args: ['foobar']
-               }, {
-                       name: 'measureText',
-                       args: ['foobar_']
-               }, {
-                       name: 'measureText',
-                       args: ['foobar_1']
-               }]);
-       });
+    expect(helpers._measureText(context, data, gc, longest, 'foobar')).toEqual(70);
+    expect(helpers._measureText(context, data, gc, longest, 'foobar_')).toEqual(70);
+    expect(helpers._measureText(context, data, gc, longest, 'foobar_1')).toEqual(80);
+    // We check to make sure we made the right calls to the canvas.
+    expect(context.getCalls()).toEqual([{
+      name: 'measureText',
+      args: ['foobar']
+    }, {
+      name: 'measureText',
+      args: ['foobar_']
+    }, {
+      name: 'measureText',
+      args: ['foobar_1']
+    }]);
+  });
 
-       describe('renderText', function() {
-               it('should render multiple lines of text', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, ['foo', 'foo2'], 0, 0, font);
+  describe('renderText', function() {
+    it('should render multiple lines of text', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, ['foo', 'foo2'], 0, 0, font);
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo2', 0, 20, undefined],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'fillText',
+        args: ['foo2', 0, 20, undefined],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should accept the text maxWidth', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {maxWidth: 30});
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, 30],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+    it('should accept the text maxWidth', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {maxWidth: 30});
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, 30],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should underline the text', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {decorationWidth: 3, underline: true});
+    it('should underline the text', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {decorationWidth: 3, underline: true});
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'measureText',
-                               args: ['foo'],
-                       }, {
-                               name: 'setStrokeStyle',
-                               args: [null],
-                       }, {
-                               name: 'beginPath',
-                               args: [],
-                       }, {
-                               name: 'setLineWidth',
-                               args: [3],
-                       }, {
-                               name: 'moveTo',
-                               args: [-15, 8],
-                       }, {
-                               name: 'lineTo',
-                               args: [25, 8],
-                       }, {
-                               name: 'stroke',
-                               args: [],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'measureText',
+        args: ['foo'],
+      }, {
+        name: 'setStrokeStyle',
+        args: [null],
+      }, {
+        name: 'beginPath',
+        args: [],
+      }, {
+        name: 'setLineWidth',
+        args: [3],
+      }, {
+        name: 'moveTo',
+        args: [-15, 8],
+      }, {
+        name: 'lineTo',
+        args: [25, 8],
+      }, {
+        name: 'stroke',
+        args: [],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should strikethrough the text', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {strikethrough: true});
+    it('should strikethrough the text', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {strikethrough: true});
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'measureText',
-                               args: ['foo'],
-                       }, {
-                               name: 'setStrokeStyle',
-                               args: [null],
-                       }, {
-                               name: 'beginPath',
-                               args: [],
-                       }, {
-                               name: 'setLineWidth',
-                               args: [2],
-                       }, {
-                               name: 'moveTo',
-                               args: [-15, 2],
-                       }, {
-                               name: 'lineTo',
-                               args: [25, 2],
-                       }, {
-                               name: 'stroke',
-                               args: [],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'measureText',
+        args: ['foo'],
+      }, {
+        name: 'setStrokeStyle',
+        args: [null],
+      }, {
+        name: 'beginPath',
+        args: [],
+      }, {
+        name: 'setLineWidth',
+        args: [2],
+      }, {
+        name: 'moveTo',
+        args: [-15, 2],
+      }, {
+        name: 'lineTo',
+        args: [25, 2],
+      }, {
+        name: 'stroke',
+        args: [],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should set the fill style if supplied', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {color: 'red'});
+    it('should set the fill style if supplied', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {color: 'red'});
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'setFillStyle',
-                               args: ['red'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'setFillStyle',
+        args: ['red'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should set the stroke style if supplied', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {strokeColor: 'red', strokeWidth: 2});
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'setStrokeStyle',
-                               args: ['red'],
-                       }, {
-                               name: 'setLineWidth',
-                               args: [2],
-                       }, {
-                               name: 'strokeText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+    it('should set the stroke style if supplied', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {strokeColor: 'red', strokeWidth: 2});
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'setStrokeStyle',
+        args: ['red'],
+      }, {
+        name: 'setLineWidth',
+        args: [2],
+      }, {
+        name: 'strokeText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should set the text alignment', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {textAlign: 'left', textBaseline: 'middle'});
+    it('should set the text alignment', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {textAlign: 'left', textBaseline: 'middle'});
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'setTextAlign',
-                               args: ['left'],
-                       }, {
-                               name: 'setTextBaseline',
-                               args: ['middle'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'setTextAlign',
+        args: ['left'],
+      }, {
+        name: 'setTextBaseline',
+        args: ['middle'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
 
-               it('should translate and rotate text', function() {
-                       var context = window.createMockContext();
-                       var font = {string: '12px arial', lineHeight: 20};
-                       helpers.renderText(context, 'foo', 0, 0, font, {rotation: 90, translation: [10, 20]});
+    it('should translate and rotate text', function() {
+      var context = window.createMockContext();
+      var font = {string: '12px arial', lineHeight: 20};
+      helpers.renderText(context, 'foo', 0, 0, font, {rotation: 90, translation: [10, 20]});
 
-                       expect(context.getCalls()).toEqual([{
-                               name: 'save',
-                               args: [],
-                       }, {
-                               name: 'translate',
-                               args: [10, 20],
-                       }, {
-                               name: 'rotate',
-                               args: [90],
-                       }, {
-                               name: 'setFont',
-                               args: ['12px arial'],
-                       }, {
-                               name: 'fillText',
-                               args: ['foo', 0, 0, undefined],
-                       }, {
-                               name: 'restore',
-                               args: [],
-                       }]);
-               });
-       });
+      expect(context.getCalls()).toEqual([{
+        name: 'save',
+        args: [],
+      }, {
+        name: 'translate',
+        args: [10, 20],
+      }, {
+        name: 'rotate',
+        args: [90],
+      }, {
+        name: 'setFont',
+        args: ['12px arial'],
+      }, {
+        name: 'fillText',
+        args: ['foo', 0, 0, undefined],
+      }, {
+        name: 'restore',
+        args: [],
+      }]);
+    });
+  });
 });
index cae35c200d71a043b6ad1a325ab982a7e40f9fbd..f6a1cbae5eb738c03d5150e46313ea73b9c6ff2f 100644 (file)
@@ -1,36 +1,36 @@
 const {_filterBetween, _lookup, _lookupByKey, _rlookupByKey} = Chart.helpers;
 
 describe('helpers.collection', function() {
-       it('Should do binary search', function() {
-               const data = [0, 2, 6, 9];
-               expect(_lookup(data, 0)).toEqual({lo: 0, hi: 1});
-               expect(_lookup(data, 1)).toEqual({lo: 0, hi: 1});
-               expect(_lookup(data, 3)).toEqual({lo: 1, hi: 2});
-               expect(_lookup(data, 6)).toEqual({lo: 1, hi: 2});
-               expect(_lookup(data, 9)).toEqual({lo: 2, hi: 3});
-       });
+  it('Should do binary search', function() {
+    const data = [0, 2, 6, 9];
+    expect(_lookup(data, 0)).toEqual({lo: 0, hi: 1});
+    expect(_lookup(data, 1)).toEqual({lo: 0, hi: 1});
+    expect(_lookup(data, 3)).toEqual({lo: 1, hi: 2});
+    expect(_lookup(data, 6)).toEqual({lo: 1, hi: 2});
+    expect(_lookup(data, 9)).toEqual({lo: 2, hi: 3});
+  });
 
-       it('Should do binary search by key', function() {
-               const data = [{x: 0}, {x: 2}, {x: 6}, {x: 9}];
-               expect(_lookupByKey(data, 'x', 0)).toEqual({lo: 0, hi: 1});
-               expect(_lookupByKey(data, 'x', 1)).toEqual({lo: 0, hi: 1});
-               expect(_lookupByKey(data, 'x', 3)).toEqual({lo: 1, hi: 2});
-               expect(_lookupByKey(data, 'x', 6)).toEqual({lo: 1, hi: 2});
-               expect(_lookupByKey(data, 'x', 9)).toEqual({lo: 2, hi: 3});
-       });
+  it('Should do binary search by key', function() {
+    const data = [{x: 0}, {x: 2}, {x: 6}, {x: 9}];
+    expect(_lookupByKey(data, 'x', 0)).toEqual({lo: 0, hi: 1});
+    expect(_lookupByKey(data, 'x', 1)).toEqual({lo: 0, hi: 1});
+    expect(_lookupByKey(data, 'x', 3)).toEqual({lo: 1, hi: 2});
+    expect(_lookupByKey(data, 'x', 6)).toEqual({lo: 1, hi: 2});
+    expect(_lookupByKey(data, 'x', 9)).toEqual({lo: 2, hi: 3});
+  });
 
-       it('Should do reverse binary search by key', function() {
-               const data = [{x: 10}, {x: 7}, {x: 3}, {x: 0}];
-               expect(_rlookupByKey(data, 'x', 0)).toEqual({lo: 2, hi: 3});
-               expect(_rlookupByKey(data, 'x', 3)).toEqual({lo: 2, hi: 3});
-               expect(_rlookupByKey(data, 'x', 5)).toEqual({lo: 1, hi: 2});
-               expect(_rlookupByKey(data, 'x', 8)).toEqual({lo: 0, hi: 1});
-               expect(_rlookupByKey(data, 'x', 10)).toEqual({lo: 0, hi: 1});
-       });
+  it('Should do reverse binary search by key', function() {
+    const data = [{x: 10}, {x: 7}, {x: 3}, {x: 0}];
+    expect(_rlookupByKey(data, 'x', 0)).toEqual({lo: 2, hi: 3});
+    expect(_rlookupByKey(data, 'x', 3)).toEqual({lo: 2, hi: 3});
+    expect(_rlookupByKey(data, 'x', 5)).toEqual({lo: 1, hi: 2});
+    expect(_rlookupByKey(data, 'x', 8)).toEqual({lo: 0, hi: 1});
+    expect(_rlookupByKey(data, 'x', 10)).toEqual({lo: 0, hi: 1});
+  });
 
-       it('Should filter a sorted array', function() {
-               expect(_filterBetween([1, 2, 3, 4, 5, 6, 7, 8, 9], 5, 8)).toEqual([5, 6, 7, 8]);
-               expect(_filterBetween([1], 1, 1)).toEqual([1]);
-               expect(_filterBetween([1583049600000], 1584816327553, 1585680327553)).toEqual([]);
-       });
+  it('Should filter a sorted array', function() {
+    expect(_filterBetween([1, 2, 3, 4, 5, 6, 7, 8, 9], 5, 8)).toEqual([5, 6, 7, 8]);
+    expect(_filterBetween([1], 1, 1)).toEqual([1]);
+    expect(_filterBetween([1583049600000], 1584816327553, 1585680327553)).toEqual([]);
+  });
 });
index 6f478ddf46d5125607217e407624dc4fc4bc7d27..228d198077427ae5206f75e7ac3deb19217975e0 100644 (file)
@@ -1,47 +1,47 @@
 const {color, getHoverColor} = Chart.helpers;
 
 describe('Color helper', function() {
-       function isColorInstance(obj) {
-               return typeof obj === 'object' && obj.valid;
-       }
+  function isColorInstance(obj) {
+    return typeof obj === 'object' && obj.valid;
+  }
 
-       it('should return a color when called with a color', function() {
-               expect(isColorInstance(color('rgb(1, 2, 3)'))).toBe(true);
-       });
+  it('should return a color when called with a color', function() {
+    expect(isColorInstance(color('rgb(1, 2, 3)'))).toBe(true);
+  });
 });
 
 describe('Background hover color helper', function() {
-       it('should return a modified version of color when called with a color', function() {
-               var originalColorRGB = 'rgb(70, 191, 189)';
+  it('should return a modified version of color when called with a color', function() {
+    var originalColorRGB = 'rgb(70, 191, 189)';
 
-               expect(getHoverColor('#46BFBD')).not.toEqual(originalColorRGB);
-       });
+    expect(getHoverColor('#46BFBD')).not.toEqual(originalColorRGB);
+  });
 });
 
 describe('color and getHoverColor helpers', function() {
-       it('should return a CanvasPattern when called with a CanvasPattern', function(done) {
-               var dots = new Image();
-               dots.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAAD1BMVEUAAAD///////////////+PQt5oAAAABXRSTlMAHlFhZsfk/BEAAAAqSURBVHgBY2BgZGJmYmSAAUYWEIDzmcBcJhiXGcxlRpPFrhdmMiqgvX0AcGIBEUAo6UAAAAAASUVORK5CYII=';
-               dots.onload = function() {
-                       var chartContext = document.createElement('canvas').getContext('2d');
-                       var patternCanvas = document.createElement('canvas');
-                       var patternContext = patternCanvas.getContext('2d');
-                       var pattern = patternContext.createPattern(dots, 'repeat');
-                       patternContext.fillStyle = pattern;
-                       var chartPattern = chartContext.createPattern(patternCanvas, 'repeat');
-
-                       expect(color(chartPattern) instanceof CanvasPattern).toBe(true);
-                       expect(getHoverColor(chartPattern) instanceof CanvasPattern).toBe(true);
-
-                       done();
-               };
-       });
-
-       it('should return a CanvasGradient when called with a CanvasGradient', function() {
-               var context = document.createElement('canvas').getContext('2d');
-               var gradient = context.createLinearGradient(0, 1, 2, 3);
-
-               expect(color(gradient) instanceof CanvasGradient).toBe(true);
-               expect(getHoverColor(gradient) instanceof CanvasGradient).toBe(true);
-       });
+  it('should return a CanvasPattern when called with a CanvasPattern', function(done) {
+    var dots = new Image();
+    dots.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAAD1BMVEUAAAD///////////////+PQt5oAAAABXRSTlMAHlFhZsfk/BEAAAAqSURBVHgBY2BgZGJmYmSAAUYWEIDzmcBcJhiXGcxlRpPFrhdmMiqgvX0AcGIBEUAo6UAAAAAASUVORK5CYII=';
+    dots.onload = function() {
+      var chartContext = document.createElement('canvas').getContext('2d');
+      var patternCanvas = document.createElement('canvas');
+      var patternContext = patternCanvas.getContext('2d');
+      var pattern = patternContext.createPattern(dots, 'repeat');
+      patternContext.fillStyle = pattern;
+      var chartPattern = chartContext.createPattern(patternCanvas, 'repeat');
+
+      expect(color(chartPattern) instanceof CanvasPattern).toBe(true);
+      expect(getHoverColor(chartPattern) instanceof CanvasPattern).toBe(true);
+
+      done();
+    };
+  });
+
+  it('should return a CanvasGradient when called with a CanvasGradient', function() {
+    var context = document.createElement('canvas').getContext('2d');
+    var gradient = context.createLinearGradient(0, 1, 2, 3);
+
+    expect(color(gradient) instanceof CanvasGradient).toBe(true);
+    expect(getHoverColor(gradient) instanceof CanvasGradient).toBe(true);
+  });
 });
index b491686f804e73a02eff0c379482a592c7c63fe9..fb4e34f53bf402f35f6ea904496a6b3ad34ff7f6 100644 (file)
 'use strict';
 
 describe('Chart.helpers.core', function() {
-       var helpers = Chart.helpers;
-
-       describe('noop', function() {
-               it('should be callable', function() {
-                       expect(helpers.noop).toBeDefined();
-                       expect(typeof helpers.noop).toBe('function');
-                       expect(typeof helpers.noop.call).toBe('function');
-               });
-               it('should returns "undefined"', function() {
-                       expect(helpers.noop(42)).not.toBeDefined();
-                       expect(helpers.noop.call(this, 42)).not.toBeDefined();
-               });
-       });
-
-       describe('isArray', function() {
-               it('should return true if value is an array', function() {
-                       expect(helpers.isArray([])).toBeTruthy();
-                       expect(helpers.isArray([42])).toBeTruthy();
-                       expect(helpers.isArray(new Array())).toBeTruthy();
-                       expect(helpers.isArray(Array.prototype)).toBeTruthy();
-                       expect(helpers.isArray(new Int8Array(2))).toBeTruthy();
-                       expect(helpers.isArray(new Uint8Array())).toBeTruthy();
-                       expect(helpers.isArray(new Uint8ClampedArray([128, 244]))).toBeTruthy();
-                       expect(helpers.isArray(new Int16Array())).toBeTruthy();
-                       expect(helpers.isArray(new Uint16Array())).toBeTruthy();
-                       expect(helpers.isArray(new Int32Array())).toBeTruthy();
-                       expect(helpers.isArray(new Uint32Array())).toBeTruthy();
-                       expect(helpers.isArray(new Float32Array([1.2]))).toBeTruthy();
-                       expect(helpers.isArray(new Float64Array([]))).toBeTruthy();
-               });
-               it('should return false if value is not an array', function() {
-                       expect(helpers.isArray()).toBeFalsy();
-                       expect(helpers.isArray({})).toBeFalsy();
-                       expect(helpers.isArray(undefined)).toBeFalsy();
-                       expect(helpers.isArray(null)).toBeFalsy();
-                       expect(helpers.isArray(true)).toBeFalsy();
-                       expect(helpers.isArray(false)).toBeFalsy();
-                       expect(helpers.isArray(42)).toBeFalsy();
-                       expect(helpers.isArray('Array')).toBeFalsy();
-                       expect(helpers.isArray({__proto__: Array.prototype})).toBeFalsy();
-               });
-       });
-
-       describe('isObject', function() {
-               it('should return true if value is an object', function() {
-                       expect(helpers.isObject({})).toBeTruthy();
-                       expect(helpers.isObject({a: 42})).toBeTruthy();
-                       expect(helpers.isObject(new Object())).toBeTruthy();
-               });
-               it('should return false if value is not an object', function() {
-                       expect(helpers.isObject()).toBeFalsy();
-                       expect(helpers.isObject(undefined)).toBeFalsy();
-                       expect(helpers.isObject(null)).toBeFalsy();
-                       expect(helpers.isObject(true)).toBeFalsy();
-                       expect(helpers.isObject(false)).toBeFalsy();
-                       expect(helpers.isObject(42)).toBeFalsy();
-                       expect(helpers.isObject('Object')).toBeFalsy();
-                       expect(helpers.isObject([])).toBeFalsy();
-                       expect(helpers.isObject([42])).toBeFalsy();
-                       expect(helpers.isObject(new Array())).toBeFalsy();
-                       expect(helpers.isObject(new Date())).toBeFalsy();
-               });
-       });
-
-       describe('isFinite', function() {
-               it('should return true if value is a finite number', function() {
-                       expect(helpers.isFinite(0)).toBeTruthy();
-                       // eslint-disable-next-line no-new-wrappers
-                       expect(helpers.isFinite(new Number(10))).toBeTruthy();
-               });
-
-               it('should return false if the value is infinite', function() {
-                       expect(helpers.isFinite(Number.POSITIVE_INFINITY)).toBeFalsy();
-                       expect(helpers.isFinite(Number.NEGATIVE_INFINITY)).toBeFalsy();
-               });
-
-               it('should return false if the value is not a number', function() {
-                       expect(helpers.isFinite('a')).toBeFalsy();
-                       expect(helpers.isFinite({})).toBeFalsy();
-               });
-       });
-
-       describe('isNullOrUndef', function() {
-               it('should return true if value is null/undefined', function() {
-                       expect(helpers.isNullOrUndef(null)).toBeTruthy();
-                       expect(helpers.isNullOrUndef(undefined)).toBeTruthy();
-               });
-               it('should return false if value is not null/undefined', function() {
-                       expect(helpers.isNullOrUndef(true)).toBeFalsy();
-                       expect(helpers.isNullOrUndef(false)).toBeFalsy();
-                       expect(helpers.isNullOrUndef('')).toBeFalsy();
-                       expect(helpers.isNullOrUndef('String')).toBeFalsy();
-                       expect(helpers.isNullOrUndef(0)).toBeFalsy();
-                       expect(helpers.isNullOrUndef([])).toBeFalsy();
-                       expect(helpers.isNullOrUndef({})).toBeFalsy();
-                       expect(helpers.isNullOrUndef([42])).toBeFalsy();
-                       expect(helpers.isNullOrUndef(new Date())).toBeFalsy();
-               });
-       });
-
-       describe('valueOrDefault', function() {
-               it('should return value if defined', function() {
-                       var object = {};
-                       var array = [];
-
-                       expect(helpers.valueOrDefault(null, 42)).toBe(null);
-                       expect(helpers.valueOrDefault(false, 42)).toBe(false);
-                       expect(helpers.valueOrDefault(object, 42)).toBe(object);
-                       expect(helpers.valueOrDefault(array, 42)).toBe(array);
-                       expect(helpers.valueOrDefault('', 42)).toBe('');
-                       expect(helpers.valueOrDefault(0, 42)).toBe(0);
-               });
-               it('should return default if undefined', function() {
-                       expect(helpers.valueOrDefault(undefined, 42)).toBe(42);
-                       expect(helpers.valueOrDefault({}.foo, 42)).toBe(42);
-               });
-       });
-
-       describe('callback', function() {
-               it('should return undefined if fn is not a function', function() {
-                       expect(helpers.callback()).not.toBeDefined();
-                       expect(helpers.callback(null)).not.toBeDefined();
-                       expect(helpers.callback(42)).not.toBeDefined();
-                       expect(helpers.callback([])).not.toBeDefined();
-                       expect(helpers.callback({})).not.toBeDefined();
-               });
-               it('should call fn with the given args', function() {
-                       var spy = jasmine.createSpy('spy');
-                       helpers.callback(spy);
-                       helpers.callback(spy, []);
-                       helpers.callback(spy, ['foo']);
-                       helpers.callback(spy, [42, 'bar']);
-
-                       expect(spy.calls.argsFor(0)).toEqual([]);
-                       expect(spy.calls.argsFor(1)).toEqual([]);
-                       expect(spy.calls.argsFor(2)).toEqual(['foo']);
-                       expect(spy.calls.argsFor(3)).toEqual([42, 'bar']);
-               });
-               it('should call fn with the given scope', function() {
-                       var spy = jasmine.createSpy('spy');
-                       var scope = {};
-
-                       helpers.callback(spy);
-                       helpers.callback(spy, [], null);
-                       helpers.callback(spy, [], undefined);
-                       helpers.callback(spy, [], scope);
-
-                       expect(spy.calls.all()[0].object).toBe(window);
-                       expect(spy.calls.all()[1].object).toBe(window);
-                       expect(spy.calls.all()[2].object).toBe(window);
-                       expect(spy.calls.all()[3].object).toBe(scope);
-               });
-               it('should return the value returned by fn', function() {
-                       expect(helpers.callback(helpers.noop, [41])).toBe(undefined);
-                       expect(helpers.callback(function(i) {
-                               return i + 1;
-                       }, [41])).toBe(42);
-               });
-       });
-
-       describe('each', function() {
-               it('should iterate over an array forward if reverse === false', function() {
-                       var scope = {};
-                       var scopes = [];
-                       var items = [];
-                       var keys = [];
-
-                       helpers.each(['foo', 'bar', 42], function(item, key) {
-                               scopes.push(this);
-                               items.push(item);
-                               keys.push(key);
-                       }, scope);
-
-                       expect(scopes).toEqual([scope, scope, scope]);
-                       expect(items).toEqual(['foo', 'bar', 42]);
-                       expect(keys).toEqual([0, 1, 2]);
-               });
-               it('should iterate over an array backward if reverse === true', function() {
-                       var scope = {};
-                       var scopes = [];
-                       var items = [];
-                       var keys = [];
-
-                       helpers.each(['foo', 'bar', 42], function(item, key) {
-                               scopes.push(this);
-                               items.push(item);
-                               keys.push(key);
-                       }, scope, true);
-
-                       expect(scopes).toEqual([scope, scope, scope]);
-                       expect(items).toEqual([42, 'bar', 'foo']);
-                       expect(keys).toEqual([2, 1, 0]);
-               });
-               it('should iterate over object properties', function() {
-                       var scope = {};
-                       var scopes = [];
-                       var items = [];
-
-                       helpers.each({a: 'foo', b: 'bar', c: 42}, function(item, key) {
-                               scopes.push(this);
-                               items[key] = item;
-                       }, scope);
-
-                       expect(scopes).toEqual([scope, scope, scope]);
-                       expect(items).toEqual(jasmine.objectContaining({a: 'foo', b: 'bar', c: 42}));
-               });
-               it('should not throw when called with a non iterable object', function() {
-                       expect(function() {
-                               helpers.each(undefined);
-                       }).not.toThrow();
-                       expect(function() {
-                               helpers.each(null);
-                       }).not.toThrow();
-                       expect(function() {
-                               helpers.each(42);
-                       }).not.toThrow();
-               });
-       });
-
-       describe('_elementsEqual', function() {
-               it('should return true if arrays are the same', function() {
-                       expect(helpers._elementsEqual(
-                               [{datasetIndex: 0, index: 1}, {datasetIndex: 0, index: 2}],
-                               [{datasetIndex: 0, index: 1}, {datasetIndex: 0, index: 2}])).toBeTruthy();
-               });
-               it('should return false if arrays are not the same', function() {
-                       expect(helpers._elementsEqual([], [{datasetIndex: 0, index: 1}])).toBeFalsy();
-                       expect(helpers._elementsEqual([{datasetIndex: 0, index: 2}], [{datasetIndex: 0, index: 1}])).toBeFalsy();
-               });
-       });
-
-       describe('clone', function() {
-               it('should clone primitive values', function() {
-                       expect(helpers.clone()).toBe(undefined);
-                       expect(helpers.clone(null)).toBe(null);
-                       expect(helpers.clone(true)).toBe(true);
-                       expect(helpers.clone(42)).toBe(42);
-                       expect(helpers.clone('foo')).toBe('foo');
-               });
-               it('should perform a deep copy of arrays', function() {
-                       var o0 = {a: 42};
-                       var o1 = {s: 's'};
-                       var a0 = ['bar'];
-                       var a1 = [a0, o0, 2];
-                       var f0 = function() {};
-                       var input = [a1, o1, f0, 42, 'foo'];
-                       var output = helpers.clone(input);
-
-                       expect(output).toEqual(input);
-                       expect(output).not.toBe(input);
-                       expect(output[0]).not.toBe(a1);
-                       expect(output[0][0]).not.toBe(a0);
-                       expect(output[1]).not.toBe(o1);
-               });
-               it('should perform a deep copy of objects', function() {
-                       var a0 = ['bar'];
-                       var a1 = [1, 2, 3];
-                       var o0 = {a: a1, i: 42};
-                       var f0 = function() {};
-                       var input = {o: o0, a: a0, f: f0, s: 'foo', i: 42};
-                       var output = helpers.clone(input);
-
-                       expect(output).toEqual(input);
-                       expect(output).not.toBe(input);
-                       expect(output.o).not.toBe(o0);
-                       expect(output.o.a).not.toBe(a1);
-                       expect(output.a).not.toBe(a0);
-               });
-       });
-
-       describe('merge', function() {
-               it('should not allow prototype pollution', function() {
-                       var test = helpers.merge({}, JSON.parse('{"__proto__":{"polluted": true}}'));
-                       expect(test.prototype).toBeUndefined();
-                       expect(Object.prototype.polluted).toBeUndefined();
-               });
-               it('should update target and return it', function() {
-                       var target = {a: 1};
-                       var result = helpers.merge(target, {a: 2, b: 'foo'});
-                       expect(target).toEqual({a: 2, b: 'foo'});
-                       expect(target).toBe(result);
-               });
-               it('should return target if not an object', function() {
-                       expect(helpers.merge(undefined, {a: 42})).toEqual(undefined);
-                       expect(helpers.merge(null, {a: 42})).toEqual(null);
-                       expect(helpers.merge('foo', {a: 42})).toEqual('foo');
-                       expect(helpers.merge(['foo', 'bar'], {a: 42})).toEqual(['foo', 'bar']);
-               });
-               it('should ignore sources which are not objects', function() {
-                       expect(helpers.merge({a: 42})).toEqual({a: 42});
-                       expect(helpers.merge({a: 42}, null)).toEqual({a: 42});
-                       expect(helpers.merge({a: 42}, 42)).toEqual({a: 42});
-               });
-               it('should recursively overwrite target with source properties', function() {
-                       expect(helpers.merge({a: {b: 1}}, {a: {c: 2}})).toEqual({a: {b: 1, c: 2}});
-                       expect(helpers.merge({a: {b: 1}}, {a: {b: 2}})).toEqual({a: {b: 2}});
-                       expect(helpers.merge({a: [1, 2]}, {a: [3, 4]})).toEqual({a: [3, 4]});
-                       expect(helpers.merge({a: 42}, {a: {b: 0}})).toEqual({a: {b: 0}});
-                       expect(helpers.merge({a: 42}, {a: null})).toEqual({a: null});
-                       expect(helpers.merge({a: 42}, {a: undefined})).toEqual({a: undefined});
-               });
-               it('should merge multiple sources in the correct order', function() {
-                       var t0 = {a: {b: 1, c: [1, 2]}};
-                       var s0 = {a: {d: 3}, e: {f: 4}};
-                       var s1 = {a: {b: 5}};
-                       var s2 = {a: {c: [6, 7]}, e: 'foo'};
-
-                       expect(helpers.merge(t0, [s0, s1, s2])).toEqual({a: {b: 5, c: [6, 7], d: 3}, e: 'foo'});
-               });
-               it('should deep copy merged values from sources', function() {
-                       var a0 = ['foo'];
-                       var a1 = [1, 2, 3];
-                       var o0 = {a: a1, i: 42};
-                       var output = helpers.merge({}, {a: a0, o: o0});
-
-                       expect(output).toEqual({a: a0, o: o0});
-                       expect(output.a).not.toBe(a0);
-                       expect(output.o).not.toBe(o0);
-                       expect(output.o.a).not.toBe(a1);
-               });
-       });
-
-       describe('mergeIf', function() {
-               it('should not allow prototype pollution', function() {
-                       var test = helpers.mergeIf({}, JSON.parse('{"__proto__":{"polluted": true}}'));
-                       expect(test.prototype).toBeUndefined();
-                       expect(Object.prototype.polluted).toBeUndefined();
-               });
-               it('should update target and return it', function() {
-                       var target = {a: 1};
-                       var result = helpers.mergeIf(target, {a: 2, b: 'foo'});
-                       expect(target).toEqual({a: 1, b: 'foo'});
-                       expect(target).toBe(result);
-               });
-               it('should return target if not an object', function() {
-                       expect(helpers.mergeIf(undefined, {a: 42})).toEqual(undefined);
-                       expect(helpers.mergeIf(null, {a: 42})).toEqual(null);
-                       expect(helpers.mergeIf('foo', {a: 42})).toEqual('foo');
-                       expect(helpers.mergeIf(['foo', 'bar'], {a: 42})).toEqual(['foo', 'bar']);
-               });
-               it('should ignore sources which are not objects', function() {
-                       expect(helpers.mergeIf({a: 42})).toEqual({a: 42});
-                       expect(helpers.mergeIf({a: 42}, null)).toEqual({a: 42});
-                       expect(helpers.mergeIf({a: 42}, 42)).toEqual({a: 42});
-               });
-               it('should recursively copy source properties in target only if they do not exist in target', function() {
-                       expect(helpers.mergeIf({a: {b: 1}}, {a: {c: 2}})).toEqual({a: {b: 1, c: 2}});
-                       expect(helpers.mergeIf({a: {b: 1}}, {a: {b: 2}})).toEqual({a: {b: 1}});
-                       expect(helpers.mergeIf({a: [1, 2]}, {a: [3, 4]})).toEqual({a: [1, 2]});
-                       expect(helpers.mergeIf({a: 0}, {a: {b: 2}})).toEqual({a: 0});
-                       expect(helpers.mergeIf({a: null}, {a: 42})).toEqual({a: null});
-                       expect(helpers.mergeIf({a: undefined}, {a: 42})).toEqual({a: undefined});
-               });
-               it('should merge multiple sources in the correct order', function() {
-                       var t0 = {a: {b: 1, c: [1, 2]}};
-                       var s0 = {a: {d: 3}, e: {f: 4}};
-                       var s1 = {a: {b: 5}};
-                       var s2 = {a: {c: [6, 7]}, e: 'foo'};
-
-                       expect(helpers.mergeIf(t0, [s0, s1, s2])).toEqual({a: {b: 1, c: [1, 2], d: 3}, e: {f: 4}});
-               });
-               it('should deep copy merged values from sources', function() {
-                       var a0 = ['foo'];
-                       var a1 = [1, 2, 3];
-                       var o0 = {a: a1, i: 42};
-                       var output = helpers.mergeIf({}, {a: a0, o: o0});
-
-                       expect(output).toEqual({a: a0, o: o0});
-                       expect(output.a).not.toBe(a0);
-                       expect(output.o).not.toBe(o0);
-                       expect(output.o.a).not.toBe(a1);
-               });
-       });
-
-       describe('resolveObjectKey', function() {
-               it('should resolve empty key to root object', function() {
-                       const obj = {test: true};
-                       expect(helpers.resolveObjectKey(obj, '')).toEqual(obj);
-               });
-               it('should resolve one level', function() {
-                       const obj = {
-                               bool: true,
-                               str: 'test',
-                               int: 42,
-                               obj: {name: 'object'}
-                       };
-                       expect(helpers.resolveObjectKey(obj, 'bool')).toEqual(true);
-                       expect(helpers.resolveObjectKey(obj, 'str')).toEqual('test');
-                       expect(helpers.resolveObjectKey(obj, 'int')).toEqual(42);
-                       expect(helpers.resolveObjectKey(obj, 'obj')).toEqual(obj.obj);
-               });
-               it('should resolve multiple levels', function() {
-                       const obj = {
-                               child: {
-                                       level: 1,
-                                       child: {
-                                               level: 2,
-                                               child: {
-                                                       level: 3
-                                               }
-                                       }
-                               }
-                       };
-                       expect(helpers.resolveObjectKey(obj, 'child.level')).toEqual(1);
-                       expect(helpers.resolveObjectKey(obj, 'child.child.level')).toEqual(2);
-                       expect(helpers.resolveObjectKey(obj, 'child.child.child.level')).toEqual(3);
-               });
-               it('should resolve circular reference', function() {
-                       const root = {};
-                       const child = {root};
-                       child.child = child;
-                       root.child = child;
-                       expect(helpers.resolveObjectKey(root, 'child')).toEqual(child);
-                       expect(helpers.resolveObjectKey(root, 'child.child.child.child.child.child')).toEqual(child);
-                       expect(helpers.resolveObjectKey(root, 'child.child.root')).toEqual(root);
-               });
-               it('should break at empty key', function() {
-                       const obj = {
-                               child: {
-                                       level: 1,
-                                       child: {
-                                               level: 2,
-                                               child: {
-                                                       level: 3
-                                               }
-                                       }
-                               }
-                       };
-                       expect(helpers.resolveObjectKey(obj, 'child..level')).toEqual(obj.child);
-                       expect(helpers.resolveObjectKey(obj, 'child.child.level...')).toEqual(2);
-                       expect(helpers.resolveObjectKey(obj, '.')).toEqual(obj);
-                       expect(helpers.resolveObjectKey(obj, '..')).toEqual(obj);
-               });
-               it('should resolve undefined', function() {
-                       const obj = {
-                               child: {
-                                       level: 1,
-                                       child: {
-                                               level: 2,
-                                               child: {
-                                                       level: 3
-                                               }
-                                       }
-                               }
-                       };
-                       expect(helpers.resolveObjectKey(obj, 'level')).toEqual(undefined);
-                       expect(helpers.resolveObjectKey(obj, 'child.level.a')).toEqual(undefined);
-               });
-               it('should throw on invalid input', function() {
-                       expect(() => helpers.resolveObjectKey(undefined, undefined)).toThrow();
-                       expect(() => helpers.resolveObjectKey({}, null)).toThrow();
-                       expect(() => helpers.resolveObjectKey({}, false)).toThrow();
-                       expect(() => helpers.resolveObjectKey({}, true)).toThrow();
-                       expect(() => helpers.resolveObjectKey({}, 1)).toThrow();
-               });
-       });
+  var helpers = Chart.helpers;
+
+  describe('noop', function() {
+    it('should be callable', function() {
+      expect(helpers.noop).toBeDefined();
+      expect(typeof helpers.noop).toBe('function');
+      expect(typeof helpers.noop.call).toBe('function');
+    });
+    it('should returns "undefined"', function() {
+      expect(helpers.noop(42)).not.toBeDefined();
+      expect(helpers.noop.call(this, 42)).not.toBeDefined();
+    });
+  });
+
+  describe('isArray', function() {
+    it('should return true if value is an array', function() {
+      expect(helpers.isArray([])).toBeTruthy();
+      expect(helpers.isArray([42])).toBeTruthy();
+      expect(helpers.isArray(new Array())).toBeTruthy();
+      expect(helpers.isArray(Array.prototype)).toBeTruthy();
+      expect(helpers.isArray(new Int8Array(2))).toBeTruthy();
+      expect(helpers.isArray(new Uint8Array())).toBeTruthy();
+      expect(helpers.isArray(new Uint8ClampedArray([128, 244]))).toBeTruthy();
+      expect(helpers.isArray(new Int16Array())).toBeTruthy();
+      expect(helpers.isArray(new Uint16Array())).toBeTruthy();
+      expect(helpers.isArray(new Int32Array())).toBeTruthy();
+      expect(helpers.isArray(new Uint32Array())).toBeTruthy();
+      expect(helpers.isArray(new Float32Array([1.2]))).toBeTruthy();
+      expect(helpers.isArray(new Float64Array([]))).toBeTruthy();
+    });
+    it('should return false if value is not an array', function() {
+      expect(helpers.isArray()).toBeFalsy();
+      expect(helpers.isArray({})).toBeFalsy();
+      expect(helpers.isArray(undefined)).toBeFalsy();
+      expect(helpers.isArray(null)).toBeFalsy();
+      expect(helpers.isArray(true)).toBeFalsy();
+      expect(helpers.isArray(false)).toBeFalsy();
+      expect(helpers.isArray(42)).toBeFalsy();
+      expect(helpers.isArray('Array')).toBeFalsy();
+      expect(helpers.isArray({__proto__: Array.prototype})).toBeFalsy();
+    });
+  });
+
+  describe('isObject', function() {
+    it('should return true if value is an object', function() {
+      expect(helpers.isObject({})).toBeTruthy();
+      expect(helpers.isObject({a: 42})).toBeTruthy();
+      expect(helpers.isObject(new Object())).toBeTruthy();
+    });
+    it('should return false if value is not an object', function() {
+      expect(helpers.isObject()).toBeFalsy();
+      expect(helpers.isObject(undefined)).toBeFalsy();
+      expect(helpers.isObject(null)).toBeFalsy();
+      expect(helpers.isObject(true)).toBeFalsy();
+      expect(helpers.isObject(false)).toBeFalsy();
+      expect(helpers.isObject(42)).toBeFalsy();
+      expect(helpers.isObject('Object')).toBeFalsy();
+      expect(helpers.isObject([])).toBeFalsy();
+      expect(helpers.isObject([42])).toBeFalsy();
+      expect(helpers.isObject(new Array())).toBeFalsy();
+      expect(helpers.isObject(new Date())).toBeFalsy();
+    });
+  });
+
+  describe('isFinite', function() {
+    it('should return true if value is a finite number', function() {
+      expect(helpers.isFinite(0)).toBeTruthy();
+      // eslint-disable-next-line no-new-wrappers
+      expect(helpers.isFinite(new Number(10))).toBeTruthy();
+    });
+
+    it('should return false if the value is infinite', function() {
+      expect(helpers.isFinite(Number.POSITIVE_INFINITY)).toBeFalsy();
+      expect(helpers.isFinite(Number.NEGATIVE_INFINITY)).toBeFalsy();
+    });
+
+    it('should return false if the value is not a number', function() {
+      expect(helpers.isFinite('a')).toBeFalsy();
+      expect(helpers.isFinite({})).toBeFalsy();
+    });
+  });
+
+  describe('isNullOrUndef', function() {
+    it('should return true if value is null/undefined', function() {
+      expect(helpers.isNullOrUndef(null)).toBeTruthy();
+      expect(helpers.isNullOrUndef(undefined)).toBeTruthy();
+    });
+    it('should return false if value is not null/undefined', function() {
+      expect(helpers.isNullOrUndef(true)).toBeFalsy();
+      expect(helpers.isNullOrUndef(false)).toBeFalsy();
+      expect(helpers.isNullOrUndef('')).toBeFalsy();
+      expect(helpers.isNullOrUndef('String')).toBeFalsy();
+      expect(helpers.isNullOrUndef(0)).toBeFalsy();
+      expect(helpers.isNullOrUndef([])).toBeFalsy();
+      expect(helpers.isNullOrUndef({})).toBeFalsy();
+      expect(helpers.isNullOrUndef([42])).toBeFalsy();
+      expect(helpers.isNullOrUndef(new Date())).toBeFalsy();
+    });
+  });
+
+  describe('valueOrDefault', function() {
+    it('should return value if defined', function() {
+      var object = {};
+      var array = [];
+
+      expect(helpers.valueOrDefault(null, 42)).toBe(null);
+      expect(helpers.valueOrDefault(false, 42)).toBe(false);
+      expect(helpers.valueOrDefault(object, 42)).toBe(object);
+      expect(helpers.valueOrDefault(array, 42)).toBe(array);
+      expect(helpers.valueOrDefault('', 42)).toBe('');
+      expect(helpers.valueOrDefault(0, 42)).toBe(0);
+    });
+    it('should return default if undefined', function() {
+      expect(helpers.valueOrDefault(undefined, 42)).toBe(42);
+      expect(helpers.valueOrDefault({}.foo, 42)).toBe(42);
+    });
+  });
+
+  describe('callback', function() {
+    it('should return undefined if fn is not a function', function() {
+      expect(helpers.callback()).not.toBeDefined();
+      expect(helpers.callback(null)).not.toBeDefined();
+      expect(helpers.callback(42)).not.toBeDefined();
+      expect(helpers.callback([])).not.toBeDefined();
+      expect(helpers.callback({})).not.toBeDefined();
+    });
+    it('should call fn with the given args', function() {
+      var spy = jasmine.createSpy('spy');
+      helpers.callback(spy);
+      helpers.callback(spy, []);
+      helpers.callback(spy, ['foo']);
+      helpers.callback(spy, [42, 'bar']);
+
+      expect(spy.calls.argsFor(0)).toEqual([]);
+      expect(spy.calls.argsFor(1)).toEqual([]);
+      expect(spy.calls.argsFor(2)).toEqual(['foo']);
+      expect(spy.calls.argsFor(3)).toEqual([42, 'bar']);
+    });
+    it('should call fn with the given scope', function() {
+      var spy = jasmine.createSpy('spy');
+      var scope = {};
+
+      helpers.callback(spy);
+      helpers.callback(spy, [], null);
+      helpers.callback(spy, [], undefined);
+      helpers.callback(spy, [], scope);
+
+      expect(spy.calls.all()[0].object).toBe(window);
+      expect(spy.calls.all()[1].object).toBe(window);
+      expect(spy.calls.all()[2].object).toBe(window);
+      expect(spy.calls.all()[3].object).toBe(scope);
+    });
+    it('should return the value returned by fn', function() {
+      expect(helpers.callback(helpers.noop, [41])).toBe(undefined);
+      expect(helpers.callback(function(i) {
+        return i + 1;
+      }, [41])).toBe(42);
+    });
+  });
+
+  describe('each', function() {
+    it('should iterate over an array forward if reverse === false', function() {
+      var scope = {};
+      var scopes = [];
+      var items = [];
+      var keys = [];
+
+      helpers.each(['foo', 'bar', 42], function(item, key) {
+        scopes.push(this);
+        items.push(item);
+        keys.push(key);
+      }, scope);
+
+      expect(scopes).toEqual([scope, scope, scope]);
+      expect(items).toEqual(['foo', 'bar', 42]);
+      expect(keys).toEqual([0, 1, 2]);
+    });
+    it('should iterate over an array backward if reverse === true', function() {
+      var scope = {};
+      var scopes = [];
+      var items = [];
+      var keys = [];
+
+      helpers.each(['foo', 'bar', 42], function(item, key) {
+        scopes.push(this);
+        items.push(item);
+        keys.push(key);
+      }, scope, true);
+
+      expect(scopes).toEqual([scope, scope, scope]);
+      expect(items).toEqual([42, 'bar', 'foo']);
+      expect(keys).toEqual([2, 1, 0]);
+    });
+    it('should iterate over object properties', function() {
+      var scope = {};
+      var scopes = [];
+      var items = [];
+
+      helpers.each({a: 'foo', b: 'bar', c: 42}, function(item, key) {
+        scopes.push(this);
+        items[key] = item;
+      }, scope);
+
+      expect(scopes).toEqual([scope, scope, scope]);
+      expect(items).toEqual(jasmine.objectContaining({a: 'foo', b: 'bar', c: 42}));
+    });
+    it('should not throw when called with a non iterable object', function() {
+      expect(function() {
+        helpers.each(undefined);
+      }).not.toThrow();
+      expect(function() {
+        helpers.each(null);
+      }).not.toThrow();
+      expect(function() {
+        helpers.each(42);
+      }).not.toThrow();
+    });
+  });
+
+  describe('_elementsEqual', function() {
+    it('should return true if arrays are the same', function() {
+      expect(helpers._elementsEqual(
+        [{datasetIndex: 0, index: 1}, {datasetIndex: 0, index: 2}],
+        [{datasetIndex: 0, index: 1}, {datasetIndex: 0, index: 2}])).toBeTruthy();
+    });
+    it('should return false if arrays are not the same', function() {
+      expect(helpers._elementsEqual([], [{datasetIndex: 0, index: 1}])).toBeFalsy();
+      expect(helpers._elementsEqual([{datasetIndex: 0, index: 2}], [{datasetIndex: 0, index: 1}])).toBeFalsy();
+    });
+  });
+
+  describe('clone', function() {
+    it('should clone primitive values', function() {
+      expect(helpers.clone()).toBe(undefined);
+      expect(helpers.clone(null)).toBe(null);
+      expect(helpers.clone(true)).toBe(true);
+      expect(helpers.clone(42)).toBe(42);
+      expect(helpers.clone('foo')).toBe('foo');
+    });
+    it('should perform a deep copy of arrays', function() {
+      var o0 = {a: 42};
+      var o1 = {s: 's'};
+      var a0 = ['bar'];
+      var a1 = [a0, o0, 2];
+      var f0 = function() {};
+      var input = [a1, o1, f0, 42, 'foo'];
+      var output = helpers.clone(input);
+
+      expect(output).toEqual(input);
+      expect(output).not.toBe(input);
+      expect(output[0]).not.toBe(a1);
+      expect(output[0][0]).not.toBe(a0);
+      expect(output[1]).not.toBe(o1);
+    });
+    it('should perform a deep copy of objects', function() {
+      var a0 = ['bar'];
+      var a1 = [1, 2, 3];
+      var o0 = {a: a1, i: 42};
+      var f0 = function() {};
+      var input = {o: o0, a: a0, f: f0, s: 'foo', i: 42};
+      var output = helpers.clone(input);
+
+      expect(output).toEqual(input);
+      expect(output).not.toBe(input);
+      expect(output.o).not.toBe(o0);
+      expect(output.o.a).not.toBe(a1);
+      expect(output.a).not.toBe(a0);
+    });
+  });
+
+  describe('merge', function() {
+    it('should not allow prototype pollution', function() {
+      var test = helpers.merge({}, JSON.parse('{"__proto__":{"polluted": true}}'));
+      expect(test.prototype).toBeUndefined();
+      expect(Object.prototype.polluted).toBeUndefined();
+    });
+    it('should update target and return it', function() {
+      var target = {a: 1};
+      var result = helpers.merge(target, {a: 2, b: 'foo'});
+      expect(target).toEqual({a: 2, b: 'foo'});
+      expect(target).toBe(result);
+    });
+    it('should return target if not an object', function() {
+      expect(helpers.merge(undefined, {a: 42})).toEqual(undefined);
+      expect(helpers.merge(null, {a: 42})).toEqual(null);
+      expect(helpers.merge('foo', {a: 42})).toEqual('foo');
+      expect(helpers.merge(['foo', 'bar'], {a: 42})).toEqual(['foo', 'bar']);
+    });
+    it('should ignore sources which are not objects', function() {
+      expect(helpers.merge({a: 42})).toEqual({a: 42});
+      expect(helpers.merge({a: 42}, null)).toEqual({a: 42});
+      expect(helpers.merge({a: 42}, 42)).toEqual({a: 42});
+    });
+    it('should recursively overwrite target with source properties', function() {
+      expect(helpers.merge({a: {b: 1}}, {a: {c: 2}})).toEqual({a: {b: 1, c: 2}});
+      expect(helpers.merge({a: {b: 1}}, {a: {b: 2}})).toEqual({a: {b: 2}});
+      expect(helpers.merge({a: [1, 2]}, {a: [3, 4]})).toEqual({a: [3, 4]});
+      expect(helpers.merge({a: 42}, {a: {b: 0}})).toEqual({a: {b: 0}});
+      expect(helpers.merge({a: 42}, {a: null})).toEqual({a: null});
+      expect(helpers.merge({a: 42}, {a: undefined})).toEqual({a: undefined});
+    });
+    it('should merge multiple sources in the correct order', function() {
+      var t0 = {a: {b: 1, c: [1, 2]}};
+      var s0 = {a: {d: 3}, e: {f: 4}};
+      var s1 = {a: {b: 5}};
+      var s2 = {a: {c: [6, 7]}, e: 'foo'};
+
+      expect(helpers.merge(t0, [s0, s1, s2])).toEqual({a: {b: 5, c: [6, 7], d: 3}, e: 'foo'});
+    });
+    it('should deep copy merged values from sources', function() {
+      var a0 = ['foo'];
+      var a1 = [1, 2, 3];
+      var o0 = {a: a1, i: 42};
+      var output = helpers.merge({}, {a: a0, o: o0});
+
+      expect(output).toEqual({a: a0, o: o0});
+      expect(output.a).not.toBe(a0);
+      expect(output.o).not.toBe(o0);
+      expect(output.o.a).not.toBe(a1);
+    });
+  });
+
+  describe('mergeIf', function() {
+    it('should not allow prototype pollution', function() {
+      var test = helpers.mergeIf({}, JSON.parse('{"__proto__":{"polluted": true}}'));
+      expect(test.prototype).toBeUndefined();
+      expect(Object.prototype.polluted).toBeUndefined();
+    });
+    it('should update target and return it', function() {
+      var target = {a: 1};
+      var result = helpers.mergeIf(target, {a: 2, b: 'foo'});
+      expect(target).toEqual({a: 1, b: 'foo'});
+      expect(target).toBe(result);
+    });
+    it('should return target if not an object', function() {
+      expect(helpers.mergeIf(undefined, {a: 42})).toEqual(undefined);
+      expect(helpers.mergeIf(null, {a: 42})).toEqual(null);
+      expect(helpers.mergeIf('foo', {a: 42})).toEqual('foo');
+      expect(helpers.mergeIf(['foo', 'bar'], {a: 42})).toEqual(['foo', 'bar']);
+    });
+    it('should ignore sources which are not objects', function() {
+      expect(helpers.mergeIf({a: 42})).toEqual({a: 42});
+      expect(helpers.mergeIf({a: 42}, null)).toEqual({a: 42});
+      expect(helpers.mergeIf({a: 42}, 42)).toEqual({a: 42});
+    });
+    it('should recursively copy source properties in target only if they do not exist in target', function() {
+      expect(helpers.mergeIf({a: {b: 1}}, {a: {c: 2}})).toEqual({a: {b: 1, c: 2}});
+      expect(helpers.mergeIf({a: {b: 1}}, {a: {b: 2}})).toEqual({a: {b: 1}});
+      expect(helpers.mergeIf({a: [1, 2]}, {a: [3, 4]})).toEqual({a: [1, 2]});
+      expect(helpers.mergeIf({a: 0}, {a: {b: 2}})).toEqual({a: 0});
+      expect(helpers.mergeIf({a: null}, {a: 42})).toEqual({a: null});
+      expect(helpers.mergeIf({a: undefined}, {a: 42})).toEqual({a: undefined});
+    });
+    it('should merge multiple sources in the correct order', function() {
+      var t0 = {a: {b: 1, c: [1, 2]}};
+      var s0 = {a: {d: 3}, e: {f: 4}};
+      var s1 = {a: {b: 5}};
+      var s2 = {a: {c: [6, 7]}, e: 'foo'};
+
+      expect(helpers.mergeIf(t0, [s0, s1, s2])).toEqual({a: {b: 1, c: [1, 2], d: 3}, e: {f: 4}});
+    });
+    it('should deep copy merged values from sources', function() {
+      var a0 = ['foo'];
+      var a1 = [1, 2, 3];
+      var o0 = {a: a1, i: 42};
+      var output = helpers.mergeIf({}, {a: a0, o: o0});
+
+      expect(output).toEqual({a: a0, o: o0});
+      expect(output.a).not.toBe(a0);
+      expect(output.o).not.toBe(o0);
+      expect(output.o.a).not.toBe(a1);
+    });
+  });
+
+  describe('resolveObjectKey', function() {
+    it('should resolve empty key to root object', function() {
+      const obj = {test: true};
+      expect(helpers.resolveObjectKey(obj, '')).toEqual(obj);
+    });
+    it('should resolve one level', function() {
+      const obj = {
+        bool: true,
+        str: 'test',
+        int: 42,
+        obj: {name: 'object'}
+      };
+      expect(helpers.resolveObjectKey(obj, 'bool')).toEqual(true);
+      expect(helpers.resolveObjectKey(obj, 'str')).toEqual('test');
+      expect(helpers.resolveObjectKey(obj, 'int')).toEqual(42);
+      expect(helpers.resolveObjectKey(obj, 'obj')).toEqual(obj.obj);
+    });
+    it('should resolve multiple levels', function() {
+      const obj = {
+        child: {
+          level: 1,
+          child: {
+            level: 2,
+            child: {
+              level: 3
+            }
+          }
+        }
+      };
+      expect(helpers.resolveObjectKey(obj, 'child.level')).toEqual(1);
+      expect(helpers.resolveObjectKey(obj, 'child.child.level')).toEqual(2);
+      expect(helpers.resolveObjectKey(obj, 'child.child.child.level')).toEqual(3);
+    });
+    it('should resolve circular reference', function() {
+      const root = {};
+      const child = {root};
+      child.child = child;
+      root.child = child;
+      expect(helpers.resolveObjectKey(root, 'child')).toEqual(child);
+      expect(helpers.resolveObjectKey(root, 'child.child.child.child.child.child')).toEqual(child);
+      expect(helpers.resolveObjectKey(root, 'child.child.root')).toEqual(root);
+    });
+    it('should break at empty key', function() {
+      const obj = {
+        child: {
+          level: 1,
+          child: {
+            level: 2,
+            child: {
+              level: 3
+            }
+          }
+        }
+      };
+      expect(helpers.resolveObjectKey(obj, 'child..level')).toEqual(obj.child);
+      expect(helpers.resolveObjectKey(obj, 'child.child.level...')).toEqual(2);
+      expect(helpers.resolveObjectKey(obj, '.')).toEqual(obj);
+      expect(helpers.resolveObjectKey(obj, '..')).toEqual(obj);
+    });
+    it('should resolve undefined', function() {
+      const obj = {
+        child: {
+          level: 1,
+          child: {
+            level: 2,
+            child: {
+              level: 3
+            }
+          }
+        }
+      };
+      expect(helpers.resolveObjectKey(obj, 'level')).toEqual(undefined);
+      expect(helpers.resolveObjectKey(obj, 'child.level.a')).toEqual(undefined);
+    });
+    it('should throw on invalid input', function() {
+      expect(() => helpers.resolveObjectKey(undefined, undefined)).toThrow();
+      expect(() => helpers.resolveObjectKey({}, null)).toThrow();
+      expect(() => helpers.resolveObjectKey({}, false)).toThrow();
+      expect(() => helpers.resolveObjectKey({}, true)).toThrow();
+      expect(() => helpers.resolveObjectKey({}, 1)).toThrow();
+    });
+  });
 });
index 1b888e986f249ab78718dfcdb9271dfd9f86348c..25a447befd70e8382bc9b926795a2c91d90c4aa6 100644 (file)
 describe('Curve helper tests', function() {
-       let helpers;
+  let helpers;
 
-       beforeAll(function() {
-               helpers = window.Chart.helpers;
-       });
+  beforeAll(function() {
+    helpers = window.Chart.helpers;
+  });
 
-       it('should spline curves', function() {
-               expect(helpers.splineCurve({
-                       x: 0,
-                       y: 0
-               }, {
-                       x: 1,
-                       y: 1
-               }, {
-                       x: 2,
-                       y: 0
-               }, 0)).toEqual({
-                       previous: {
-                               x: 1,
-                               y: 1,
-                       },
-                       next: {
-                               x: 1,
-                               y: 1,
-                       }
-               });
+  it('should spline curves', function() {
+    expect(helpers.splineCurve({
+      x: 0,
+      y: 0
+    }, {
+      x: 1,
+      y: 1
+    }, {
+      x: 2,
+      y: 0
+    }, 0)).toEqual({
+      previous: {
+        x: 1,
+        y: 1,
+      },
+      next: {
+        x: 1,
+        y: 1,
+      }
+    });
 
-               expect(helpers.splineCurve({
-                       x: 0,
-                       y: 0
-               }, {
-                       x: 1,
-                       y: 1
-               }, {
-                       x: 2,
-                       y: 0
-               }, 1)).toEqual({
-                       previous: {
-                               x: 0,
-                               y: 1,
-                       },
-                       next: {
-                               x: 2,
-                               y: 1,
-                       }
-               });
-       });
+    expect(helpers.splineCurve({
+      x: 0,
+      y: 0
+    }, {
+      x: 1,
+      y: 1
+    }, {
+      x: 2,
+      y: 0
+    }, 1)).toEqual({
+      previous: {
+        x: 0,
+        y: 1,
+      },
+      next: {
+        x: 2,
+        y: 1,
+      }
+    });
+  });
 
-       it('should spline curves with monotone cubic interpolation', function() {
-               var dataPoints = [
-                       {x: 0, y: 0, skip: false},
-                       {x: 3, y: 6, skip: false},
-                       {x: 9, y: 6, skip: false},
-                       {x: 12, y: 60, skip: false},
-                       {x: 15, y: 60, skip: false},
-                       {x: 18, y: 120, skip: false},
-                       {x: null, y: null, skip: true},
-                       {x: 21, y: 180, skip: false},
-                       {x: 24, y: 120, skip: false},
-                       {x: 27, y: 125, skip: false},
-                       {x: 30, y: 105, skip: false},
-                       {x: 33, y: 110, skip: false},
-                       {x: 33, y: 110, skip: false},
-                       {x: 36, y: 170, skip: false}
-               ];
-               helpers.splineCurveMonotone(dataPoints);
-               expect(dataPoints).toEqual([{
-                       x: 0,
-                       y: 0,
-                       skip: false,
-                       controlPointNextX: 1,
-                       controlPointNextY: 2
-               },
-               {
-                       x: 3,
-                       y: 6,
-                       skip: false,
-                       controlPointPreviousX: 2,
-                       controlPointPreviousY: 6,
-                       controlPointNextX: 5,
-                       controlPointNextY: 6
-               },
-               {
-                       x: 9,
-                       y: 6,
-                       skip: false,
-                       controlPointPreviousX: 7,
-                       controlPointPreviousY: 6,
-                       controlPointNextX: 10,
-                       controlPointNextY: 6
-               },
-               {
-                       x: 12,
-                       y: 60,
-                       skip: false,
-                       controlPointPreviousX: 11,
-                       controlPointPreviousY: 60,
-                       controlPointNextX: 13,
-                       controlPointNextY: 60
-               },
-               {
-                       x: 15,
-                       y: 60,
-                       skip: false,
-                       controlPointPreviousX: 14,
-                       controlPointPreviousY: 60,
-                       controlPointNextX: 16,
-                       controlPointNextY: 60
-               },
-               {
-                       x: 18,
-                       y: 120,
-                       skip: false,
-                       controlPointPreviousX: 17,
-                       controlPointPreviousY: 100
-               },
-               {
-                       x: null,
-                       y: null,
-                       skip: true
-               },
-               {
-                       x: 21,
-                       y: 180,
-                       skip: false,
-                       controlPointNextX: 22,
-                       controlPointNextY: 160
-               },
-               {
-                       x: 24,
-                       y: 120,
-                       skip: false,
-                       controlPointPreviousX: 23,
-                       controlPointPreviousY: 120,
-                       controlPointNextX: 25,
-                       controlPointNextY: 120
-               },
-               {
-                       x: 27,
-                       y: 125,
-                       skip: false,
-                       controlPointPreviousX: 26,
-                       controlPointPreviousY: 125,
-                       controlPointNextX: 28,
-                       controlPointNextY: 125
-               },
-               {
-                       x: 30,
-                       y: 105,
-                       skip: false,
-                       controlPointPreviousX: 29,
-                       controlPointPreviousY: 105,
-                       controlPointNextX: 31,
-                       controlPointNextY: 105
-               },
-               {
-                       x: 33,
-                       y: 110,
-                       skip: false,
-                       controlPointPreviousX: 32,
-                       controlPointPreviousY: 110,
-                       controlPointNextX: 33,
-                       controlPointNextY: 110
-               },
-               {
-                       x: 33,
-                       y: 110,
-                       skip: false,
-                       controlPointPreviousX: 33,
-                       controlPointPreviousY: 110,
-                       controlPointNextX: 34,
-                       controlPointNextY: 110
-               },
-               {
-                       x: 36,
-                       y: 170,
-                       skip: false,
-                       controlPointPreviousX: 35,
-                       controlPointPreviousY: 150
-               }]);
-       });
+  it('should spline curves with monotone cubic interpolation', function() {
+    var dataPoints = [
+      {x: 0, y: 0, skip: false},
+      {x: 3, y: 6, skip: false},
+      {x: 9, y: 6, skip: false},
+      {x: 12, y: 60, skip: false},
+      {x: 15, y: 60, skip: false},
+      {x: 18, y: 120, skip: false},
+      {x: null, y: null, skip: true},
+      {x: 21, y: 180, skip: false},
+      {x: 24, y: 120, skip: false},
+      {x: 27, y: 125, skip: false},
+      {x: 30, y: 105, skip: false},
+      {x: 33, y: 110, skip: false},
+      {x: 33, y: 110, skip: false},
+      {x: 36, y: 170, skip: false}
+    ];
+    helpers.splineCurveMonotone(dataPoints);
+    expect(dataPoints).toEqual([{
+      x: 0,
+      y: 0,
+      skip: false,
+      controlPointNextX: 1,
+      controlPointNextY: 2
+    },
+    {
+      x: 3,
+      y: 6,
+      skip: false,
+      controlPointPreviousX: 2,
+      controlPointPreviousY: 6,
+      controlPointNextX: 5,
+      controlPointNextY: 6
+    },
+    {
+      x: 9,
+      y: 6,
+      skip: false,
+      controlPointPreviousX: 7,
+      controlPointPreviousY: 6,
+      controlPointNextX: 10,
+      controlPointNextY: 6
+    },
+    {
+      x: 12,
+      y: 60,
+      skip: false,
+      controlPointPreviousX: 11,
+      controlPointPreviousY: 60,
+      controlPointNextX: 13,
+      controlPointNextY: 60
+    },
+    {
+      x: 15,
+      y: 60,
+      skip: false,
+      controlPointPreviousX: 14,
+      controlPointPreviousY: 60,
+      controlPointNextX: 16,
+      controlPointNextY: 60
+    },
+    {
+      x: 18,
+      y: 120,
+      skip: false,
+      controlPointPreviousX: 17,
+      controlPointPreviousY: 100
+    },
+    {
+      x: null,
+      y: null,
+      skip: true
+    },
+    {
+      x: 21,
+      y: 180,
+      skip: false,
+      controlPointNextX: 22,
+      controlPointNextY: 160
+    },
+    {
+      x: 24,
+      y: 120,
+      skip: false,
+      controlPointPreviousX: 23,
+      controlPointPreviousY: 120,
+      controlPointNextX: 25,
+      controlPointNextY: 120
+    },
+    {
+      x: 27,
+      y: 125,
+      skip: false,
+      controlPointPreviousX: 26,
+      controlPointPreviousY: 125,
+      controlPointNextX: 28,
+      controlPointNextY: 125
+    },
+    {
+      x: 30,
+      y: 105,
+      skip: false,
+      controlPointPreviousX: 29,
+      controlPointPreviousY: 105,
+      controlPointNextX: 31,
+      controlPointNextY: 105
+    },
+    {
+      x: 33,
+      y: 110,
+      skip: false,
+      controlPointPreviousX: 32,
+      controlPointPreviousY: 110,
+      controlPointNextX: 33,
+      controlPointNextY: 110
+    },
+    {
+      x: 33,
+      y: 110,
+      skip: false,
+      controlPointPreviousX: 33,
+      controlPointPreviousY: 110,
+      controlPointNextX: 34,
+      controlPointNextY: 110
+    },
+    {
+      x: 36,
+      y: 170,
+      skip: false,
+      controlPointPreviousX: 35,
+      controlPointPreviousY: 150
+    }]);
+  });
 });
index 9cd370d055895857d7749a35d5a4cda5c02d064c..d3b3f4c6bf364d9893daff9559b7a96a3d2f54d0 100644 (file)
 describe('DOM helpers tests', function() {
-       let helpers;
+  let helpers;
 
-       beforeAll(function() {
-               helpers = window.Chart.helpers;
-       });
+  beforeAll(function() {
+    helpers = window.Chart.helpers;
+  });
 
-       it ('should get the maximum size for a node', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum size for a node', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create the div we want to get the max size for
-               var innerDiv = document.createElement('div');
-               div.appendChild(innerDiv);
+    // Create the div we want to get the max size for
+    var innerDiv = document.createElement('div');
+    div.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum width and height for a node in a ShadowRoot', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum width and height for a node in a ShadowRoot', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               if (!div.attachShadow) {
-                       // Shadow DOM is not natively supported
-                       return;
-               }
+    if (!div.attachShadow) {
+      // Shadow DOM is not natively supported
+      return;
+    }
 
-               var shadow = div.attachShadow({mode: 'closed'});
+    var shadow = div.attachShadow({mode: 'closed'});
 
-               // Create the div we want to get the max size for
-               var innerDiv = document.createElement('div');
-               shadow.appendChild(innerDiv);
+    // Create the div we want to get the max size for
+    var innerDiv = document.createElement('div');
+    shadow.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 200, height: 300}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum width of a node that has a max-width style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum width of a node that has a max-width style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create the div we want to get the max size for and set a max-width style
-               var innerDiv = document.createElement('div');
-               innerDiv.style.maxWidth = '150px';
-               div.appendChild(innerDiv);
+    // Create the div we want to get the max size for and set a max-width style
+    var innerDiv = document.createElement('div');
+    innerDiv.style.maxWidth = '150px';
+    div.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum height of a node that has a max-height style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum height of a node that has a max-height style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create the div we want to get the max size for and set a max-height style
-               var innerDiv = document.createElement('div');
-               innerDiv.style.maxHeight = '150px';
-               div.appendChild(innerDiv);
+    // Create the div we want to get the max size for and set a max-height style
+    var innerDiv = document.createElement('div');
+    innerDiv.style.maxHeight = '150px';
+    div.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum width of a node when the parent has a max-width style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum width of a node when the parent has a max-width style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create an inner wrapper around our div we want to size and give that a max-width style
-               var parentDiv = document.createElement('div');
-               parentDiv.style.maxWidth = '150px';
-               div.appendChild(parentDiv);
+    // Create an inner wrapper around our div we want to size and give that a max-width style
+    var parentDiv = document.createElement('div');
+    parentDiv.style.maxWidth = '150px';
+    div.appendChild(parentDiv);
 
-               // Create the div we want to get the max size for
-               var innerDiv = document.createElement('div');
-               parentDiv.appendChild(innerDiv);
+    // Create the div we want to get the max size for
+    var innerDiv = document.createElement('div');
+    parentDiv.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 150}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum height of a node when the parent has a max-height style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum height of a node when the parent has a max-height style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create an inner wrapper around our div we want to size and give that a max-height style
-               var parentDiv = document.createElement('div');
-               parentDiv.style.maxHeight = '150px';
-               div.appendChild(parentDiv);
+    // Create an inner wrapper around our div we want to size and give that a max-height style
+    var parentDiv = document.createElement('div');
+    parentDiv.style.maxHeight = '150px';
+    div.appendChild(parentDiv);
 
-               // Create the div we want to get the max size for
-               var innerDiv = document.createElement('div');
-               innerDiv.style.height = '300px'; // make it large
-               parentDiv.appendChild(innerDiv);
+    // Create the div we want to get the max size for
+    var innerDiv = document.createElement('div');
+    innerDiv.style.height = '300px'; // make it large
+    parentDiv.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum width of a node that has a percentage max-width style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum width of a node that has a percentage max-width style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create the div we want to get the max size for and set a max-width style
-               var innerDiv = document.createElement('div');
-               innerDiv.style.maxWidth = '50%';
-               div.appendChild(innerDiv);
+    // Create the div we want to get the max size for and set a max-width style
+    var innerDiv = document.createElement('div');
+    innerDiv.style.maxWidth = '50%';
+    div.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it('should get the maximum height of a node that has a percentage max-height style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it('should get the maximum height of a node that has a percentage max-height style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create the div we want to get the max size for and set a max-height style
-               var innerDiv = document.createElement('div');
-               innerDiv.style.maxHeight = '50%';
-               div.appendChild(innerDiv);
+    // Create the div we want to get the max size for and set a max-height style
+    var innerDiv = document.createElement('div');
+    innerDiv.style.maxHeight = '50%';
+    div.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
 
-               document.body.removeChild(div);
-       });
+    document.body.removeChild(div);
+  });
 
-       it ('should get the maximum width of a node when the parent has a percentage max-width style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
+  it ('should get the maximum width of a node when the parent has a percentage max-width style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
 
-               document.body.appendChild(div);
+    document.body.appendChild(div);
 
-               // Create an inner wrapper around our div we want to size and give that a max-width style
-               var parentDiv = document.createElement('div');
-               parentDiv.style.maxWidth = '50%';
-               div.appendChild(parentDiv);
+    // Create an inner wrapper around our div we want to size and give that a max-width style
+    var parentDiv = document.createElement('div');
+    parentDiv.style.maxWidth = '50%';
+    div.appendChild(parentDiv);
 
-               // Create the div we want to get the max size for
-               var innerDiv = document.createElement('div');
-               parentDiv.appendChild(innerDiv);
+    // Create the div we want to get the max size for
+    var innerDiv = document.createElement('div');
+    parentDiv.appendChild(innerDiv);
 
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({width: 100}));
 
-               document.body.removeChild(div);
-       });
-
-       it ('should get the maximum height of a node when the parent has a percentage max-height style', function() {
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '200px';
-               div.style.height = '300px';
-
-               document.body.appendChild(div);
-
-               // Create an inner wrapper around our div we want to size and give that a max-height style
-               var parentDiv = document.createElement('div');
-               parentDiv.style.maxHeight = '50%';
-               div.appendChild(parentDiv);
-
-               var innerDiv = document.createElement('div');
-               innerDiv.style.height = '300px'; // make it large
-               parentDiv.appendChild(innerDiv);
-
-               expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
-
-               document.body.removeChild(div);
-       });
-
-       it ('Should get padding of parent as number (pixels) when defined as percent (returns incorrectly in IE11)', function() {
-
-               // Create div with fixed size as a test bed
-               var div = document.createElement('div');
-               div.style.width = '300px';
-               div.style.height = '300px';
-               document.body.appendChild(div);
-
-               // Inner DIV to have 5% padding of parent
-               var innerDiv = document.createElement('div');
-
-               div.appendChild(innerDiv);
-
-               var canvas = document.createElement('canvas');
-               innerDiv.appendChild(canvas);
-
-               // No padding
-               expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 300}));
-
-               // test with percentage
-               innerDiv.style.padding = '5%';
-               expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 270}));
-
-               // test with pixels
-               innerDiv.style.padding = '10px';
-               expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 280}));
-
-               document.body.removeChild(div);
-       });
-
-       it ('should leave styled height and width on canvas if explicitly set', function() {
-               var chart = window.acquireChart({}, {
-                       canvas: {
-                               height: 200,
-                               width: 200,
-                               style: 'height: 400px; width: 400px;'
-                       }
-               });
-
-               helpers.retinaScale(chart, true);
-
-               var canvas = chart.canvas;
-
-               expect(canvas.style.height).toBe('400px');
-               expect(canvas.style.width).toBe('400px');
-       });
-
-       describe('getRelativePosition', function() {
-               it('should use offsetX/Y when available', function() {
-                       const event = {offsetX: 50, offsetY: 100};
-                       const chart = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                               }
-                       });
-                       expect(helpers.getRelativePosition(event, chart)).toEqual({x: 50, y: 100});
-
-                       const chart2 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'padding: 10px'
-                               }
-                       });
-                       expect(helpers.getRelativePosition(event, chart2)).toEqual({
-                               x: Math.round((event.offsetX - 10) / 180 * 200),
-                               y: Math.round((event.offsetY - 10) / 180 * 200)
-                       });
-
-                       const chart3 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'width: 400px, height: 400px; padding: 10px'
-                               }
-                       });
-                       expect(helpers.getRelativePosition(event, chart3)).toEqual({
-                               x: Math.round((event.offsetX - 10) / 360 * 400),
-                               y: Math.round((event.offsetY - 10) / 360 * 400)
-                       });
-
-                       const chart4 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'width: 400px, height: 400px; padding: 10px; position: absolute; left: 20, top: 20'
-                               }
-                       });
-                       expect(helpers.getRelativePosition(event, chart4)).toEqual({
-                               x: Math.round((event.offsetX - 10) / 360 * 400),
-                               y: Math.round((event.offsetY - 10) / 360 * 400)
-                       });
-
-               });
-
-               it('should calculate from clientX/Y as fallback', function() {
-                       const chart = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                               }
-                       });
-
-                       const event = {
-                               clientX: 50,
-                               clientY: 100
-                       };
-
-                       const rect = chart.canvas.getBoundingClientRect();
-                       const pos = helpers.getRelativePosition(event, chart);
-                       expect(Math.abs(pos.x - Math.round(event.clientX - rect.x))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos.y - Math.round(event.clientY - rect.y))).toBeLessThanOrEqual(1);
-
-                       const chart2 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'padding: 10px'
-                               }
-                       });
-                       const rect2 = chart2.canvas.getBoundingClientRect();
-                       const pos2 = helpers.getRelativePosition(event, chart2);
-                       expect(Math.abs(pos2.x - Math.round((event.clientX - rect2.x - 10) / 180 * 200))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos2.y - Math.round((event.clientY - rect2.y - 10) / 180 * 200))).toBeLessThanOrEqual(1);
-
-                       const chart3 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'width: 400px, height: 400px; padding: 10px'
-                               }
-                       });
-                       const rect3 = chart3.canvas.getBoundingClientRect();
-                       const pos3 = helpers.getRelativePosition(event, chart3);
-                       expect(Math.abs(pos3.x - Math.round((event.clientX - rect3.x - 10) / 360 * 400))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos3.y - Math.round((event.clientY - rect3.y - 10) / 360 * 400))).toBeLessThanOrEqual(1);
-               });
-
-               it ('should get the correct relative position for a node in a ShadowRoot', function() {
-                       const event = {
-                               offsetX: 50,
-                               offsetY: 100,
-                               clientX: 50,
-                               clientY: 100
-                       };
-
-                       const chart = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                               },
-                               useShadowDOM: true
-                       });
-
-                       event.target = chart.canvas.parentNode.host;
-                       expect(event.target.shadowRoot).not.toEqual(null);
-                       const rect = chart.canvas.getBoundingClientRect();
-                       const pos = helpers.getRelativePosition(event, chart);
-                       expect(Math.abs(pos.x - Math.round(event.clientX - rect.x))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos.y - Math.round(event.clientY - rect.y))).toBeLessThanOrEqual(1);
-
-                       const chart2 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'padding: 10px'
-                               },
-                               useShadowDOM: true
-                       });
-
-                       event.target = chart2.canvas.parentNode.host;
-                       const rect2 = chart2.canvas.getBoundingClientRect();
-                       const pos2 = helpers.getRelativePosition(event, chart2);
-                       expect(Math.abs(pos2.x - Math.round((event.clientX - rect2.x - 10) / 180 * 200))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos2.y - Math.round((event.clientY - rect2.y - 10) / 180 * 200))).toBeLessThanOrEqual(1);
-
-                       const chart3 = window.acquireChart({}, {
-                               canvas: {
-                                       height: 200,
-                                       width: 200,
-                                       style: 'width: 400px, height: 400px; padding: 10px'
-                               },
-                               useShadowDOM: true
-                       });
-
-                       event.target = chart3.canvas.parentNode.host;
-                       const rect3 = chart3.canvas.getBoundingClientRect();
-                       const pos3 = helpers.getRelativePosition(event, chart3);
-                       expect(Math.abs(pos3.x - Math.round((event.clientX - rect3.x - 10) / 360 * 400))).toBeLessThanOrEqual(1);
-                       expect(Math.abs(pos3.y - Math.round((event.clientY - rect3.y - 10) / 360 * 400))).toBeLessThanOrEqual(1);
-               });
-       });
+    document.body.removeChild(div);
+  });
+
+  it ('should get the maximum height of a node when the parent has a percentage max-height style', function() {
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '200px';
+    div.style.height = '300px';
+
+    document.body.appendChild(div);
+
+    // Create an inner wrapper around our div we want to size and give that a max-height style
+    var parentDiv = document.createElement('div');
+    parentDiv.style.maxHeight = '50%';
+    div.appendChild(parentDiv);
+
+    var innerDiv = document.createElement('div');
+    innerDiv.style.height = '300px'; // make it large
+    parentDiv.appendChild(innerDiv);
+
+    expect(helpers.getMaximumSize(innerDiv)).toEqual(jasmine.objectContaining({height: 150}));
+
+    document.body.removeChild(div);
+  });
+
+  it ('Should get padding of parent as number (pixels) when defined as percent (returns incorrectly in IE11)', function() {
+
+    // Create div with fixed size as a test bed
+    var div = document.createElement('div');
+    div.style.width = '300px';
+    div.style.height = '300px';
+    document.body.appendChild(div);
+
+    // Inner DIV to have 5% padding of parent
+    var innerDiv = document.createElement('div');
+
+    div.appendChild(innerDiv);
+
+    var canvas = document.createElement('canvas');
+    innerDiv.appendChild(canvas);
+
+    // No padding
+    expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 300}));
+
+    // test with percentage
+    innerDiv.style.padding = '5%';
+    expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 270}));
+
+    // test with pixels
+    innerDiv.style.padding = '10px';
+    expect(helpers.getMaximumSize(canvas)).toEqual(jasmine.objectContaining({width: 280}));
+
+    document.body.removeChild(div);
+  });
+
+  it ('should leave styled height and width on canvas if explicitly set', function() {
+    var chart = window.acquireChart({}, {
+      canvas: {
+        height: 200,
+        width: 200,
+        style: 'height: 400px; width: 400px;'
+      }
+    });
+
+    helpers.retinaScale(chart, true);
+
+    var canvas = chart.canvas;
+
+    expect(canvas.style.height).toBe('400px');
+    expect(canvas.style.width).toBe('400px');
+  });
+
+  describe('getRelativePosition', function() {
+    it('should use offsetX/Y when available', function() {
+      const event = {offsetX: 50, offsetY: 100};
+      const chart = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+        }
+      });
+      expect(helpers.getRelativePosition(event, chart)).toEqual({x: 50, y: 100});
+
+      const chart2 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'padding: 10px'
+        }
+      });
+      expect(helpers.getRelativePosition(event, chart2)).toEqual({
+        x: Math.round((event.offsetX - 10) / 180 * 200),
+        y: Math.round((event.offsetY - 10) / 180 * 200)
+      });
+
+      const chart3 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'width: 400px, height: 400px; padding: 10px'
+        }
+      });
+      expect(helpers.getRelativePosition(event, chart3)).toEqual({
+        x: Math.round((event.offsetX - 10) / 360 * 400),
+        y: Math.round((event.offsetY - 10) / 360 * 400)
+      });
+
+      const chart4 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'width: 400px, height: 400px; padding: 10px; position: absolute; left: 20, top: 20'
+        }
+      });
+      expect(helpers.getRelativePosition(event, chart4)).toEqual({
+        x: Math.round((event.offsetX - 10) / 360 * 400),
+        y: Math.round((event.offsetY - 10) / 360 * 400)
+      });
+
+    });
+
+    it('should calculate from clientX/Y as fallback', function() {
+      const chart = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+        }
+      });
+
+      const event = {
+        clientX: 50,
+        clientY: 100
+      };
+
+      const rect = chart.canvas.getBoundingClientRect();
+      const pos = helpers.getRelativePosition(event, chart);
+      expect(Math.abs(pos.x - Math.round(event.clientX - rect.x))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos.y - Math.round(event.clientY - rect.y))).toBeLessThanOrEqual(1);
+
+      const chart2 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'padding: 10px'
+        }
+      });
+      const rect2 = chart2.canvas.getBoundingClientRect();
+      const pos2 = helpers.getRelativePosition(event, chart2);
+      expect(Math.abs(pos2.x - Math.round((event.clientX - rect2.x - 10) / 180 * 200))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos2.y - Math.round((event.clientY - rect2.y - 10) / 180 * 200))).toBeLessThanOrEqual(1);
+
+      const chart3 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'width: 400px, height: 400px; padding: 10px'
+        }
+      });
+      const rect3 = chart3.canvas.getBoundingClientRect();
+      const pos3 = helpers.getRelativePosition(event, chart3);
+      expect(Math.abs(pos3.x - Math.round((event.clientX - rect3.x - 10) / 360 * 400))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos3.y - Math.round((event.clientY - rect3.y - 10) / 360 * 400))).toBeLessThanOrEqual(1);
+    });
+
+    it ('should get the correct relative position for a node in a ShadowRoot', function() {
+      const event = {
+        offsetX: 50,
+        offsetY: 100,
+        clientX: 50,
+        clientY: 100
+      };
+
+      const chart = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+        },
+        useShadowDOM: true
+      });
+
+      event.target = chart.canvas.parentNode.host;
+      expect(event.target.shadowRoot).not.toEqual(null);
+      const rect = chart.canvas.getBoundingClientRect();
+      const pos = helpers.getRelativePosition(event, chart);
+      expect(Math.abs(pos.x - Math.round(event.clientX - rect.x))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos.y - Math.round(event.clientY - rect.y))).toBeLessThanOrEqual(1);
+
+      const chart2 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'padding: 10px'
+        },
+        useShadowDOM: true
+      });
+
+      event.target = chart2.canvas.parentNode.host;
+      const rect2 = chart2.canvas.getBoundingClientRect();
+      const pos2 = helpers.getRelativePosition(event, chart2);
+      expect(Math.abs(pos2.x - Math.round((event.clientX - rect2.x - 10) / 180 * 200))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos2.y - Math.round((event.clientY - rect2.y - 10) / 180 * 200))).toBeLessThanOrEqual(1);
+
+      const chart3 = window.acquireChart({}, {
+        canvas: {
+          height: 200,
+          width: 200,
+          style: 'width: 400px, height: 400px; padding: 10px'
+        },
+        useShadowDOM: true
+      });
+
+      event.target = chart3.canvas.parentNode.host;
+      const rect3 = chart3.canvas.getBoundingClientRect();
+      const pos3 = helpers.getRelativePosition(event, chart3);
+      expect(Math.abs(pos3.x - Math.round((event.clientX - rect3.x - 10) / 360 * 400))).toBeLessThanOrEqual(1);
+      expect(Math.abs(pos3.y - Math.round((event.clientY - rect3.y - 10) / 360 * 400))).toBeLessThanOrEqual(1);
+    });
+  });
 });
index cf5ac99c3e65cf215771f545a4c967b4c8ea1cd1..cae4ca98488777d0717616d9a2329a3955344728 100644 (file)
@@ -1,61 +1,61 @@
 'use strict';
 
 describe('Chart.helpers.easingEffects', function() {
-       var helpers = Chart.helpers;
+  var helpers = Chart.helpers;
 
-       describe('effects', function() {
-               var expected = {
-                       easeInOutBack: [-0, -0.03751855, -0.09255566, -0.07883348, 0.08992579, 0.5, 0.91007421, 1.07883348, 1.09255566, 1.03751855, 1],
-                       easeInOutBounce: [0, 0.03, 0.11375, 0.045, 0.34875, 0.5, 0.65125, 0.955, 0.88625, 0.97, 1],
-                       easeInOutCirc: [-0, 0.01010205, 0.04174243, 0.1, 0.2, 0.5, 0.8, 0.9, 0.95825757, 0.98989795, 1],
-                       easeInOutCubic: [0, 0.004, 0.032, 0.108, 0.256, 0.5, 0.744, 0.892, 0.968, 0.996, 1],
-                       easeInOutElastic: [0, 0.00033916, -0.00390625, 0.02393889, -0.11746158, 0.5, 1.11746158, 0.97606111, 1.00390625, 0.99966084, 1],
-                       easeInOutExpo: [0, 0.00195313, 0.0078125, 0.03125, 0.125, 0.5, 0.875, 0.96875, 0.9921875, 0.99804688, 1],
-                       easeInOutQuad: [0, 0.02, 0.08, 0.18, 0.32, 0.5, 0.68, 0.82, 0.92, 0.98, 1],
-                       easeInOutQuart: [0, 0.0008, 0.0128, 0.0648, 0.2048, 0.5, 0.7952, 0.9352, 0.9872, 0.9992, 1],
-                       easeInOutQuint: [0, 0.00016, 0.00512, 0.03888, 0.16384, 0.5, 0.83616, 0.96112, 0.99488, 0.99984, 1],
-                       easeInOutSine: [-0, 0.02447174, 0.0954915, 0.20610737, 0.3454915, 0.5, 0.6545085, 0.79389263, 0.9045085, 0.97552826, 1],
-                       easeInBack: [-0, -0.01431422, -0.04645056, -0.08019954, -0.09935168, -0.0876975, -0.02902752, 0.09286774, 0.29419776, 0.59117202, 1],
-                       easeInBounce: [0, 0.011875, 0.06, 0.069375, 0.2275, 0.234375, 0.09, 0.319375, 0.6975, 0.924375, 1],
-                       easeInCirc: [-0, 0.00501256, 0.0202041, 0.0460608, 0.08348486, 0.1339746, 0.2, 0.28585716, 0.4, 0.56411011, 1],
-                       easeInCubic: [0, 0.001, 0.008, 0.027, 0.064, 0.125, 0.216, 0.343, 0.512, 0.729, 1],
-                       easeInExpo: [0, 0.00195313, 0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5, 1],
-                       easeInElastic: [0, 0.00195313, -0.00195313, -0.00390625, 0.015625, -0.015625, -0.03125, 0.125, -0.125, -0.25, 1],
-                       easeInQuad: [0, 0.01, 0.04, 0.09, 0.16, 0.25, 0.36, 0.49, 0.64, 0.81, 1],
-                       easeInQuart: [0, 0.0001, 0.0016, 0.0081, 0.0256, 0.0625, 0.1296, 0.2401, 0.4096, 0.6561, 1],
-                       easeInQuint: [0, 0.00001, 0.00032, 0.00243, 0.01024, 0.03125, 0.07776, 0.16807, 0.32768, 0.59049, 1],
-                       easeInSine: [0, 0.01231166, 0.04894348, 0.10899348, 0.19098301, 0.29289322, 0.41221475, 0.5460095, 0.69098301, 0.84356553, 1],
-                       easeOutBack: [0, 0.40882798, 0.70580224, 0.90713226, 1.02902752, 1.0876975, 1.09935168, 1.08019954, 1.04645056, 1.01431422, 1],
-                       easeOutBounce: [0, 0.075625, 0.3025, 0.680625, 0.91, 0.765625, 0.7725, 0.930625, 0.94, 0.988125, 1],
-                       easeOutCirc: [0, 0.43588989, 0.6, 0.71414284, 0.8, 0.8660254, 0.91651514, 0.9539392, 0.9797959, 0.99498744, 1],
-                       easeOutElastic: [0, 1.25, 1.125, 0.875, 1.03125, 1.015625, 0.984375, 1.00390625, 1.00195313, 0.99804688, 1],
-                       easeOutExpo: [0, 0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.9921875, 0.99609375, 0.99804688, 1],
-                       easeOutCubic: [0, 0.271, 0.488, 0.657, 0.784, 0.875, 0.936, 0.973, 0.992, 0.999, 1],
-                       easeOutQuad: [0, 0.19, 0.36, 0.51, 0.64, 0.75, 0.84, 0.91, 0.96, 0.99, 1],
-                       easeOutQuart: [-0, 0.3439, 0.5904, 0.7599, 0.8704, 0.9375, 0.9744, 0.9919, 0.9984, 0.9999, 1],
-                       easeOutQuint: [0, 0.40951, 0.67232, 0.83193, 0.92224, 0.96875, 0.98976, 0.99757, 0.99968, 0.99999, 1],
-                       easeOutSine: [0, 0.15643447, 0.30901699, 0.4539905, 0.58778525, 0.70710678, 0.80901699, 0.89100652, 0.95105652, 0.98768834, 1],
-                       linear: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
-               };
+  describe('effects', function() {
+    var expected = {
+      easeInOutBack: [-0, -0.03751855, -0.09255566, -0.07883348, 0.08992579, 0.5, 0.91007421, 1.07883348, 1.09255566, 1.03751855, 1],
+      easeInOutBounce: [0, 0.03, 0.11375, 0.045, 0.34875, 0.5, 0.65125, 0.955, 0.88625, 0.97, 1],
+      easeInOutCirc: [-0, 0.01010205, 0.04174243, 0.1, 0.2, 0.5, 0.8, 0.9, 0.95825757, 0.98989795, 1],
+      easeInOutCubic: [0, 0.004, 0.032, 0.108, 0.256, 0.5, 0.744, 0.892, 0.968, 0.996, 1],
+      easeInOutElastic: [0, 0.00033916, -0.00390625, 0.02393889, -0.11746158, 0.5, 1.11746158, 0.97606111, 1.00390625, 0.99966084, 1],
+      easeInOutExpo: [0, 0.00195313, 0.0078125, 0.03125, 0.125, 0.5, 0.875, 0.96875, 0.9921875, 0.99804688, 1],
+      easeInOutQuad: [0, 0.02, 0.08, 0.18, 0.32, 0.5, 0.68, 0.82, 0.92, 0.98, 1],
+      easeInOutQuart: [0, 0.0008, 0.0128, 0.0648, 0.2048, 0.5, 0.7952, 0.9352, 0.9872, 0.9992, 1],
+      easeInOutQuint: [0, 0.00016, 0.00512, 0.03888, 0.16384, 0.5, 0.83616, 0.96112, 0.99488, 0.99984, 1],
+      easeInOutSine: [-0, 0.02447174, 0.0954915, 0.20610737, 0.3454915, 0.5, 0.6545085, 0.79389263, 0.9045085, 0.97552826, 1],
+      easeInBack: [-0, -0.01431422, -0.04645056, -0.08019954, -0.09935168, -0.0876975, -0.02902752, 0.09286774, 0.29419776, 0.59117202, 1],
+      easeInBounce: [0, 0.011875, 0.06, 0.069375, 0.2275, 0.234375, 0.09, 0.319375, 0.6975, 0.924375, 1],
+      easeInCirc: [-0, 0.00501256, 0.0202041, 0.0460608, 0.08348486, 0.1339746, 0.2, 0.28585716, 0.4, 0.56411011, 1],
+      easeInCubic: [0, 0.001, 0.008, 0.027, 0.064, 0.125, 0.216, 0.343, 0.512, 0.729, 1],
+      easeInExpo: [0, 0.00195313, 0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5, 1],
+      easeInElastic: [0, 0.00195313, -0.00195313, -0.00390625, 0.015625, -0.015625, -0.03125, 0.125, -0.125, -0.25, 1],
+      easeInQuad: [0, 0.01, 0.04, 0.09, 0.16, 0.25, 0.36, 0.49, 0.64, 0.81, 1],
+      easeInQuart: [0, 0.0001, 0.0016, 0.0081, 0.0256, 0.0625, 0.1296, 0.2401, 0.4096, 0.6561, 1],
+      easeInQuint: [0, 0.00001, 0.00032, 0.00243, 0.01024, 0.03125, 0.07776, 0.16807, 0.32768, 0.59049, 1],
+      easeInSine: [0, 0.01231166, 0.04894348, 0.10899348, 0.19098301, 0.29289322, 0.41221475, 0.5460095, 0.69098301, 0.84356553, 1],
+      easeOutBack: [0, 0.40882798, 0.70580224, 0.90713226, 1.02902752, 1.0876975, 1.09935168, 1.08019954, 1.04645056, 1.01431422, 1],
+      easeOutBounce: [0, 0.075625, 0.3025, 0.680625, 0.91, 0.765625, 0.7725, 0.930625, 0.94, 0.988125, 1],
+      easeOutCirc: [0, 0.43588989, 0.6, 0.71414284, 0.8, 0.8660254, 0.91651514, 0.9539392, 0.9797959, 0.99498744, 1],
+      easeOutElastic: [0, 1.25, 1.125, 0.875, 1.03125, 1.015625, 0.984375, 1.00390625, 1.00195313, 0.99804688, 1],
+      easeOutExpo: [0, 0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.9921875, 0.99609375, 0.99804688, 1],
+      easeOutCubic: [0, 0.271, 0.488, 0.657, 0.784, 0.875, 0.936, 0.973, 0.992, 0.999, 1],
+      easeOutQuad: [0, 0.19, 0.36, 0.51, 0.64, 0.75, 0.84, 0.91, 0.96, 0.99, 1],
+      easeOutQuart: [-0, 0.3439, 0.5904, 0.7599, 0.8704, 0.9375, 0.9744, 0.9919, 0.9984, 0.9999, 1],
+      easeOutQuint: [0, 0.40951, 0.67232, 0.83193, 0.92224, 0.96875, 0.98976, 0.99757, 0.99968, 0.99999, 1],
+      easeOutSine: [0, 0.15643447, 0.30901699, 0.4539905, 0.58778525, 0.70710678, 0.80901699, 0.89100652, 0.95105652, 0.98768834, 1],
+      linear: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
+    };
 
-               function generate(method) {
-                       var fn = helpers.easingEffects[method];
-                       var accuracy = Math.pow(10, 8);
-                       var count = 10;
-                       var values = [];
-                       var i;
+    function generate(method) {
+      var fn = helpers.easingEffects[method];
+      var accuracy = Math.pow(10, 8);
+      var count = 10;
+      var values = [];
+      var i;
 
-                       for (i = 0; i <= count; ++i) {
-                               values.push(Math.round(accuracy * fn(i / count)) / accuracy);
-                       }
+      for (i = 0; i <= count; ++i) {
+        values.push(Math.round(accuracy * fn(i / count)) / accuracy);
+      }
 
-                       return values;
-               }
+      return values;
+    }
 
-               Object.keys(helpers.easingEffects).forEach(function(method) {
-                       it ('"' + method + '" should return expected values', function() {
-                               expect(generate(method)).toEqual(expected[method]);
-                       });
-               });
-       });
+    Object.keys(helpers.easingEffects).forEach(function(method) {
+      it ('"' + method + '" should return expected values', function() {
+        expect(generate(method)).toEqual(expected[method]);
+      });
+    });
+  });
 });
index 22f8254a3f9688940564b2a2c5a43e605a72fe9c..644d93dbcfbf49f2189e9de2aa21452f0c472eac 100644 (file)
@@ -1,35 +1,35 @@
 const {_pointInLine, _steppedInterpolation, _bezierInterpolation} = Chart.helpers;
 
 describe('helpers.interpolation', function() {
-       it('Should interpolate a point in line', function() {
-               expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 0)).toEqual({x: 10, y: 10});
-               expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 0.5)).toEqual({x: 15, y: 15});
-               expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 1)).toEqual({x: 20, y: 20});
-       });
+  it('Should interpolate a point in line', function() {
+    expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 0)).toEqual({x: 10, y: 10});
+    expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 0.5)).toEqual({x: 15, y: 15});
+    expect(_pointInLine({x: 10, y: 10}, {x: 20, y: 20}, 1)).toEqual({x: 20, y: 20});
+  });
 
-       it('Should intepolate a point in stepped line', function() {
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'before')).toEqual({x: 10, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'before')).toEqual({x: 14, y: 20});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'before')).toEqual({x: 15, y: 20});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'before')).toEqual({x: 20, y: 20});
+  it('Should intepolate a point in stepped line', function() {
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'before')).toEqual({x: 10, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'before')).toEqual({x: 14, y: 20});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'before')).toEqual({x: 15, y: 20});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'before')).toEqual({x: 20, y: 20});
 
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'middle')).toEqual({x: 10, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'middle')).toEqual({x: 14, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'middle')).toEqual({x: 15, y: 20});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'middle')).toEqual({x: 20, y: 20});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'middle')).toEqual({x: 10, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'middle')).toEqual({x: 14, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'middle')).toEqual({x: 15, y: 20});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'middle')).toEqual({x: 20, y: 20});
 
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'after')).toEqual({x: 10, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'after')).toEqual({x: 14, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'after')).toEqual({x: 15, y: 10});
-               expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'after')).toEqual({x: 20, y: 20});
-       });
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0, 'after')).toEqual({x: 10, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.4, 'after')).toEqual({x: 14, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 0.5, 'after')).toEqual({x: 15, y: 10});
+    expect(_steppedInterpolation({x: 10, y: 10}, {x: 20, y: 20}, 1, 'after')).toEqual({x: 20, y: 20});
+  });
 
-       it('Should interpolate a point in curve', function() {
-               const pt1 = {x: 10, y: 10, controlPointNextX: 12, controlPointNextY: 12};
-               const pt2 = {x: 20, y: 30, controlPointPreviousX: 18, controlPointPreviousY: 28};
+  it('Should interpolate a point in curve', function() {
+    const pt1 = {x: 10, y: 10, controlPointNextX: 12, controlPointNextY: 12};
+    const pt2 = {x: 20, y: 30, controlPointPreviousX: 18, controlPointPreviousY: 28};
 
-               expect(_bezierInterpolation(pt1, pt2, 0)).toEqual({x: 10, y: 10});
-               expect(_bezierInterpolation(pt1, pt2, 0.2)).toBeCloseToPoint({x: 11.616, y: 12.656});
-               expect(_bezierInterpolation(pt1, pt2, 1)).toEqual({x: 20, y: 30});
-       });
+    expect(_bezierInterpolation(pt1, pt2, 0)).toEqual({x: 10, y: 10});
+    expect(_bezierInterpolation(pt1, pt2, 0.2)).toBeCloseToPoint({x: 11.616, y: 12.656});
+    expect(_bezierInterpolation(pt1, pt2, 1)).toEqual({x: 20, y: 30});
+  });
 });
index c71902201b1561f035b9321efaea97b5c257fa00..b6b8e125f093ae934efa1e7b28e8ef9902ccdef3 100644 (file)
 const math = Chart.helpers;
 
 describe('Chart.helpers.math', function() {
-       var factorize = math._factorize;
-       var decimalPlaces = math._decimalPlaces;
-
-       it('should factorize', function() {
-               expect(factorize(1000)).toEqual([1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500]);
-               expect(factorize(60)).toEqual([1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30]);
-               expect(factorize(30)).toEqual([1, 2, 3, 5, 6, 10, 15]);
-               expect(factorize(24)).toEqual([1, 2, 3, 4, 6, 8, 12]);
-               expect(factorize(12)).toEqual([1, 2, 3, 4, 6]);
-               expect(factorize(4)).toEqual([1, 2]);
-               expect(factorize(-1)).toEqual([]);
-               expect(factorize(2.76)).toEqual([]);
-       });
-
-       it('should do a log10 operation', function() {
-               expect(math.log10(0)).toBe(-Infinity);
-
-               // Check all allowed powers of 10, which should return integer values
-               var maxPowerOf10 = Math.floor(math.log10(Number.MAX_VALUE));
-               for (var i = 0; i < maxPowerOf10; i += 1) {
-                       expect(math.log10(Math.pow(10, i))).toBe(i);
-               }
-       });
-
-       it('should get the correct number of decimal places', function() {
-               expect(decimalPlaces(100)).toBe(0);
-               expect(decimalPlaces(1)).toBe(0);
-               expect(decimalPlaces(0)).toBe(0);
-               expect(decimalPlaces(0.01)).toBe(2);
-               expect(decimalPlaces(-0.01)).toBe(2);
-               expect(decimalPlaces('1')).toBe(undefined);
-               expect(decimalPlaces('')).toBe(undefined);
-               expect(decimalPlaces(undefined)).toBe(undefined);
-               expect(decimalPlaces(12345678.1234)).toBe(4);
-               expect(decimalPlaces(1234567890.1234567)).toBe(7);
-       });
-
-       it('should get an angle from a point', function() {
-               var center = {
-                       x: 0,
-                       y: 0
-               };
-
-               expect(math.getAngleFromPoint(center, {
-                       x: 0,
-                       y: 10
-               })).toEqual({
-                       angle: Math.PI / 2,
-                       distance: 10,
-               });
-
-               expect(math.getAngleFromPoint(center, {
-                       x: Math.sqrt(2),
-                       y: Math.sqrt(2)
-               })).toEqual({
-                       angle: Math.PI / 4,
-                       distance: 2
-               });
-
-               expect(math.getAngleFromPoint(center, {
-                       x: -1.0 * Math.sqrt(2),
-                       y: -1.0 * Math.sqrt(2)
-               })).toEqual({
-                       angle: Math.PI * 1.25,
-                       distance: 2
-               });
-       });
-
-       it('should convert between radians and degrees', function() {
-               expect(math.toRadians(180)).toBe(Math.PI);
-               expect(math.toRadians(90)).toBe(0.5 * Math.PI);
-               expect(math.toDegrees(Math.PI)).toBe(180);
-               expect(math.toDegrees(Math.PI * 3 / 2)).toBe(270);
-       });
-
-       it('should correctly determine if two numbers are essentially equal', function() {
-               expect(math.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
-               expect(math.almostEquals(1, 1.1, 0.0001)).toBe(false);
-               expect(math.almostEquals(1e30, 1e30 + Number.EPSILON, 0)).toBe(false);
-               expect(math.almostEquals(1e30, 1e30 + Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
-       });
-
-       it('should get the correct sign', function() {
-               expect(math.sign(0)).toBe(0);
-               expect(math.sign(10)).toBe(1);
-               expect(math.sign(-5)).toBe(-1);
-       });
-
-       it('should correctly determine if a numbers are essentially whole', function() {
-               expect(math.almostWhole(0.99999, 0.0001)).toBe(true);
-               expect(math.almostWhole(0.9, 0.0001)).toBe(false);
-               expect(math.almostWhole(1234567890123, 0.0001)).toBe(true);
-               expect(math.almostWhole(1234567890123.001, 0.0001)).toBe(false);
-       });
-
-       it('should detect a number', function() {
-               expect(math.isNumber(123)).toBe(true);
-               expect(math.isNumber('123')).toBe(true);
-               expect(math.isNumber(null)).toBe(false);
-               expect(math.isNumber(NaN)).toBe(false);
-               expect(math.isNumber(undefined)).toBe(false);
-               expect(math.isNumber('cbc')).toBe(false);
-       });
-
-       it('should compute shortest distance between angles', function() {
-               expect(math._angleDiff(1, 2)).toEqual(-1);
-               expect(math._angleDiff(2, 1)).toEqual(1);
-               expect(math._angleDiff(0, 3.15)).toBeCloseTo(3.13, 2);
-               expect(math._angleDiff(0, 3.13)).toEqual(-3.13);
-               expect(math._angleDiff(6.2, 0)).toBeCloseTo(-0.08, 2);
-               expect(math._angleDiff(6.3, 0)).toBeCloseTo(0.02, 2);
-               expect(math._angleDiff(4 * Math.PI, -4 * Math.PI)).toBeCloseTo(0, 4);
-               expect(math._angleDiff(4 * Math.PI, -3 * Math.PI)).toBeCloseTo(-3.14, 2);
-               expect(math._angleDiff(6.28, 3.1)).toBeCloseTo(-3.1, 2);
-               expect(math._angleDiff(6.28, 3.2)).toBeCloseTo(3.08, 2);
-       });
-
-       it('should normalize angles correctly', function() {
-               expect(math._normalizeAngle(-Math.PI)).toEqual(Math.PI);
-               expect(math._normalizeAngle(Math.PI)).toEqual(Math.PI);
-               expect(math._normalizeAngle(2)).toEqual(2);
-               expect(math._normalizeAngle(5 * Math.PI)).toEqual(Math.PI);
-               expect(math._normalizeAngle(-50 * Math.PI)).toBeCloseTo(6.28, 2);
-       });
-
-       it('should determine if angle is between boundaries', function() {
-               expect(math._angleBetween(2, 1, 3)).toBeTrue();
-               expect(math._angleBetween(2, 3, 1)).toBeFalse();
-               expect(math._angleBetween(-3.14, 2, 4)).toBeTrue();
-               expect(math._angleBetween(-3.14, 4, 2)).toBeFalse();
-               expect(math._angleBetween(0, -1, 1)).toBeTrue();
-               expect(math._angleBetween(-1, 0, 1)).toBeFalse();
-               expect(math._angleBetween(-15 * Math.PI, 3.1, 3.2)).toBeTrue();
-               expect(math._angleBetween(15 * Math.PI, -3.2, -3.1)).toBeTrue();
-       });
+  var factorize = math._factorize;
+  var decimalPlaces = math._decimalPlaces;
+
+  it('should factorize', function() {
+    expect(factorize(1000)).toEqual([1, 2, 4, 5, 8, 10, 20, 25, 40, 50, 100, 125, 200, 250, 500]);
+    expect(factorize(60)).toEqual([1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30]);
+    expect(factorize(30)).toEqual([1, 2, 3, 5, 6, 10, 15]);
+    expect(factorize(24)).toEqual([1, 2, 3, 4, 6, 8, 12]);
+    expect(factorize(12)).toEqual([1, 2, 3, 4, 6]);
+    expect(factorize(4)).toEqual([1, 2]);
+    expect(factorize(-1)).toEqual([]);
+    expect(factorize(2.76)).toEqual([]);
+  });
+
+  it('should do a log10 operation', function() {
+    expect(math.log10(0)).toBe(-Infinity);
+
+    // Check all allowed powers of 10, which should return integer values
+    var maxPowerOf10 = Math.floor(math.log10(Number.MAX_VALUE));
+    for (var i = 0; i < maxPowerOf10; i += 1) {
+      expect(math.log10(Math.pow(10, i))).toBe(i);
+    }
+  });
+
+  it('should get the correct number of decimal places', function() {
+    expect(decimalPlaces(100)).toBe(0);
+    expect(decimalPlaces(1)).toBe(0);
+    expect(decimalPlaces(0)).toBe(0);
+    expect(decimalPlaces(0.01)).toBe(2);
+    expect(decimalPlaces(-0.01)).toBe(2);
+    expect(decimalPlaces('1')).toBe(undefined);
+    expect(decimalPlaces('')).toBe(undefined);
+    expect(decimalPlaces(undefined)).toBe(undefined);
+    expect(decimalPlaces(12345678.1234)).toBe(4);
+    expect(decimalPlaces(1234567890.1234567)).toBe(7);
+  });
+
+  it('should get an angle from a point', function() {
+    var center = {
+      x: 0,
+      y: 0
+    };
+
+    expect(math.getAngleFromPoint(center, {
+      x: 0,
+      y: 10
+    })).toEqual({
+      angle: Math.PI / 2,
+      distance: 10,
+    });
+
+    expect(math.getAngleFromPoint(center, {
+      x: Math.sqrt(2),
+      y: Math.sqrt(2)
+    })).toEqual({
+      angle: Math.PI / 4,
+      distance: 2
+    });
+
+    expect(math.getAngleFromPoint(center, {
+      x: -1.0 * Math.sqrt(2),
+      y: -1.0 * Math.sqrt(2)
+    })).toEqual({
+      angle: Math.PI * 1.25,
+      distance: 2
+    });
+  });
+
+  it('should convert between radians and degrees', function() {
+    expect(math.toRadians(180)).toBe(Math.PI);
+    expect(math.toRadians(90)).toBe(0.5 * Math.PI);
+    expect(math.toDegrees(Math.PI)).toBe(180);
+    expect(math.toDegrees(Math.PI * 3 / 2)).toBe(270);
+  });
+
+  it('should correctly determine if two numbers are essentially equal', function() {
+    expect(math.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
+    expect(math.almostEquals(1, 1.1, 0.0001)).toBe(false);
+    expect(math.almostEquals(1e30, 1e30 + Number.EPSILON, 0)).toBe(false);
+    expect(math.almostEquals(1e30, 1e30 + Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
+  });
+
+  it('should get the correct sign', function() {
+    expect(math.sign(0)).toBe(0);
+    expect(math.sign(10)).toBe(1);
+    expect(math.sign(-5)).toBe(-1);
+  });
+
+  it('should correctly determine if a numbers are essentially whole', function() {
+    expect(math.almostWhole(0.99999, 0.0001)).toBe(true);
+    expect(math.almostWhole(0.9, 0.0001)).toBe(false);
+    expect(math.almostWhole(1234567890123, 0.0001)).toBe(true);
+    expect(math.almostWhole(1234567890123.001, 0.0001)).toBe(false);
+  });
+
+  it('should detect a number', function() {
+    expect(math.isNumber(123)).toBe(true);
+    expect(math.isNumber('123')).toBe(true);
+    expect(math.isNumber(null)).toBe(false);
+    expect(math.isNumber(NaN)).toBe(false);
+    expect(math.isNumber(undefined)).toBe(false);
+    expect(math.isNumber('cbc')).toBe(false);
+  });
+
+  it('should compute shortest distance between angles', function() {
+    expect(math._angleDiff(1, 2)).toEqual(-1);
+    expect(math._angleDiff(2, 1)).toEqual(1);
+    expect(math._angleDiff(0, 3.15)).toBeCloseTo(3.13, 2);
+    expect(math._angleDiff(0, 3.13)).toEqual(-3.13);
+    expect(math._angleDiff(6.2, 0)).toBeCloseTo(-0.08, 2);
+    expect(math._angleDiff(6.3, 0)).toBeCloseTo(0.02, 2);
+    expect(math._angleDiff(4 * Math.PI, -4 * Math.PI)).toBeCloseTo(0, 4);
+    expect(math._angleDiff(4 * Math.PI, -3 * Math.PI)).toBeCloseTo(-3.14, 2);
+    expect(math._angleDiff(6.28, 3.1)).toBeCloseTo(-3.1, 2);
+    expect(math._angleDiff(6.28, 3.2)).toBeCloseTo(3.08, 2);
+  });
+
+  it('should normalize angles correctly', function() {
+    expect(math._normalizeAngle(-Math.PI)).toEqual(Math.PI);
+    expect(math._normalizeAngle(Math.PI)).toEqual(Math.PI);
+    expect(math._normalizeAngle(2)).toEqual(2);
+    expect(math._normalizeAngle(5 * Math.PI)).toEqual(Math.PI);
+    expect(math._normalizeAngle(-50 * Math.PI)).toBeCloseTo(6.28, 2);
+  });
+
+  it('should determine if angle is between boundaries', function() {
+    expect(math._angleBetween(2, 1, 3)).toBeTrue();
+    expect(math._angleBetween(2, 3, 1)).toBeFalse();
+    expect(math._angleBetween(-3.14, 2, 4)).toBeTrue();
+    expect(math._angleBetween(-3.14, 4, 2)).toBeFalse();
+    expect(math._angleBetween(0, -1, 1)).toBeTrue();
+    expect(math._angleBetween(-1, 0, 1)).toBeFalse();
+    expect(math._angleBetween(-15 * Math.PI, 3.1, 3.2)).toBeTrue();
+    expect(math._angleBetween(15 * Math.PI, -3.2, -3.1)).toBeTrue();
+  });
 });
index 31beec8fe8ebc44119b0da1ca4c5a68fe5edb926..8bbacba9a0a0d490e082194ed513ffab3a8796af 100644 (file)
 const {toLineHeight, toPadding, toFont, resolve, toTRBLCorners} = Chart.helpers;
 
 describe('Chart.helpers.options', function() {
-       describe('toLineHeight', function() {
-               it ('should support keyword values', function() {
-                       expect(toLineHeight('normal', 16)).toBe(16 * 1.2);
-               });
-               it ('should support unitless values', function() {
-                       expect(toLineHeight(1.4, 16)).toBe(16 * 1.4);
-                       expect(toLineHeight('1.4', 16)).toBe(16 * 1.4);
-               });
-               it ('should support length values', function() {
-                       expect(toLineHeight('42px', 16)).toBe(42);
-                       expect(toLineHeight('1.4em', 16)).toBe(16 * 1.4);
-               });
-               it ('should support percentage values', function() {
-                       expect(toLineHeight('140%', 16)).toBe(16 * 1.4);
-               });
-               it ('should fallback to default (1.2) for invalid values', function() {
-                       expect(toLineHeight(null, 16)).toBe(16 * 1.2);
-                       expect(toLineHeight(undefined, 16)).toBe(16 * 1.2);
-                       expect(toLineHeight('foobar', 16)).toBe(16 * 1.2);
-               });
-       });
+  describe('toLineHeight', function() {
+    it ('should support keyword values', function() {
+      expect(toLineHeight('normal', 16)).toBe(16 * 1.2);
+    });
+    it ('should support unitless values', function() {
+      expect(toLineHeight(1.4, 16)).toBe(16 * 1.4);
+      expect(toLineHeight('1.4', 16)).toBe(16 * 1.4);
+    });
+    it ('should support length values', function() {
+      expect(toLineHeight('42px', 16)).toBe(42);
+      expect(toLineHeight('1.4em', 16)).toBe(16 * 1.4);
+    });
+    it ('should support percentage values', function() {
+      expect(toLineHeight('140%', 16)).toBe(16 * 1.4);
+    });
+    it ('should fallback to default (1.2) for invalid values', function() {
+      expect(toLineHeight(null, 16)).toBe(16 * 1.2);
+      expect(toLineHeight(undefined, 16)).toBe(16 * 1.2);
+      expect(toLineHeight('foobar', 16)).toBe(16 * 1.2);
+    });
+  });
 
-       describe('toTRBLCorners', function() {
-               it('should support number values', function() {
-                       expect(toTRBLCorners(4)).toEqual(
-                               {topLeft: 4, topRight: 4, bottomLeft: 4, bottomRight: 4});
-                       expect(toTRBLCorners(4.5)).toEqual(
-                               {topLeft: 4.5, topRight: 4.5, bottomLeft: 4.5, bottomRight: 4.5});
-               });
-               it('should support string values', function() {
-                       expect(toTRBLCorners('4')).toEqual(
-                               {topLeft: 4, topRight: 4, bottomLeft: 4, bottomRight: 4});
-                       expect(toTRBLCorners('4.5')).toEqual(
-                               {topLeft: 4.5, topRight: 4.5, bottomLeft: 4.5, bottomRight: 4.5});
-               });
-               it('should support object values', function() {
-                       expect(toTRBLCorners({topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4})).toEqual(
-                               {topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4});
-                       expect(toTRBLCorners({topLeft: 1.5, topRight: 2.5, bottomLeft: 3.5, bottomRight: 4.5})).toEqual(
-                               {topLeft: 1.5, topRight: 2.5, bottomLeft: 3.5, bottomRight: 4.5});
-                       expect(toTRBLCorners({topLeft: '1', topRight: '2', bottomLeft: '3', bottomRight: '4'})).toEqual(
-                               {topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4});
-               });
-               it('should fallback to 0 for invalid values', function() {
-                       expect(toTRBLCorners({topLeft: 'foo', topRight: 'foo', bottomLeft: 'foo', bottomRight: 'foo'})).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-                       expect(toTRBLCorners({topLeft: null, topRight: null, bottomLeft: null, bottomRight: null})).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-                       expect(toTRBLCorners({})).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-                       expect(toTRBLCorners('foo')).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-                       expect(toTRBLCorners(null)).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-                       expect(toTRBLCorners(undefined)).toEqual(
-                               {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
-               });
-       });
+  describe('toTRBLCorners', function() {
+    it('should support number values', function() {
+      expect(toTRBLCorners(4)).toEqual(
+        {topLeft: 4, topRight: 4, bottomLeft: 4, bottomRight: 4});
+      expect(toTRBLCorners(4.5)).toEqual(
+        {topLeft: 4.5, topRight: 4.5, bottomLeft: 4.5, bottomRight: 4.5});
+    });
+    it('should support string values', function() {
+      expect(toTRBLCorners('4')).toEqual(
+        {topLeft: 4, topRight: 4, bottomLeft: 4, bottomRight: 4});
+      expect(toTRBLCorners('4.5')).toEqual(
+        {topLeft: 4.5, topRight: 4.5, bottomLeft: 4.5, bottomRight: 4.5});
+    });
+    it('should support object values', function() {
+      expect(toTRBLCorners({topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4})).toEqual(
+        {topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4});
+      expect(toTRBLCorners({topLeft: 1.5, topRight: 2.5, bottomLeft: 3.5, bottomRight: 4.5})).toEqual(
+        {topLeft: 1.5, topRight: 2.5, bottomLeft: 3.5, bottomRight: 4.5});
+      expect(toTRBLCorners({topLeft: '1', topRight: '2', bottomLeft: '3', bottomRight: '4'})).toEqual(
+        {topLeft: 1, topRight: 2, bottomLeft: 3, bottomRight: 4});
+    });
+    it('should fallback to 0 for invalid values', function() {
+      expect(toTRBLCorners({topLeft: 'foo', topRight: 'foo', bottomLeft: 'foo', bottomRight: 'foo'})).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+      expect(toTRBLCorners({topLeft: null, topRight: null, bottomLeft: null, bottomRight: null})).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+      expect(toTRBLCorners({})).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+      expect(toTRBLCorners('foo')).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+      expect(toTRBLCorners(null)).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+      expect(toTRBLCorners(undefined)).toEqual(
+        {topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0});
+    });
+  });
 
-       describe('toPadding', function() {
-               it ('should support number values', function() {
-                       expect(toPadding(4)).toEqual(
-                               {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
-                       expect(toPadding(4.5)).toEqual(
-                               {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
-               });
-               it ('should support string values', function() {
-                       expect(toPadding('4')).toEqual(
-                               {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
-                       expect(toPadding('4.5')).toEqual(
-                               {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
-               });
-               it ('should support object values', function() {
-                       expect(toPadding({top: 1, right: 2, bottom: 3, left: 4})).toEqual(
-                               {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
-                       expect(toPadding({top: 1.5, right: 2.5, bottom: 3.5, left: 4.5})).toEqual(
-                               {top: 1.5, right: 2.5, bottom: 3.5, left: 4.5, height: 5, width: 7});
-                       expect(toPadding({top: '1', right: '2', bottom: '3', left: '4'})).toEqual(
-                               {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
-               });
-               it ('should fallback to 0 for invalid values', function() {
-                       expect(toPadding({top: 'foo', right: 'foo', bottom: 'foo', left: 'foo'})).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(toPadding({top: null, right: null, bottom: null, left: null})).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(toPadding({})).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(toPadding('foo')).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(toPadding(null)).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-                       expect(toPadding(undefined)).toEqual(
-                               {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
-               });
-       });
+  describe('toPadding', function() {
+    it ('should support number values', function() {
+      expect(toPadding(4)).toEqual(
+        {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
+      expect(toPadding(4.5)).toEqual(
+        {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
+    });
+    it ('should support string values', function() {
+      expect(toPadding('4')).toEqual(
+        {top: 4, right: 4, bottom: 4, left: 4, height: 8, width: 8});
+      expect(toPadding('4.5')).toEqual(
+        {top: 4.5, right: 4.5, bottom: 4.5, left: 4.5, height: 9, width: 9});
+    });
+    it ('should support object values', function() {
+      expect(toPadding({top: 1, right: 2, bottom: 3, left: 4})).toEqual(
+        {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
+      expect(toPadding({top: 1.5, right: 2.5, bottom: 3.5, left: 4.5})).toEqual(
+        {top: 1.5, right: 2.5, bottom: 3.5, left: 4.5, height: 5, width: 7});
+      expect(toPadding({top: '1', right: '2', bottom: '3', left: '4'})).toEqual(
+        {top: 1, right: 2, bottom: 3, left: 4, height: 4, width: 6});
+    });
+    it ('should fallback to 0 for invalid values', function() {
+      expect(toPadding({top: 'foo', right: 'foo', bottom: 'foo', left: 'foo'})).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+      expect(toPadding({top: null, right: null, bottom: null, left: null})).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+      expect(toPadding({})).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+      expect(toPadding('foo')).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+      expect(toPadding(null)).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+      expect(toPadding(undefined)).toEqual(
+        {top: 0, right: 0, bottom: 0, left: 0, height: 0, width: 0});
+    });
+  });
 
-       describe('toFont', function() {
-               it('should return a font with default values', function() {
-                       const defaultFont = Object.assign({}, Chart.defaults.font);
+  describe('toFont', function() {
+    it('should return a font with default values', function() {
+      const defaultFont = Object.assign({}, Chart.defaults.font);
 
-                       Object.assign(Chart.defaults.font, {
-                               family: 'foobar',
-                               size: 42,
-                               style: 'xxxyyy',
-                               lineHeight: 1.5
-                       });
+      Object.assign(Chart.defaults.font, {
+        family: 'foobar',
+        size: 42,
+        style: 'xxxyyy',
+        lineHeight: 1.5
+      });
 
-                       expect(toFont({})).toEqual({
-                               family: 'foobar',
-                               lineHeight: 63,
-                               size: 42,
-                               string: 'xxxyyy 42px foobar',
-                               style: 'xxxyyy',
-                               weight: null
-                       });
+      expect(toFont({})).toEqual({
+        family: 'foobar',
+        lineHeight: 63,
+        size: 42,
+        string: 'xxxyyy 42px foobar',
+        style: 'xxxyyy',
+        weight: null
+      });
 
-                       Object.assign(Chart.defaults.font, defaultFont);
-               });
-               it ('should return a font with given values', function() {
-                       expect(toFont({
-                               family: 'bla',
-                               lineHeight: 8,
-                               size: 21,
-                               style: 'zzz'
-                       })).toEqual({
-                               family: 'bla',
-                               lineHeight: 8 * 21,
-                               size: 21,
-                               string: 'zzz 21px bla',
-                               style: 'zzz',
-                               weight: null
-                       });
-               });
-               it ('should handle a string font size', function() {
-                       expect(toFont({
-                               family: 'bla',
-                               lineHeight: 8,
-                               size: '21',
-                               style: 'zzz'
-                       })).toEqual({
-                               family: 'bla',
-                               lineHeight: 8 * 21,
-                               size: 21,
-                               string: 'zzz 21px bla',
-                               style: 'zzz',
-                               weight: null
-                       });
-               });
-               it('should return null as a font string if size or family are missing', function() {
-                       const fontFamily = Chart.defaults.font.family;
-                       const fontSize = Chart.defaults.font.size;
-                       delete Chart.defaults.font.family;
-                       delete Chart.defaults.font.size;
+      Object.assign(Chart.defaults.font, defaultFont);
+    });
+    it ('should return a font with given values', function() {
+      expect(toFont({
+        family: 'bla',
+        lineHeight: 8,
+        size: 21,
+        style: 'zzz'
+      })).toEqual({
+        family: 'bla',
+        lineHeight: 8 * 21,
+        size: 21,
+        string: 'zzz 21px bla',
+        style: 'zzz',
+        weight: null
+      });
+    });
+    it ('should handle a string font size', function() {
+      expect(toFont({
+        family: 'bla',
+        lineHeight: 8,
+        size: '21',
+        style: 'zzz'
+      })).toEqual({
+        family: 'bla',
+        lineHeight: 8 * 21,
+        size: 21,
+        string: 'zzz 21px bla',
+        style: 'zzz',
+        weight: null
+      });
+    });
+    it('should return null as a font string if size or family are missing', function() {
+      const fontFamily = Chart.defaults.font.family;
+      const fontSize = Chart.defaults.font.size;
+      delete Chart.defaults.font.family;
+      delete Chart.defaults.font.size;
 
-                       expect(toFont({
-                               style: 'italic',
-                               size: 12
-                       }).string).toBeNull();
-                       expect(toFont({
-                               style: 'italic',
-                               family: 'serif'
-                       }).string).toBeNull();
+      expect(toFont({
+        style: 'italic',
+        size: 12
+      }).string).toBeNull();
+      expect(toFont({
+        style: 'italic',
+        family: 'serif'
+      }).string).toBeNull();
 
-                       Chart.defaults.font.family = fontFamily;
-                       Chart.defaults.font.size = fontSize;
-               });
-               it('font.style should be optional for font strings', function() {
-                       const fontStyle = Chart.defaults.font.style;
-                       delete Chart.defaults.font.style;
+      Chart.defaults.font.family = fontFamily;
+      Chart.defaults.font.size = fontSize;
+    });
+    it('font.style should be optional for font strings', function() {
+      const fontStyle = Chart.defaults.font.style;
+      delete Chart.defaults.font.style;
 
-                       expect(toFont({
-                               size: 12,
-                               family: 'serif'
-                       }).string).toBe('12px serif');
+      expect(toFont({
+        size: 12,
+        family: 'serif'
+      }).string).toBe('12px serif');
 
-                       Chart.defaults.font.style = fontStyle;
-               });
-       });
+      Chart.defaults.font.style = fontStyle;
+    });
+  });
 
-       describe('resolve', function() {
-               it ('should fallback to the first defined input', function() {
-                       expect(resolve([42])).toBe(42);
-                       expect(resolve([42, 'foo'])).toBe(42);
-                       expect(resolve([undefined, 42, 'foo'])).toBe(42);
-                       expect(resolve([42, 'foo', undefined])).toBe(42);
-                       expect(resolve([undefined])).toBe(undefined);
-               });
-               it ('should correctly handle empty values (null, 0, "")', function() {
-                       expect(resolve([0, 'foo'])).toBe(0);
-                       expect(resolve(['', 'foo'])).toBe('');
-                       expect(resolve([null, 'foo'])).toBe(null);
-               });
-               it ('should support indexable options if index is provided', function() {
-                       var input = [42, 'foo', 'bar'];
-                       expect(resolve([input], undefined, 0)).toBe(42);
-                       expect(resolve([input], undefined, 1)).toBe('foo');
-                       expect(resolve([input], undefined, 2)).toBe('bar');
-               });
-               it ('should fallback if an indexable option value is undefined', function() {
-                       var input = [42, undefined, 'bar'];
-                       expect(resolve([input], undefined, 1)).toBe(undefined);
-                       expect(resolve([input, 'foo'], undefined, 1)).toBe('foo');
-               });
-               it ('should loop if an indexable option index is out of bounds', function() {
-                       var input = [42, undefined, 'bar'];
-                       expect(resolve([input], undefined, 3)).toBe(42);
-                       expect(resolve([input, 'foo'], undefined, 4)).toBe('foo');
-                       expect(resolve([input, 'foo'], undefined, 5)).toBe('bar');
-               });
-               it ('should not handle indexable options if index is undefined', function() {
-                       var array = [42, 'foo', 'bar'];
-                       expect(resolve([array])).toBe(array);
-                       expect(resolve([array], undefined, undefined)).toBe(array);
-               });
-               it ('should support scriptable options if context is provided', function() {
-                       var input = function(context) {
-                               return context.v * 2;
-                       };
-                       expect(resolve([42], {v: 42})).toBe(42);
-                       expect(resolve([input], {v: 42})).toBe(84);
-               });
-               it ('should fallback if a scriptable option returns undefined', function() {
-                       var input = function() {};
-                       expect(resolve([input], {v: 42})).toBe(undefined);
-                       expect(resolve([input, 'foo'], {v: 42})).toBe('foo');
-                       expect(resolve([input, undefined, 'foo'], {v: 42})).toBe('foo');
-               });
-               it ('should not handle scriptable options if context is undefined', function() {
-                       var input = function(context) {
-                               return context.v * 2;
-                       };
-                       expect(resolve([input])).toBe(input);
-                       expect(resolve([input], undefined)).toBe(input);
-               });
-               it ('should handle scriptable and indexable option', function() {
-                       var input = function(context) {
-                               return [context.v, undefined, 'bar'];
-                       };
-                       expect(resolve([input, 'foo'], {v: 42}, 0)).toBe(42);
-                       expect(resolve([input, 'foo'], {v: 42}, 1)).toBe('foo');
-                       expect(resolve([input, 'foo'], {v: 42}, 5)).toBe('bar');
-                       expect(resolve([input, ['foo', 'bar']], {v: 42}, 1)).toBe('bar');
-               });
-       });
+  describe('resolve', function() {
+    it ('should fallback to the first defined input', function() {
+      expect(resolve([42])).toBe(42);
+      expect(resolve([42, 'foo'])).toBe(42);
+      expect(resolve([undefined, 42, 'foo'])).toBe(42);
+      expect(resolve([42, 'foo', undefined])).toBe(42);
+      expect(resolve([undefined])).toBe(undefined);
+    });
+    it ('should correctly handle empty values (null, 0, "")', function() {
+      expect(resolve([0, 'foo'])).toBe(0);
+      expect(resolve(['', 'foo'])).toBe('');
+      expect(resolve([null, 'foo'])).toBe(null);
+    });
+    it ('should support indexable options if index is provided', function() {
+      var input = [42, 'foo', 'bar'];
+      expect(resolve([input], undefined, 0)).toBe(42);
+      expect(resolve([input], undefined, 1)).toBe('foo');
+      expect(resolve([input], undefined, 2)).toBe('bar');
+    });
+    it ('should fallback if an indexable option value is undefined', function() {
+      var input = [42, undefined, 'bar'];
+      expect(resolve([input], undefined, 1)).toBe(undefined);
+      expect(resolve([input, 'foo'], undefined, 1)).toBe('foo');
+    });
+    it ('should loop if an indexable option index is out of bounds', function() {
+      var input = [42, undefined, 'bar'];
+      expect(resolve([input], undefined, 3)).toBe(42);
+      expect(resolve([input, 'foo'], undefined, 4)).toBe('foo');
+      expect(resolve([input, 'foo'], undefined, 5)).toBe('bar');
+    });
+    it ('should not handle indexable options if index is undefined', function() {
+      var array = [42, 'foo', 'bar'];
+      expect(resolve([array])).toBe(array);
+      expect(resolve([array], undefined, undefined)).toBe(array);
+    });
+    it ('should support scriptable options if context is provided', function() {
+      var input = function(context) {
+        return context.v * 2;
+      };
+      expect(resolve([42], {v: 42})).toBe(42);
+      expect(resolve([input], {v: 42})).toBe(84);
+    });
+    it ('should fallback if a scriptable option returns undefined', function() {
+      var input = function() {};
+      expect(resolve([input], {v: 42})).toBe(undefined);
+      expect(resolve([input, 'foo'], {v: 42})).toBe('foo');
+      expect(resolve([input, undefined, 'foo'], {v: 42})).toBe('foo');
+    });
+    it ('should not handle scriptable options if context is undefined', function() {
+      var input = function(context) {
+        return context.v * 2;
+      };
+      expect(resolve([input])).toBe(input);
+      expect(resolve([input], undefined)).toBe(input);
+    });
+    it ('should handle scriptable and indexable option', function() {
+      var input = function(context) {
+        return [context.v, undefined, 'bar'];
+      };
+      expect(resolve([input, 'foo'], {v: 42}, 0)).toBe(42);
+      expect(resolve([input, 'foo'], {v: 42}, 1)).toBe('foo');
+      expect(resolve([input, 'foo'], {v: 42}, 5)).toBe('bar');
+      expect(resolve([input, ['foo', 'bar']], {v: 42}, 1)).toBe('bar');
+    });
+  });
 });
index d1578733a7f02bbd46478cf051be2c8fbaa18c31..c0ac630260324072037a4e14ada288cff1293ec6 100644 (file)
@@ -1,44 +1,44 @@
 const {_boundSegment} = Chart.helpers;
 
 describe('helpers.segments', function() {
-       describe('_boundSegment', function() {
-               const points = [{x: 10, y: 1}, {x: 20, y: 2}, {x: 30, y: 3}];
-               const segment = {start: 0, end: 2, loop: false};
-
-               it('should not find segment from before the line', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 5, end: 9.99999})).toEqual([]);
-               });
-
-               it('should not find segment from after the line', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 30.00001, end: 800})).toEqual([]);
-               });
-
-               it('should find segment when starting before line', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 5, end: 15})).toEqual([{start: 0, end: 1, loop: false}]);
-               });
-
-               it('should find segment directly on point', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 10, end: 10})).toEqual([{start: 0, end: 0, loop: false}]);
-               });
-
-               it('should find segment from range between points', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 11, end: 14})).toEqual([{start: 0, end: 1, loop: false}]);
-               });
-
-               it('should find segment from point between points', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 22, end: 22})).toEqual([{start: 1, end: 2, loop: false}]);
-               });
-
-               it('should find whole segment', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 0, end: 50})).toEqual([{start: 0, end: 2, loop: false}]);
-               });
-
-               it('should find correct segment from near points', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 10.001, end: 29.999})).toEqual([{start: 0, end: 2, loop: false}]);
-               });
-
-               it('should find segment from after the line', function() {
-                       expect(_boundSegment(segment, points, {property: 'x', start: 25, end: 35})).toEqual([{start: 1, end: 2, loop: false}]);
-               });
-       });
+  describe('_boundSegment', function() {
+    const points = [{x: 10, y: 1}, {x: 20, y: 2}, {x: 30, y: 3}];
+    const segment = {start: 0, end: 2, loop: false};
+
+    it('should not find segment from before the line', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 5, end: 9.99999})).toEqual([]);
+    });
+
+    it('should not find segment from after the line', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 30.00001, end: 800})).toEqual([]);
+    });
+
+    it('should find segment when starting before line', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 5, end: 15})).toEqual([{start: 0, end: 1, loop: false}]);
+    });
+
+    it('should find segment directly on point', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 10, end: 10})).toEqual([{start: 0, end: 0, loop: false}]);
+    });
+
+    it('should find segment from range between points', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 11, end: 14})).toEqual([{start: 0, end: 1, loop: false}]);
+    });
+
+    it('should find segment from point between points', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 22, end: 22})).toEqual([{start: 1, end: 2, loop: false}]);
+    });
+
+    it('should find whole segment', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 0, end: 50})).toEqual([{start: 0, end: 2, loop: false}]);
+    });
+
+    it('should find correct segment from near points', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 10.001, end: 29.999})).toEqual([{start: 0, end: 2, loop: false}]);
+    });
+
+    it('should find segment from after the line', function() {
+      expect(_boundSegment(segment, points, {property: 'x', start: 25, end: 35})).toEqual([{start: 1, end: 2, loop: false}]);
+    });
+  });
 });
index 236fe95c1f5299a60d5f944ac71915224395af14..0d501e558288a248f26eeb36c1f41882c40e0faa 100644 (file)
@@ -1,3 +1,3 @@
 describe('Mixed charts', function() {
-       describe('auto', jasmine.fixture.specs('mixed'));
+  describe('auto', jasmine.fixture.specs('mixed'));
 });
index 90a6541b5d80c7b972e32a483e1f048ce9a16122..1ee7278b96bd1771b0b8199406ad79894938d17b 100644 (file)
@@ -1,91 +1,91 @@
 describe('Platform.basic', function() {
 
-       it('should automatically choose the BasicPlatform for offscreen canvas', function() {
-               const chart = acquireChart({type: 'line'}, {useOffscreenCanvas: true});
+  it('should automatically choose the BasicPlatform for offscreen canvas', function() {
+    const chart = acquireChart({type: 'line'}, {useOffscreenCanvas: true});
 
-               expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
+    expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
 
-               chart.destroy();
-       });
+    chart.destroy();
+  });
 
-       it('supports choosing the BasicPlatform in a web worker', function(done) {
-               const canvas = document.createElement('canvas');
-               if (!canvas.transferControlToOffscreen) {
-                       pending();
-               }
-               const offscreenCanvas = canvas.transferControlToOffscreen();
+  it('supports choosing the BasicPlatform in a web worker', function(done) {
+    const canvas = document.createElement('canvas');
+    if (!canvas.transferControlToOffscreen) {
+      pending();
+    }
+    const offscreenCanvas = canvas.transferControlToOffscreen();
 
-               const worker = new Worker('base/test/BasicChartWebWorker.js');
-               worker.onmessage = (event) => {
-                       worker.terminate();
-                       const {type, errorMessage} = event.data;
-                       if (type === 'error') {
-                               done.fail(errorMessage);
-                       } else if (type === 'success') {
-                               expect(type).toEqual('success');
-                               done();
-                       } else {
-                               done.fail('invalid message type sent by worker: ' + type);
-                       }
-               };
+    const worker = new Worker('base/test/BasicChartWebWorker.js');
+    worker.onmessage = (event) => {
+      worker.terminate();
+      const {type, errorMessage} = event.data;
+      if (type === 'error') {
+        done.fail(errorMessage);
+      } else if (type === 'success') {
+        expect(type).toEqual('success');
+        done();
+      } else {
+        done.fail('invalid message type sent by worker: ' + type);
+      }
+    };
 
-               worker.postMessage({type: 'initialize', canvas: offscreenCanvas}, [offscreenCanvas]);
-       });
+    worker.postMessage({type: 'initialize', canvas: offscreenCanvas}, [offscreenCanvas]);
+  });
 
-       describe('with offscreenCanvas', function() {
-               it('supports laying out a simple chart', function() {
-                       const chart = acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {data: [10, 5, 0, 25, 78, -10]}
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               },
-                               useOffscreenCanvas: true,
-                       });
+  describe('with offscreenCanvas', function() {
+    it('supports laying out a simple chart', function() {
+      const chart = acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {data: [10, 5, 0, 25, 78, -10]}
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        },
+        useOffscreenCanvas: true,
+      });
 
-                       expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
+      expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
 
-                       expect(chart.chartArea.bottom).toBeCloseToPixel(120);
-                       expect(chart.chartArea.left).toBeCloseToPixel(34);
-                       expect(chart.chartArea.right).toBeCloseToPixel(247);
-                       expect(chart.chartArea.top).toBeCloseToPixel(32);
-               });
+      expect(chart.chartArea.bottom).toBeCloseToPixel(120);
+      expect(chart.chartArea.left).toBeCloseToPixel(34);
+      expect(chart.chartArea.right).toBeCloseToPixel(247);
+      expect(chart.chartArea.top).toBeCloseToPixel(32);
+    });
 
-               it('supports resizing a chart', function() {
-                       const chart = acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [
-                                               {data: [10, 5, 0, 25, 78, -10]}
-                                       ],
-                                       labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
-                               }
-                       }, {
-                               canvas: {
-                                       height: 150,
-                                       width: 250
-                               },
-                               useOffscreenCanvas: true,
-                       });
+    it('supports resizing a chart', function() {
+      const chart = acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [
+            {data: [10, 5, 0, 25, 78, -10]}
+          ],
+          labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5', 'tick6']
+        }
+      }, {
+        canvas: {
+          height: 150,
+          width: 250
+        },
+        useOffscreenCanvas: true,
+      });
 
-                       expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
+      expect(chart.platform).toBeInstanceOf(Chart.platforms.BasicPlatform);
 
-                       const canvasElement = chart.canvas;
-                       canvasElement.height = 200;
-                       canvasElement.width = 300;
-                       chart.resize();
+      const canvasElement = chart.canvas;
+      canvasElement.height = 200;
+      canvasElement.width = 300;
+      chart.resize();
 
-                       expect(chart.chartArea.bottom).toBeCloseToPixel(150);
-                       expect(chart.chartArea.left).toBeCloseToPixel(34);
-                       expect(chart.chartArea.right).toBeCloseToPixel(297);
-                       expect(chart.chartArea.top).toBeCloseToPixel(32);
-               });
-       });
+      expect(chart.chartArea.bottom).toBeCloseToPixel(150);
+      expect(chart.chartArea.left).toBeCloseToPixel(34);
+      expect(chart.chartArea.right).toBeCloseToPixel(297);
+      expect(chart.chartArea.top).toBeCloseToPixel(32);
+    });
+  });
 });
index e32100249c0a3b07ebbbcf8a5953ebf0ec69290b..fe65095236dcf89fdd133a3c1acaa7d7ad47cd45 100644 (file)
@@ -2,429 +2,429 @@ const DomPlatform = Chart.platforms.DomPlatform;
 
 describe('Platform.dom', function() {
 
-       describe('context acquisition', function() {
-               var canvasId = 'chartjs-canvas';
+  describe('context acquisition', function() {
+    var canvasId = 'chartjs-canvas';
 
-               beforeEach(function() {
-                       var canvas = document.createElement('canvas');
-                       canvas.setAttribute('id', canvasId);
-                       window.document.body.appendChild(canvas);
-               });
-
-               afterEach(function() {
-                       document.getElementById(canvasId).remove();
-               });
-
-               it('should use the DomPlatform by default', function() {
-                       var chart = acquireChart({type: 'line'});
-
-                       expect(chart.platform).toBeInstanceOf(Chart.platforms.DomPlatform);
-
-                       chart.destroy();
-               });
-
-               // see https://github.com/chartjs/Chart.js/issues/2807
-               it('should gracefully handle invalid item', function() {
-                       var chart = new Chart('foobar');
-
-                       expect(chart).not.toBeValidChart();
-
-                       chart.destroy();
-               });
-
-               it('should accept a DOM element id', function() {
-                       var canvas = document.getElementById(canvasId);
-                       var chart = new Chart(canvasId);
-
-                       expect(chart).toBeValidChart();
-                       expect(chart.canvas).toBe(canvas);
-                       expect(chart.ctx).toBe(canvas.getContext('2d'));
-
-                       chart.destroy();
-               });
-
-               it('should accept a canvas element', function() {
-                       var canvas = document.getElementById(canvasId);
-                       var chart = new Chart(canvas);
-
-                       expect(chart).toBeValidChart();
-                       expect(chart.canvas).toBe(canvas);
-                       expect(chart.ctx).toBe(canvas.getContext('2d'));
-
-                       chart.destroy();
-               });
-
-               it('should accept a canvas context2D', function() {
-                       var canvas = document.getElementById(canvasId);
-                       var context = canvas.getContext('2d');
-                       var chart = new Chart(context);
-
-                       expect(chart).toBeValidChart();
-                       expect(chart.canvas).toBe(canvas);
-                       expect(chart.ctx).toBe(context);
-
-                       chart.destroy();
-               });
-
-               it('should accept an array containing canvas', function() {
-                       var canvas = document.getElementById(canvasId);
-                       var chart = new Chart([canvas]);
-
-                       expect(chart).toBeValidChart();
-                       expect(chart.canvas).toBe(canvas);
-                       expect(chart.ctx).toBe(canvas.getContext('2d'));
-
-                       chart.destroy();
-               });
-
-               it('should accept a canvas from an iframe', function(done) {
-                       var iframe = document.createElement('iframe');
-                       iframe.onload = function() {
-                               var doc = iframe.contentDocument;
-                               doc.body.innerHTML += '<canvas id="chart"></canvas>';
-                               var canvas = doc.getElementById('chart');
-                               var chart = new Chart(canvas);
-
-                               expect(chart).toBeValidChart();
-                               expect(chart.canvas).toBe(canvas);
-                               expect(chart.ctx).toBe(canvas.getContext('2d'));
-
-                               chart.destroy();
-                               canvas.remove();
-                               iframe.remove();
-
-                               done();
-                       };
-
-                       document.body.appendChild(iframe);
-               });
-       });
-
-       describe('config.options.aspectRatio', function() {
-               it('should use default "global" aspect ratio for render and display sizes', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 620px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 620, dh: 310,
-                               rw: 620, rh: 310,
-                       });
-               });
-
-               it('should use default "chart" aspect ratio for render and display sizes', function() {
-                       var ratio = Chart.defaults.controllers.doughnut.aspectRatio;
-                       Chart.defaults.controllers.doughnut.aspectRatio = 1;
-
-                       var chart = acquireChart({
-                               type: 'doughnut',
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 425px'
-                               }
-                       });
-
-                       Chart.defaults.controllers.doughnut.aspectRatio = ratio;
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 425, dh: 425,
-                               rw: 425, rh: 425,
-                       });
-               });
-
-               it('should use "user" aspect ratio for render and display sizes', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false,
-                                       aspectRatio: 3
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 405px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 405, dh: 135,
-                               rw: 405, rh: 135,
-                       });
-               });
-
-               it('should not apply aspect ratio when height specified', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false,
-                                       aspectRatio: 3
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 400px; height: 410px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 400, dh: 410,
-                               rw: 400, rh: 410,
-                       });
-               });
-       });
-
-       describe('config.options.responsive: false', function() {
-               it('should use default canvas size for render and display sizes', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: ''
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 150,
-                               rw: 300, rh: 150,
-                       });
-               });
-
-               it('should use canvas attributes for render and display sizes', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: '',
-                                       width: 305,
-                                       height: 245,
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 305, dh: 245,
-                               rw: 305, rh: 245,
-                       });
-               });
-
-               it('should use canvas style for render and display sizes (if no attributes)', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 345px; height: 125px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 345, dh: 125,
-                               rw: 345, rh: 125,
-                       });
-               });
-
-               it('should use attributes for the render size and style for the display size', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 345px; height: 125px;',
-                                       width: 165,
-                                       height: 85,
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 345, dh: 125,
-                               rw: 165, rh: 85,
-                       });
-               });
-
-               // https://github.com/chartjs/Chart.js/issues/3860
-               it('should support decimal display width and/or height', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: false
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 345.42px; height: 125.42px;'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 345, dh: 125,
-                               rw: 345, rh: 125,
-                       });
-               });
-       });
-
-       describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
-               it('should fill parent width and use aspect ratio to calculate height', function() {
-                       var chart = acquireChart({
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: true
-                               }
-                       }, {
-                               canvas: {
-                                       style: 'width: 150px; height: 245px'
-                               },
-                               wrapper: {
-                                       style: 'width: 300px; height: 350px'
-                               }
-                       });
-
-                       expect(chart).toBeChartOfSize({
-                               dw: 300, dh: 490,
-                               rw: 300, rh: 490,
-                       });
-               });
-       });
-
-       describe('controller.destroy', function() {
-               it('should reset context to default values', function() {
-                       var wrapper = document.createElement('div');
-                       var canvas = document.createElement('canvas');
-                       wrapper.appendChild(canvas);
-                       window.document.body.appendChild(wrapper);
-                       var chart = new Chart(canvas, {});
-                       var context = chart.ctx;
-
-                       chart.destroy();
-
-                       // https://www.w3.org/TR/2dcontext/#conformance-requirements
-                       Chart.helpers.each({
-                               fillStyle: '#000000',
-                               font: '10px sans-serif',
-                               lineJoin: 'miter',
-                               lineCap: 'butt',
-                               lineWidth: 1,
-                               miterLimit: 10,
-                               shadowBlur: 0,
-                               shadowColor: 'rgba(0, 0, 0, 0)',
-                               shadowOffsetX: 0,
-                               shadowOffsetY: 0,
-                               strokeStyle: '#000000',
-                               textAlign: 'start',
-                               textBaseline: 'alphabetic'
-                       }, function(value, key) {
-                               expect(context[key]).toBe(value);
-                       });
-
-                       wrapper.parentNode.removeChild(wrapper);
-               });
-
-               it('should restore canvas initial values', function(done) {
-                       var wrapper = document.createElement('div');
-                       var canvas = document.createElement('canvas');
-
-                       canvas.setAttribute('width', 180);
-                       canvas.setAttribute('style', 'width: 512px; height: 480px');
-                       wrapper.setAttribute('style', 'width: 450px; height: 450px; position: relative');
-
-                       wrapper.appendChild(canvas);
-                       window.document.body.appendChild(wrapper);
-
-                       var chart = new Chart(canvas.getContext('2d'), {
-                               options: {
-                                       responsive: true,
-                                       maintainAspectRatio: false
-                               }
-                       });
-
-                       waitForResize(chart, function() {
-                               expect(chart).toBeChartOfSize({
-                                       dw: 475, dh: 450,
-                                       rw: 475, rh: 450,
-                               });
-
-                               chart.destroy();
-
-                               expect(canvas.getAttribute('width')).toBe('180');
-                               expect(canvas.getAttribute('height')).toBe(null);
-                               expect(canvas.style.width).toBe('512px');
-                               expect(canvas.style.height).toBe('480px');
-                               expect(canvas.style.display).toBe('');
-
-                               wrapper.parentNode.removeChild(wrapper);
-                               done();
-                       });
-                       wrapper.style.width = '475px';
-               });
-       });
-
-       describe('event handling', function() {
-               it('should notify plugins about events', function(done) {
-                       var notifiedEvent;
-                       var plugin = {
-                               afterEvent: function(chart, args) {
-                                       notifiedEvent = args.event;
-                               }
-                       };
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       responsive: true
-                               },
-                               plugins: [plugin]
-                       });
-
-                       afterEvent(chart, 'click', function() {
-                               // Check that notifiedEvent is correct
-                               expect(notifiedEvent).not.toBe(undefined);
-
-                               // Is type correctly translated
-                               expect(notifiedEvent.type).toBe('click');
-
-                               // Relative Position
-                               expect(notifiedEvent.x).toBeCloseToPixel(chart.width / 2);
-                               expect(notifiedEvent.y).toBeCloseToPixel(chart.height / 2);
-
-                               done();
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'click', {
-                               x: chart.width / 2,
-                               y: chart.height / 2
-                       });
-               });
-       });
-
-       describe('isAttached', function() {
-               it('should detect detached when canvas is attached to DOM', function() {
-                       var platform = new DomPlatform();
-                       var canvas = document.createElement('canvas');
-                       var div = document.createElement('div');
-
-                       expect(platform.isAttached(canvas)).toEqual(false);
-                       div.appendChild(canvas);
-                       expect(platform.isAttached(canvas)).toEqual(false);
-                       document.body.appendChild(div);
-
-                       expect(platform.isAttached(canvas)).toEqual(true);
-
-                       div.removeChild(canvas);
-                       expect(platform.isAttached(canvas)).toEqual(false);
-                       document.body.removeChild(div);
-                       expect(platform.isAttached(canvas)).toEqual(false);
-               });
-       });
+    beforeEach(function() {
+      var canvas = document.createElement('canvas');
+      canvas.setAttribute('id', canvasId);
+      window.document.body.appendChild(canvas);
+    });
+
+    afterEach(function() {
+      document.getElementById(canvasId).remove();
+    });
+
+    it('should use the DomPlatform by default', function() {
+      var chart = acquireChart({type: 'line'});
+
+      expect(chart.platform).toBeInstanceOf(Chart.platforms.DomPlatform);
+
+      chart.destroy();
+    });
+
+    // see https://github.com/chartjs/Chart.js/issues/2807
+    it('should gracefully handle invalid item', function() {
+      var chart = new Chart('foobar');
+
+      expect(chart).not.toBeValidChart();
+
+      chart.destroy();
+    });
+
+    it('should accept a DOM element id', function() {
+      var canvas = document.getElementById(canvasId);
+      var chart = new Chart(canvasId);
+
+      expect(chart).toBeValidChart();
+      expect(chart.canvas).toBe(canvas);
+      expect(chart.ctx).toBe(canvas.getContext('2d'));
+
+      chart.destroy();
+    });
+
+    it('should accept a canvas element', function() {
+      var canvas = document.getElementById(canvasId);
+      var chart = new Chart(canvas);
+
+      expect(chart).toBeValidChart();
+      expect(chart.canvas).toBe(canvas);
+      expect(chart.ctx).toBe(canvas.getContext('2d'));
+
+      chart.destroy();
+    });
+
+    it('should accept a canvas context2D', function() {
+      var canvas = document.getElementById(canvasId);
+      var context = canvas.getContext('2d');
+      var chart = new Chart(context);
+
+      expect(chart).toBeValidChart();
+      expect(chart.canvas).toBe(canvas);
+      expect(chart.ctx).toBe(context);
+
+      chart.destroy();
+    });
+
+    it('should accept an array containing canvas', function() {
+      var canvas = document.getElementById(canvasId);
+      var chart = new Chart([canvas]);
+
+      expect(chart).toBeValidChart();
+      expect(chart.canvas).toBe(canvas);
+      expect(chart.ctx).toBe(canvas.getContext('2d'));
+
+      chart.destroy();
+    });
+
+    it('should accept a canvas from an iframe', function(done) {
+      var iframe = document.createElement('iframe');
+      iframe.onload = function() {
+        var doc = iframe.contentDocument;
+        doc.body.innerHTML += '<canvas id="chart"></canvas>';
+        var canvas = doc.getElementById('chart');
+        var chart = new Chart(canvas);
+
+        expect(chart).toBeValidChart();
+        expect(chart.canvas).toBe(canvas);
+        expect(chart.ctx).toBe(canvas.getContext('2d'));
+
+        chart.destroy();
+        canvas.remove();
+        iframe.remove();
+
+        done();
+      };
+
+      document.body.appendChild(iframe);
+    });
+  });
+
+  describe('config.options.aspectRatio', function() {
+    it('should use default "global" aspect ratio for render and display sizes', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 620px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 620, dh: 310,
+        rw: 620, rh: 310,
+      });
+    });
+
+    it('should use default "chart" aspect ratio for render and display sizes', function() {
+      var ratio = Chart.defaults.controllers.doughnut.aspectRatio;
+      Chart.defaults.controllers.doughnut.aspectRatio = 1;
+
+      var chart = acquireChart({
+        type: 'doughnut',
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 425px'
+        }
+      });
+
+      Chart.defaults.controllers.doughnut.aspectRatio = ratio;
+
+      expect(chart).toBeChartOfSize({
+        dw: 425, dh: 425,
+        rw: 425, rh: 425,
+      });
+    });
+
+    it('should use "user" aspect ratio for render and display sizes', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false,
+          aspectRatio: 3
+        }
+      }, {
+        canvas: {
+          style: 'width: 405px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 405, dh: 135,
+        rw: 405, rh: 135,
+      });
+    });
+
+    it('should not apply aspect ratio when height specified', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false,
+          aspectRatio: 3
+        }
+      }, {
+        canvas: {
+          style: 'width: 400px; height: 410px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 400, dh: 410,
+        rw: 400, rh: 410,
+      });
+    });
+  });
+
+  describe('config.options.responsive: false', function() {
+    it('should use default canvas size for render and display sizes', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: ''
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 150,
+        rw: 300, rh: 150,
+      });
+    });
+
+    it('should use canvas attributes for render and display sizes', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: '',
+          width: 305,
+          height: 245,
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 305, dh: 245,
+        rw: 305, rh: 245,
+      });
+    });
+
+    it('should use canvas style for render and display sizes (if no attributes)', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 345px; height: 125px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 345, dh: 125,
+        rw: 345, rh: 125,
+      });
+    });
+
+    it('should use attributes for the render size and style for the display size', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 345px; height: 125px;',
+          width: 165,
+          height: 85,
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 345, dh: 125,
+        rw: 165, rh: 85,
+      });
+    });
+
+    // https://github.com/chartjs/Chart.js/issues/3860
+    it('should support decimal display width and/or height', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: false
+        }
+      }, {
+        canvas: {
+          style: 'width: 345.42px; height: 125.42px;'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 345, dh: 125,
+        rw: 345, rh: 125,
+      });
+    });
+  });
+
+  describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
+    it('should fill parent width and use aspect ratio to calculate height', function() {
+      var chart = acquireChart({
+        options: {
+          responsive: true,
+          maintainAspectRatio: true
+        }
+      }, {
+        canvas: {
+          style: 'width: 150px; height: 245px'
+        },
+        wrapper: {
+          style: 'width: 300px; height: 350px'
+        }
+      });
+
+      expect(chart).toBeChartOfSize({
+        dw: 300, dh: 490,
+        rw: 300, rh: 490,
+      });
+    });
+  });
+
+  describe('controller.destroy', function() {
+    it('should reset context to default values', function() {
+      var wrapper = document.createElement('div');
+      var canvas = document.createElement('canvas');
+      wrapper.appendChild(canvas);
+      window.document.body.appendChild(wrapper);
+      var chart = new Chart(canvas, {});
+      var context = chart.ctx;
+
+      chart.destroy();
+
+      // https://www.w3.org/TR/2dcontext/#conformance-requirements
+      Chart.helpers.each({
+        fillStyle: '#000000',
+        font: '10px sans-serif',
+        lineJoin: 'miter',
+        lineCap: 'butt',
+        lineWidth: 1,
+        miterLimit: 10,
+        shadowBlur: 0,
+        shadowColor: 'rgba(0, 0, 0, 0)',
+        shadowOffsetX: 0,
+        shadowOffsetY: 0,
+        strokeStyle: '#000000',
+        textAlign: 'start',
+        textBaseline: 'alphabetic'
+      }, function(value, key) {
+        expect(context[key]).toBe(value);
+      });
+
+      wrapper.parentNode.removeChild(wrapper);
+    });
+
+    it('should restore canvas initial values', function(done) {
+      var wrapper = document.createElement('div');
+      var canvas = document.createElement('canvas');
+
+      canvas.setAttribute('width', 180);
+      canvas.setAttribute('style', 'width: 512px; height: 480px');
+      wrapper.setAttribute('style', 'width: 450px; height: 450px; position: relative');
+
+      wrapper.appendChild(canvas);
+      window.document.body.appendChild(wrapper);
+
+      var chart = new Chart(canvas.getContext('2d'), {
+        options: {
+          responsive: true,
+          maintainAspectRatio: false
+        }
+      });
+
+      waitForResize(chart, function() {
+        expect(chart).toBeChartOfSize({
+          dw: 475, dh: 450,
+          rw: 475, rh: 450,
+        });
+
+        chart.destroy();
+
+        expect(canvas.getAttribute('width')).toBe('180');
+        expect(canvas.getAttribute('height')).toBe(null);
+        expect(canvas.style.width).toBe('512px');
+        expect(canvas.style.height).toBe('480px');
+        expect(canvas.style.display).toBe('');
+
+        wrapper.parentNode.removeChild(wrapper);
+        done();
+      });
+      wrapper.style.width = '475px';
+    });
+  });
+
+  describe('event handling', function() {
+    it('should notify plugins about events', function(done) {
+      var notifiedEvent;
+      var plugin = {
+        afterEvent: function(chart, args) {
+          notifiedEvent = args.event;
+        }
+      };
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          responsive: true
+        },
+        plugins: [plugin]
+      });
+
+      afterEvent(chart, 'click', function() {
+        // Check that notifiedEvent is correct
+        expect(notifiedEvent).not.toBe(undefined);
+
+        // Is type correctly translated
+        expect(notifiedEvent.type).toBe('click');
+
+        // Relative Position
+        expect(notifiedEvent.x).toBeCloseToPixel(chart.width / 2);
+        expect(notifiedEvent.y).toBeCloseToPixel(chart.height / 2);
+
+        done();
+      });
+
+      jasmine.triggerMouseEvent(chart, 'click', {
+        x: chart.width / 2,
+        y: chart.height / 2
+      });
+    });
+  });
+
+  describe('isAttached', function() {
+    it('should detect detached when canvas is attached to DOM', function() {
+      var platform = new DomPlatform();
+      var canvas = document.createElement('canvas');
+      var div = document.createElement('div');
+
+      expect(platform.isAttached(canvas)).toEqual(false);
+      div.appendChild(canvas);
+      expect(platform.isAttached(canvas)).toEqual(false);
+      document.body.appendChild(div);
+
+      expect(platform.isAttached(canvas)).toEqual(true);
+
+      div.removeChild(canvas);
+      expect(platform.isAttached(canvas)).toEqual(false);
+      document.body.removeChild(div);
+      expect(platform.isAttached(canvas)).toEqual(false);
+    });
+  });
 });
index 9b9eb214d2be944abd8f48987d10fc4d1ebc6a4d..067781ebe4cbd0a401f8af8491704fea1f1d1df9 100644 (file)
 describe('Plugin.filler', function() {
-       function decodedFillValues(chart) {
-               return chart.data.datasets.map(function(dataset, index) {
-                       var meta = chart.getDatasetMeta(index) || {};
-                       expect(meta.$filler).toBeDefined();
-                       return meta.$filler.fill;
-               });
-       }
+  function decodedFillValues(chart) {
+    return chart.data.datasets.map(function(dataset, index) {
+      var meta = chart.getDatasetMeta(index) || {};
+      expect(meta.$filler).toBeDefined();
+      return meta.$filler.fill;
+    });
+  }
 
-       describe('auto', jasmine.fixture.specs('plugin.filler'));
+  describe('auto', jasmine.fixture.specs('plugin.filler'));
 
-       describe('dataset.fill', function() {
-               it('should support boundaries', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 'origin'},
-                                               {fill: 'start'},
-                                               {fill: 'end'},
-                                       ]
-                               }
-                       });
+  describe('dataset.fill', function() {
+    it('should support boundaries', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 'origin'},
+            {fill: 'start'},
+            {fill: 'end'},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual(['origin', 'start', 'end']);
-               });
+      expect(decodedFillValues(chart)).toEqual(['origin', 'start', 'end']);
+    });
 
-               it('should support absolute dataset index', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 1},
-                                               {fill: 3},
-                                               {fill: 0},
-                                               {fill: 2},
-                                       ]
-                               }
-                       });
+    it('should support absolute dataset index', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 1},
+            {fill: 3},
+            {fill: 0},
+            {fill: 2},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([1, 3, 0, 2]);
-               });
+      expect(decodedFillValues(chart)).toEqual([1, 3, 0, 2]);
+    });
 
-               it('should support relative dataset index', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: '+3'},
-                                               {fill: '-1'},
-                                               {fill: '+1'},
-                                               {fill: '-2'},
-                                       ]
-                               }
-                       });
+    it('should support relative dataset index', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: '+3'},
+            {fill: '-1'},
+            {fill: '+1'},
+            {fill: '-2'},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               3, // 0 + 3
-                               0, // 1 - 1
-                               3, // 2 + 1
-                               1, // 3 - 2
-                       ]);
-               });
+      expect(decodedFillValues(chart)).toEqual([
+        3, // 0 + 3
+        0, // 1 - 1
+        3, // 2 + 1
+        1, // 3 - 2
+      ]);
+    });
 
-               it('should handle default fill when true (origin)', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: true},
-                                               {fill: false},
-                                       ]
-                               }
-                       });
+    it('should handle default fill when true (origin)', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: true},
+            {fill: false},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual(['origin', false]);
-               });
+      expect(decodedFillValues(chart)).toEqual(['origin', false]);
+    });
 
-               it('should ignore self dataset index', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 0},
-                                               {fill: '-0'},
-                                               {fill: '+0'},
-                                               {fill: 3},
-                                       ]
-                               }
-                       });
+    it('should ignore self dataset index', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 0},
+            {fill: '-0'},
+            {fill: '+0'},
+            {fill: 3},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               false, // 0 === 0
-                               false, // 1 === 1 - 0
-                               false, // 2 === 2 + 0
-                               false, // 3 === 3
-                       ]);
-               });
+      expect(decodedFillValues(chart)).toEqual([
+        false, // 0 === 0
+        false, // 1 === 1 - 0
+        false, // 2 === 2 + 0
+        false, // 3 === 3
+      ]);
+    });
 
-               it('should ignore out of bounds dataset index', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: -2},
-                                               {fill: 4},
-                                               {fill: '-3'},
-                                               {fill: '+1'},
-                                       ]
-                               }
-                       });
+    it('should ignore out of bounds dataset index', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: -2},
+            {fill: 4},
+            {fill: '-3'},
+            {fill: '+1'},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               false, // 0 - 2 < 0
-                               false, // 1 + 4 > 3
-                               false, // 2 - 3 < 0
-                               false, // 3 + 1 > 3
-                       ]);
-               });
+      expect(decodedFillValues(chart)).toEqual([
+        false, // 0 - 2 < 0
+        false, // 1 + 4 > 3
+        false, // 2 - 3 < 0
+        false, // 3 + 1 > 3
+      ]);
+    });
 
-               it('should ignore invalid values', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 'foo'},
-                                               {fill: '+foo'},
-                                               {fill: '-foo'},
-                                               {fill: '+1.1'},
-                                               {fill: '-2.2'},
-                                               {fill: 3.3},
-                                               {fill: -4.4},
-                                               {fill: NaN},
-                                               {fill: Infinity},
-                                               {fill: ''},
-                                               {fill: null},
-                                               {fill: []},
-                                       ]
-                               }
-                       });
+    it('should ignore invalid values', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 'foo'},
+            {fill: '+foo'},
+            {fill: '-foo'},
+            {fill: '+1.1'},
+            {fill: '-2.2'},
+            {fill: 3.3},
+            {fill: -4.4},
+            {fill: NaN},
+            {fill: Infinity},
+            {fill: ''},
+            {fill: null},
+            {fill: []},
+          ]
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               false, // NaN (string)
-                               false, // NaN (string)
-                               false, // NaN (string)
-                               false, // float (string)
-                               false, // float (string)
-                               false, // float (number)
-                               false, // float (number)
-                               false, // NaN
-                               false, // !isFinite
-                               false, // empty string
-                               false, // null
-                               false, // array
-                       ]);
-               });
-       });
+      expect(decodedFillValues(chart)).toEqual([
+        false, // NaN (string)
+        false, // NaN (string)
+        false, // NaN (string)
+        false, // float (string)
+        false, // float (string)
+        false, // float (number)
+        false, // float (number)
+        false, // NaN
+        false, // !isFinite
+        false, // empty string
+        false, // null
+        false, // array
+      ]);
+    });
+  });
 
-       describe('options.plugins.filler.propagate', function() {
-               it('should compute propagated fill targets if true', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 'start', hidden: true},
-                                               {fill: '-1', hidden: true},
-                                               {fill: 1, hidden: true},
-                                               {fill: '-2', hidden: true},
-                                               {fill: '+1'},
-                                               {fill: '+2'},
-                                               {fill: '-1'},
-                                               {fill: 'end', hidden: true},
-                                       ]
-                               },
-                               options: {
-                                       plugins: {
-                                               filler: {
-                                                       propagate: true
-                                               }
-                                       }
-                               }
-                       });
+  describe('options.plugins.filler.propagate', function() {
+    it('should compute propagated fill targets if true', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 'start', hidden: true},
+            {fill: '-1', hidden: true},
+            {fill: 1, hidden: true},
+            {fill: '-2', hidden: true},
+            {fill: '+1'},
+            {fill: '+2'},
+            {fill: '-1'},
+            {fill: 'end', hidden: true},
+          ]
+        },
+        options: {
+          plugins: {
+            filler: {
+              propagate: true
+            }
+          }
+        }
+      });
 
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               'start', // 'start'
-                               'start', // 1 - 1 -> 0 (hidden) -> 'start'
-                               'start', // 1 (hidden) -> 0 (hidden) -> 'start'
-                               'start', // 3 - 2 -> 1 (hidden) -> 0 (hidden) -> 'start'
-                               5,       // 4 + 1
-                               'end',   // 5 + 2 -> 7 (hidden) -> 'end'
-                               5,       // 6 - 1 -> 5
-                               'end',   // 'end'
-                       ]);
-               });
+      expect(decodedFillValues(chart)).toEqual([
+        'start', // 'start'
+        'start', // 1 - 1 -> 0 (hidden) -> 'start'
+        'start', // 1 (hidden) -> 0 (hidden) -> 'start'
+        'start', // 3 - 2 -> 1 (hidden) -> 0 (hidden) -> 'start'
+        5,       // 4 + 1
+        'end',   // 5 + 2 -> 7 (hidden) -> 'end'
+        5,       // 6 - 1 -> 5
+        'end',   // 'end'
+      ]);
+    });
 
-               it('should preserve initial fill targets if false', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: 'start', hidden: true},
-                                               {fill: '-1', hidden: true},
-                                               {fill: 1, hidden: true},
-                                               {fill: '-2', hidden: true},
-                                               {fill: '+1'},
-                                               {fill: '+2'},
-                                               {fill: '-1'},
-                                               {fill: 'end', hidden: true},
-                                       ]
-                               },
-                               options: {
-                                       plugins: {
-                                               filler: {
-                                                       propagate: false
-                                               }
-                                       }
-                               }
-                       });
+    it('should preserve initial fill targets if false', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: 'start', hidden: true},
+            {fill: '-1', hidden: true},
+            {fill: 1, hidden: true},
+            {fill: '-2', hidden: true},
+            {fill: '+1'},
+            {fill: '+2'},
+            {fill: '-1'},
+            {fill: 'end', hidden: true},
+          ]
+        },
+        options: {
+          plugins: {
+            filler: {
+              propagate: false
+            }
+          }
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               'start', // 'origin'
-                               0,       // 1 - 1
-                               1,       // 1
-                               1,       // 3 - 2
-                               5,       // 4 + 1
-                               7,       // 5 + 2
-                               5,       // 6 - 1
-                               'end',   // 'end'
-                       ]);
-               });
+      expect(decodedFillValues(chart)).toEqual([
+        'start', // 'origin'
+        0,       // 1 - 1
+        1,       // 1
+        1,       // 3 - 2
+        5,       // 4 + 1
+        7,       // 5 + 2
+        5,       // 6 - 1
+        'end',   // 'end'
+      ]);
+    });
 
-               it('should prevent recursive propagation', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [
-                                               {fill: '+2', hidden: true},
-                                               {fill: '-1', hidden: true},
-                                               {fill: '-1', hidden: true},
-                                               {fill: '-2'}
-                                       ]
-                               },
-                               options: {
-                                       plugins: {
-                                               filler: {
-                                                       propagate: true
-                                               }
-                                       }
-                               }
-                       });
+    it('should prevent recursive propagation', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [
+            {fill: '+2', hidden: true},
+            {fill: '-1', hidden: true},
+            {fill: '-1', hidden: true},
+            {fill: '-2'}
+          ]
+        },
+        options: {
+          plugins: {
+            filler: {
+              propagate: true
+            }
+          }
+        }
+      });
 
-                       expect(decodedFillValues(chart)).toEqual([
-                               false, // 0 + 2 -> 2 (hidden) -> 1 (hidden) -> 0 (loop)
-                               false, // 1 - 1 -> 0 (hidden) -> 2 (hidden) -> 1 (loop)
-                               false, // 2 - 1 -> 1 (hidden) -> 0 (hidden) -> 2 (loop)
-                               false, // 3 - 2 -> 1 (hidden) -> 0 (hidden) -> 2 (hidden) -> 1 (loop)
-                       ]);
-               });
-       });
+      expect(decodedFillValues(chart)).toEqual([
+        false, // 0 + 2 -> 2 (hidden) -> 1 (hidden) -> 0 (loop)
+        false, // 1 - 1 -> 0 (hidden) -> 2 (hidden) -> 1 (loop)
+        false, // 2 - 1 -> 1 (hidden) -> 0 (hidden) -> 2 (loop)
+        false, // 3 - 2 -> 1 (hidden) -> 0 (hidden) -> 2 (hidden) -> 1 (loop)
+      ]);
+    });
+  });
 });
index a4acdf6e20bdd2d37c8af3cfc5a11fe63c16a596..f39d947d42410d345558c7c9dba49b255751031e 100644 (file)
 // Test the rectangle element
 describe('Legend block tests', function() {
-       describe('auto', jasmine.fixture.specs('plugin.legend'));
-
-       it('should have the correct default config', function() {
-               expect(Chart.defaults.plugins.legend).toEqual({
-                       display: true,
-                       position: 'top',
-                       align: 'center',
-                       fullSize: true,
-                       reverse: false,
-                       weight: 1000,
-
-                       // a callback that will handle
-                       onClick: jasmine.any(Function),
-                       onHover: null,
-                       onLeave: null,
-
-                       labels: {
-                               color: Chart.defaults.color,
-                               boxWidth: 40,
-                               padding: 10,
-                               generateLabels: jasmine.any(Function)
-                       },
-
-                       title: {
-                               color: Chart.defaults.color,
-                               display: false,
-                               position: 'center',
-                               text: '',
-                       }
-               });
-       });
-
-       it('should update bar chart correctly', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'butt',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       hidden: true,
-                                       borderJoinStyle: 'miter',
-                                       data: []
-                               }, {
-                                       label: 'dataset3',
-                                       borderWidth: 10,
-                                       borderColor: 'green',
-                                       pointStyle: 'crossRot',
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 0,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }, {
-                       text: 'dataset2',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: true,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 0,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 1
-               }, {
-                       text: 'dataset3',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 10,
-                       strokeStyle: 'green',
-                       pointStyle: 'crossRot',
-                       rotation: undefined,
-                       datasetIndex: 2
-               }]);
-       });
-
-       it('should update line chart correctly', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'round',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       hidden: true,
-                                       borderJoinStyle: 'round',
-                                       data: []
-                               }, {
-                                       label: 'dataset3',
-                                       borderWidth: 10,
-                                       borderColor: 'green',
-                                       pointStyle: 'crossRot',
-                                       fill: false,
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: 'round',
-                       lineDash: [2, 2],
-                       lineDashOffset: 5.5,
-                       lineJoin: 'miter',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }, {
-                       text: 'dataset2',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: true,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'round',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 1
-               }, {
-                       text: 'dataset3',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'miter',
-                       lineWidth: 10,
-                       strokeStyle: 'green',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 2
-               }]);
-       });
-
-       it('should reverse correctly', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'round',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       hidden: true,
-                                       borderJoinStyle: 'round',
-                                       data: []
-                               }, {
-                                       label: 'dataset3',
-                                       borderWidth: 10,
-                                       borderColor: 'green',
-                                       pointStyle: 'crossRot',
-                                       fill: false,
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               plugins: {
-                                       legend: {
-                                               reverse: true
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset3',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'miter',
-                       lineWidth: 10,
-                       strokeStyle: 'green',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 2
-               }, {
-                       text: 'dataset2',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: true,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'round',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 1
-               }, {
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: 'round',
-                       lineDash: [2, 2],
-                       lineDashOffset: 5.5,
-                       lineJoin: 'miter',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }]);
-       });
-
-       it('should filter items', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'butt',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       hidden: true,
-                                       borderJoinStyle: 'miter',
-                                       data: [],
-                                       legendHidden: true
-                               }, {
-                                       label: 'dataset3',
-                                       borderWidth: 10,
-                                       borderColor: 'green',
-                                       pointStyle: 'crossRot',
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               plugins: {
-                                       legend: {
-                                               labels: {
-                                                       filter: function(legendItem, data) {
-                                                               var dataset = data.datasets[legendItem.datasetIndex];
-                                                               return !dataset.legendHidden;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 0,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }, {
-                       text: 'dataset3',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 10,
-                       strokeStyle: 'green',
-                       pointStyle: 'crossRot',
-                       rotation: undefined,
-                       datasetIndex: 2
-               }]);
-       });
-
-       it('should sort items', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'round',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       hidden: true,
-                                       borderJoinStyle: 'round',
-                                       data: []
-                               }, {
-                                       label: 'dataset3',
-                                       borderWidth: 10,
-                                       borderColor: 'green',
-                                       pointStyle: 'crossRot',
-                                       fill: false,
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               plugins: {
-                                       legend: {
-                                               labels: {
-                                                       sort: function(a, b) {
-                                                               return b.datasetIndex > a.datasetIndex ? 1 : -1;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset3',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'miter',
-                       lineWidth: 10,
-                       strokeStyle: 'green',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 2
-               }, {
-                       text: 'dataset2',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: true,
-                       lineCap: 'butt',
-                       lineDash: [],
-                       lineDashOffset: 0,
-                       lineJoin: 'round',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 1
-               }, {
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: 'round',
-                       lineDash: [2, 2],
-                       lineDashOffset: 5.5,
-                       lineJoin: 'miter',
-                       lineWidth: 3,
-                       strokeStyle: 'rgba(0,0,0,0.1)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }]);
-       });
-
-       it('should not throw when the label options are missing', function() {
-               var makeChart = function() {
-                       window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [{
-                                               label: 'dataset1',
-                                               backgroundColor: '#f31',
-                                               borderCapStyle: 'butt',
-                                               borderDash: [2, 2],
-                                               borderDashOffset: 5.5,
-                                               data: []
-                                       }],
-                                       labels: []
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       labels: false,
-                                               }
-                                       }
-                               }
-                       });
-               };
-               expect(makeChart).not.toThrow();
-       });
-
-       it('should not draw legend items outside of the chart bounds', function() {
-               var chart = window.acquireChart(
-                       {
-                               type: 'line',
-                               data: {
-                                       datasets: [1, 2, 3].map(function(n) {
-                                               return {
-                                                       label: 'dataset' + n,
-                                                       data: []
-                                               };
-                                       }),
-                                       labels: []
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       position: 'right'
-                                               }
-                                       }
-                               }
-                       },
-                       {
-                               canvas: {
-                                       width: 512,
-                                       height: 105
-                               }
-                       }
-               );
-
-               // Check some basic assertions about the test setup
-               expect(chart.width).toBe(512);
-               expect(chart.legend.legendHitBoxes.length).toBe(3);
-
-               // Check whether any legend items reach outside the established bounds
-               chart.legend.legendHitBoxes.forEach(function(item) {
-                       expect(item.left + item.width).toBeLessThanOrEqual(chart.width);
-               });
-       });
-
-       it('should draw items with a custom boxHeight', function() {
-               var chart = window.acquireChart(
-                       {
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'dataset1',
-                                               data: []
-                                       }],
-                                       labels: []
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       position: 'right',
-                                                       labels: {
-                                                               boxHeight: 40
-                                                       }
-                                               }
-                                       }
-                               }
-                       },
-                       {
-                               canvas: {
-                                       width: 512,
-                                       height: 105
-                               }
-                       }
-               );
-               const hitBox = chart.legend.legendHitBoxes[0];
-               expect(hitBox.height).toBe(40);
-       });
-
-       it('should pick up the first item when the property is an array', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: ['#f31', '#666', '#14e'],
-                                       borderWidth: [5, 10, 15],
-                                       borderColor: ['red', 'green', 'blue'],
-                                       data: []
-                               }],
-                               labels: []
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 5,
-                       strokeStyle: 'red',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }]);
-       });
-
-       it('should use the value for the first item when the property is a function', function() {
-               var helpers = window.Chart.helpers;
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return helpers.color({r: value * 10, g: 0, b: 0}).rgbString();
-                                       },
-                                       borderWidth: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return value;
-                                       },
-                                       borderColor: function(ctx) {
-                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
-                                               return helpers.color({r: 255 - value * 10, g: 0, b: 0}).rgbString();
-                                       },
-                                       data: [5, 10, 15, 20]
-                               }],
-                               labels: ['A', 'B', 'C', 'D']
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: 'rgb(50, 0, 0)',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 5,
-                       strokeStyle: 'rgb(205, 0, 0)',
-                       pointStyle: undefined,
-                       rotation: undefined,
-                       datasetIndex: 0
-               }]);
-       });
-
-       it('should draw correctly when usePointStyle is true', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'butt',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       borderWidth: 0,
-                                       borderColor: '#f31',
-                                       pointStyle: 'crossRot',
-                                       pointBackgroundColor: 'rgba(0,0,0,0.1)',
-                                       pointBorderWidth: 5,
-                                       pointBorderColor: 'green',
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       backgroundColor: '#f31',
-                                       borderJoinStyle: 'miter',
-                                       borderWidth: 2,
-                                       borderColor: '#f31',
-                                       pointStyle: 'crossRot',
-                                       pointRotation: 15,
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               plugins: {
-                                       legend: {
-                                               labels: {
-                                                       usePointStyle: true
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 5,
-                       strokeStyle: 'green',
-                       pointStyle: 'crossRot',
-                       rotation: undefined,
-                       datasetIndex: 0
-               }, {
-                       text: 'dataset2',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 2,
-                       strokeStyle: '#f31',
-                       pointStyle: 'crossRot',
-                       rotation: 15,
-                       datasetIndex: 1
-               }]);
-       });
-
-       it('should draw correctly when usePointStyle is true and pointStyle override is set', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       backgroundColor: '#f31',
-                                       borderCapStyle: 'butt',
-                                       borderDash: [2, 2],
-                                       borderDashOffset: 5.5,
-                                       borderWidth: 0,
-                                       borderColor: '#f31',
-                                       pointStyle: 'crossRot',
-                                       pointBackgroundColor: 'rgba(0,0,0,0.1)',
-                                       pointBorderWidth: 5,
-                                       pointBorderColor: 'green',
-                                       data: []
-                               }, {
-                                       label: 'dataset2',
-                                       backgroundColor: '#f31',
-                                       borderJoinStyle: 'miter',
-                                       borderWidth: 2,
-                                       borderColor: '#f31',
-                                       pointStyle: 'crossRot',
-                                       pointRotation: 15,
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               plugins: {
-                                       legend: {
-                                               labels: {
-                                                       usePointStyle: true,
-                                                       pointStyle: 'star'
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.legend.legendItems).toEqual([{
-                       text: 'dataset1',
-                       fillStyle: 'rgba(0,0,0,0.1)',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 5,
-                       strokeStyle: 'green',
-                       pointStyle: 'star',
-                       rotation: undefined,
-                       datasetIndex: 0
-               }, {
-                       text: 'dataset2',
-                       fillStyle: '#f31',
-                       hidden: false,
-                       lineCap: undefined,
-                       lineDash: undefined,
-                       lineDashOffset: undefined,
-                       lineJoin: undefined,
-                       lineWidth: 2,
-                       strokeStyle: '#f31',
-                       pointStyle: 'star',
-                       rotation: 15,
-                       datasetIndex: 1
-               }]);
-       });
-
-       it('should not crash when the legend defaults are false', function() {
-               const oldDefaults = Chart.defaults.plugins.legend;
-
-               Chart.defaults.set({
-                       plugins: {
-                               legend: false,
-                       },
-               });
-
-               var chart = window.acquireChart({
-                       type: 'doughnut',
-                       data: {
-                               datasets: [{
-                                       label: 'dataset1',
-                                       data: [1, 2, 3, 4]
-                               }],
-                               labels: ['', '', '', '']
-                       },
-               });
-               expect(chart).toBeDefined();
-
-               Chart.defaults.set({
-                       plugins: {
-                               legend: oldDefaults,
-                       },
-               });
-       });
-
-       describe('config update', function() {
-               it ('should update the options', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       display: true
-                                               }
-                                       }
-                               }
-                       });
-                       expect(chart.legend.options.display).toBe(true);
-
-                       chart.options.plugins.legend.display = false;
-                       chart.update();
-                       expect(chart.legend.options.display).toBe(false);
-               });
-
-               it ('should update the associated layout item', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {},
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       fullSize: true,
-                                                       position: 'top',
-                                                       weight: 150
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.legend.fullSize).toBe(true);
-                       expect(chart.legend.position).toBe('top');
-                       expect(chart.legend.weight).toBe(150);
-
-                       chart.options.plugins.legend.fullSize = false;
-                       chart.options.plugins.legend.position = 'left';
-                       chart.options.plugins.legend.weight = 42;
-                       chart.update();
-
-                       expect(chart.legend.fullSize).toBe(false);
-                       expect(chart.legend.position).toBe('left');
-                       expect(chart.legend.weight).toBe(42);
-               });
-
-               it ('should remove the legend if the new options are false', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               }
-                       });
-                       expect(chart.legend).not.toBe(undefined);
-
-                       chart.options.plugins.legend = false;
-                       chart.update();
-                       expect(chart.legend).toBe(undefined);
-               });
-
-               it ('should create the legend if the legend options are changed to exist', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: false
-                                       }
-                               }
-                       });
-                       expect(chart.legend).toBe(undefined);
-
-                       chart.options.plugins.legend = {};
-                       chart.update();
-                       expect(chart.legend).not.toBe(undefined);
-                       expect(chart.legend.options).toEqual(jasmine.objectContaining(Chart.defaults.plugins.legend));
-               });
-       });
-
-       describe('callbacks', function() {
-               it('should call onClick, onHover and onLeave at the correct times', function(done) {
-                       var clickItem = null;
-                       var hoverItem = null;
-                       var leaveItem = null;
-
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       plugins: {
-                                               legend: {
-                                                       onClick: function(_, item) {
-                                                               clickItem = item;
-                                                       },
-                                                       onHover: function(_, item) {
-                                                               hoverItem = item;
-                                                       },
-                                                       onLeave: function(_, item) {
-                                                               leaveItem = item;
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       var hb = chart.legend.legendHitBoxes[0];
-                       var el = {
-                               x: hb.left + (hb.width / 2),
-                               y: hb.top + (hb.height / 2)
-                       };
-
-                       afterEvent(chart, 'click', function() {
-                               expect(clickItem).toBe(chart.legend.legendItems[0]);
-
-                               afterEvent(chart, 'mousemove', function() {
-                                       expect(hoverItem).toBe(chart.legend.legendItems[0]);
-
-                                       afterEvent(chart, 'mousemove', function() {
-                                               expect(leaveItem).toBe(chart.legend.legendItems[0]);
-
-                                               done();
-                                       });
-                                       jasmine.triggerMouseEvent(chart, 'mousemove', chart.getDatasetMeta(0).data[0]);
-                               });
-                               jasmine.triggerMouseEvent(chart, 'mousemove', el);
-                       });
-                       jasmine.triggerMouseEvent(chart, 'click', el);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('plugin.legend'));
+
+  it('should have the correct default config', function() {
+    expect(Chart.defaults.plugins.legend).toEqual({
+      display: true,
+      position: 'top',
+      align: 'center',
+      fullSize: true,
+      reverse: false,
+      weight: 1000,
+
+      // a callback that will handle
+      onClick: jasmine.any(Function),
+      onHover: null,
+      onLeave: null,
+
+      labels: {
+        color: Chart.defaults.color,
+        boxWidth: 40,
+        padding: 10,
+        generateLabels: jasmine.any(Function)
+      },
+
+      title: {
+        color: Chart.defaults.color,
+        display: false,
+        position: 'center',
+        text: '',
+      }
+    });
+  });
+
+  it('should update bar chart correctly', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'butt',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          data: []
+        }, {
+          label: 'dataset2',
+          hidden: true,
+          borderJoinStyle: 'miter',
+          data: []
+        }, {
+          label: 'dataset3',
+          borderWidth: 10,
+          borderColor: 'green',
+          pointStyle: 'crossRot',
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 0,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }, {
+      text: 'dataset2',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: true,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 0,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 1
+    }, {
+      text: 'dataset3',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 10,
+      strokeStyle: 'green',
+      pointStyle: 'crossRot',
+      rotation: undefined,
+      datasetIndex: 2
+    }]);
+  });
+
+  it('should update line chart correctly', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'round',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          data: []
+        }, {
+          label: 'dataset2',
+          hidden: true,
+          borderJoinStyle: 'round',
+          data: []
+        }, {
+          label: 'dataset3',
+          borderWidth: 10,
+          borderColor: 'green',
+          pointStyle: 'crossRot',
+          fill: false,
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: 'round',
+      lineDash: [2, 2],
+      lineDashOffset: 5.5,
+      lineJoin: 'miter',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }, {
+      text: 'dataset2',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: true,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'round',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 1
+    }, {
+      text: 'dataset3',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'miter',
+      lineWidth: 10,
+      strokeStyle: 'green',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 2
+    }]);
+  });
+
+  it('should reverse correctly', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'round',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          data: []
+        }, {
+          label: 'dataset2',
+          hidden: true,
+          borderJoinStyle: 'round',
+          data: []
+        }, {
+          label: 'dataset3',
+          borderWidth: 10,
+          borderColor: 'green',
+          pointStyle: 'crossRot',
+          fill: false,
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        plugins: {
+          legend: {
+            reverse: true
+          }
+        }
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset3',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'miter',
+      lineWidth: 10,
+      strokeStyle: 'green',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 2
+    }, {
+      text: 'dataset2',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: true,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'round',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 1
+    }, {
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: 'round',
+      lineDash: [2, 2],
+      lineDashOffset: 5.5,
+      lineJoin: 'miter',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }]);
+  });
+
+  it('should filter items', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'butt',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          data: []
+        }, {
+          label: 'dataset2',
+          hidden: true,
+          borderJoinStyle: 'miter',
+          data: [],
+          legendHidden: true
+        }, {
+          label: 'dataset3',
+          borderWidth: 10,
+          borderColor: 'green',
+          pointStyle: 'crossRot',
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        plugins: {
+          legend: {
+            labels: {
+              filter: function(legendItem, data) {
+                var dataset = data.datasets[legendItem.datasetIndex];
+                return !dataset.legendHidden;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 0,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }, {
+      text: 'dataset3',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 10,
+      strokeStyle: 'green',
+      pointStyle: 'crossRot',
+      rotation: undefined,
+      datasetIndex: 2
+    }]);
+  });
+
+  it('should sort items', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'round',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          data: []
+        }, {
+          label: 'dataset2',
+          hidden: true,
+          borderJoinStyle: 'round',
+          data: []
+        }, {
+          label: 'dataset3',
+          borderWidth: 10,
+          borderColor: 'green',
+          pointStyle: 'crossRot',
+          fill: false,
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        plugins: {
+          legend: {
+            labels: {
+              sort: function(a, b) {
+                return b.datasetIndex > a.datasetIndex ? 1 : -1;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset3',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'miter',
+      lineWidth: 10,
+      strokeStyle: 'green',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 2
+    }, {
+      text: 'dataset2',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: true,
+      lineCap: 'butt',
+      lineDash: [],
+      lineDashOffset: 0,
+      lineJoin: 'round',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 1
+    }, {
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: 'round',
+      lineDash: [2, 2],
+      lineDashOffset: 5.5,
+      lineJoin: 'miter',
+      lineWidth: 3,
+      strokeStyle: 'rgba(0,0,0,0.1)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }]);
+  });
+
+  it('should not throw when the label options are missing', function() {
+    var makeChart = function() {
+      window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [{
+            label: 'dataset1',
+            backgroundColor: '#f31',
+            borderCapStyle: 'butt',
+            borderDash: [2, 2],
+            borderDashOffset: 5.5,
+            data: []
+          }],
+          labels: []
+        },
+        options: {
+          plugins: {
+            legend: {
+              labels: false,
+            }
+          }
+        }
+      });
+    };
+    expect(makeChart).not.toThrow();
+  });
+
+  it('should not draw legend items outside of the chart bounds', function() {
+    var chart = window.acquireChart(
+      {
+        type: 'line',
+        data: {
+          datasets: [1, 2, 3].map(function(n) {
+            return {
+              label: 'dataset' + n,
+              data: []
+            };
+          }),
+          labels: []
+        },
+        options: {
+          plugins: {
+            legend: {
+              position: 'right'
+            }
+          }
+        }
+      },
+      {
+        canvas: {
+          width: 512,
+          height: 105
+        }
+      }
+    );
+
+    // Check some basic assertions about the test setup
+    expect(chart.width).toBe(512);
+    expect(chart.legend.legendHitBoxes.length).toBe(3);
+
+    // Check whether any legend items reach outside the established bounds
+    chart.legend.legendHitBoxes.forEach(function(item) {
+      expect(item.left + item.width).toBeLessThanOrEqual(chart.width);
+    });
+  });
+
+  it('should draw items with a custom boxHeight', function() {
+    var chart = window.acquireChart(
+      {
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'dataset1',
+            data: []
+          }],
+          labels: []
+        },
+        options: {
+          plugins: {
+            legend: {
+              position: 'right',
+              labels: {
+                boxHeight: 40
+              }
+            }
+          }
+        }
+      },
+      {
+        canvas: {
+          width: 512,
+          height: 105
+        }
+      }
+    );
+    const hitBox = chart.legend.legendHitBoxes[0];
+    expect(hitBox.height).toBe(40);
+  });
+
+  it('should pick up the first item when the property is an array', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: ['#f31', '#666', '#14e'],
+          borderWidth: [5, 10, 15],
+          borderColor: ['red', 'green', 'blue'],
+          data: []
+        }],
+        labels: []
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 5,
+      strokeStyle: 'red',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }]);
+  });
+
+  it('should use the value for the first item when the property is a function', function() {
+    var helpers = window.Chart.helpers;
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return helpers.color({r: value * 10, g: 0, b: 0}).rgbString();
+          },
+          borderWidth: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return value;
+          },
+          borderColor: function(ctx) {
+            var value = ctx.dataset.data[ctx.dataIndex] || 0;
+            return helpers.color({r: 255 - value * 10, g: 0, b: 0}).rgbString();
+          },
+          data: [5, 10, 15, 20]
+        }],
+        labels: ['A', 'B', 'C', 'D']
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: 'rgb(50, 0, 0)',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 5,
+      strokeStyle: 'rgb(205, 0, 0)',
+      pointStyle: undefined,
+      rotation: undefined,
+      datasetIndex: 0
+    }]);
+  });
+
+  it('should draw correctly when usePointStyle is true', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'butt',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          borderWidth: 0,
+          borderColor: '#f31',
+          pointStyle: 'crossRot',
+          pointBackgroundColor: 'rgba(0,0,0,0.1)',
+          pointBorderWidth: 5,
+          pointBorderColor: 'green',
+          data: []
+        }, {
+          label: 'dataset2',
+          backgroundColor: '#f31',
+          borderJoinStyle: 'miter',
+          borderWidth: 2,
+          borderColor: '#f31',
+          pointStyle: 'crossRot',
+          pointRotation: 15,
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        plugins: {
+          legend: {
+            labels: {
+              usePointStyle: true
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 5,
+      strokeStyle: 'green',
+      pointStyle: 'crossRot',
+      rotation: undefined,
+      datasetIndex: 0
+    }, {
+      text: 'dataset2',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 2,
+      strokeStyle: '#f31',
+      pointStyle: 'crossRot',
+      rotation: 15,
+      datasetIndex: 1
+    }]);
+  });
+
+  it('should draw correctly when usePointStyle is true and pointStyle override is set', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          backgroundColor: '#f31',
+          borderCapStyle: 'butt',
+          borderDash: [2, 2],
+          borderDashOffset: 5.5,
+          borderWidth: 0,
+          borderColor: '#f31',
+          pointStyle: 'crossRot',
+          pointBackgroundColor: 'rgba(0,0,0,0.1)',
+          pointBorderWidth: 5,
+          pointBorderColor: 'green',
+          data: []
+        }, {
+          label: 'dataset2',
+          backgroundColor: '#f31',
+          borderJoinStyle: 'miter',
+          borderWidth: 2,
+          borderColor: '#f31',
+          pointStyle: 'crossRot',
+          pointRotation: 15,
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        plugins: {
+          legend: {
+            labels: {
+              usePointStyle: true,
+              pointStyle: 'star'
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.legend.legendItems).toEqual([{
+      text: 'dataset1',
+      fillStyle: 'rgba(0,0,0,0.1)',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 5,
+      strokeStyle: 'green',
+      pointStyle: 'star',
+      rotation: undefined,
+      datasetIndex: 0
+    }, {
+      text: 'dataset2',
+      fillStyle: '#f31',
+      hidden: false,
+      lineCap: undefined,
+      lineDash: undefined,
+      lineDashOffset: undefined,
+      lineJoin: undefined,
+      lineWidth: 2,
+      strokeStyle: '#f31',
+      pointStyle: 'star',
+      rotation: 15,
+      datasetIndex: 1
+    }]);
+  });
+
+  it('should not crash when the legend defaults are false', function() {
+    const oldDefaults = Chart.defaults.plugins.legend;
+
+    Chart.defaults.set({
+      plugins: {
+        legend: false,
+      },
+    });
+
+    var chart = window.acquireChart({
+      type: 'doughnut',
+      data: {
+        datasets: [{
+          label: 'dataset1',
+          data: [1, 2, 3, 4]
+        }],
+        labels: ['', '', '', '']
+      },
+    });
+    expect(chart).toBeDefined();
+
+    Chart.defaults.set({
+      plugins: {
+        legend: oldDefaults,
+      },
+    });
+  });
+
+  describe('config update', function() {
+    it ('should update the options', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          plugins: {
+            legend: {
+              display: true
+            }
+          }
+        }
+      });
+      expect(chart.legend.options.display).toBe(true);
+
+      chart.options.plugins.legend.display = false;
+      chart.update();
+      expect(chart.legend.options.display).toBe(false);
+    });
+
+    it ('should update the associated layout item', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {},
+        options: {
+          plugins: {
+            legend: {
+              fullSize: true,
+              position: 'top',
+              weight: 150
+            }
+          }
+        }
+      });
+
+      expect(chart.legend.fullSize).toBe(true);
+      expect(chart.legend.position).toBe('top');
+      expect(chart.legend.weight).toBe(150);
+
+      chart.options.plugins.legend.fullSize = false;
+      chart.options.plugins.legend.position = 'left';
+      chart.options.plugins.legend.weight = 42;
+      chart.update();
+
+      expect(chart.legend.fullSize).toBe(false);
+      expect(chart.legend.position).toBe('left');
+      expect(chart.legend.weight).toBe(42);
+    });
+
+    it ('should remove the legend if the new options are false', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        }
+      });
+      expect(chart.legend).not.toBe(undefined);
+
+      chart.options.plugins.legend = false;
+      chart.update();
+      expect(chart.legend).toBe(undefined);
+    });
+
+    it ('should create the legend if the legend options are changed to exist', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          plugins: {
+            legend: false
+          }
+        }
+      });
+      expect(chart.legend).toBe(undefined);
+
+      chart.options.plugins.legend = {};
+      chart.update();
+      expect(chart.legend).not.toBe(undefined);
+      expect(chart.legend.options).toEqual(jasmine.objectContaining(Chart.defaults.plugins.legend));
+    });
+  });
+
+  describe('callbacks', function() {
+    it('should call onClick, onHover and onLeave at the correct times', function(done) {
+      var clickItem = null;
+      var hoverItem = null;
+      var leaveItem = null;
+
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          plugins: {
+            legend: {
+              onClick: function(_, item) {
+                clickItem = item;
+              },
+              onHover: function(_, item) {
+                hoverItem = item;
+              },
+              onLeave: function(_, item) {
+                leaveItem = item;
+              }
+            }
+          }
+        }
+      });
+
+      var hb = chart.legend.legendHitBoxes[0];
+      var el = {
+        x: hb.left + (hb.width / 2),
+        y: hb.top + (hb.height / 2)
+      };
+
+      afterEvent(chart, 'click', function() {
+        expect(clickItem).toBe(chart.legend.legendItems[0]);
+
+        afterEvent(chart, 'mousemove', function() {
+          expect(hoverItem).toBe(chart.legend.legendItems[0]);
+
+          afterEvent(chart, 'mousemove', function() {
+            expect(leaveItem).toBe(chart.legend.legendItems[0]);
+
+            done();
+          });
+          jasmine.triggerMouseEvent(chart, 'mousemove', chart.getDatasetMeta(0).data[0]);
+        });
+        jasmine.triggerMouseEvent(chart, 'mousemove', el);
+      });
+      jasmine.triggerMouseEvent(chart, 'click', el);
+    });
+  });
 });
index 351e1dcd5278b0e1d8f9c4d2634386e423c48201..9bcd0e802c70fbbb701b24b6bd5607b6baf77927 100644 (file)
 var Title = Chart.registry.getPlugin('title')._element;
 
 describe('Title block tests', function() {
-       it('Should have the correct default config', function() {
-               expect(Chart.defaults.plugins.title).toEqual({
-                       align: 'center',
-                       color: Chart.defaults.color,
-                       display: false,
-                       position: 'top',
-                       fullSize: true,
-                       weight: 2000,
-                       font: {
-                               style: 'bold'
-                       },
-                       padding: 10,
-                       text: ''
-               });
-       });
-
-       it('should update correctly', function() {
-               var chart = {
-                       options: Chart.helpers.clone(Chart.defaults)
-               };
-
-               var options = Chart.helpers.clone(Chart.defaults.plugins.title);
-               options.text = 'My title';
-
-               var title = new Title({
-                       chart: chart,
-                       options: options
-               });
-
-               title.update(400, 200);
-
-               expect(title.width).toEqual(0);
-               expect(title.height).toEqual(0);
-
-               // Now we have a height since we display
-               title.options.display = true;
-
-               title.update(400, 200);
-
-               expect(title.width).toEqual(400);
-               expect(title.height).toEqual(34.4);
-       });
-
-       it('should update correctly when vertical', function() {
-               var chart = {
-                       options: Chart.helpers.clone(Chart.defaults)
-               };
-
-               var options = Chart.helpers.clone(Chart.defaults.plugins.title);
-               options.text = 'My title';
-               options.position = 'left';
-
-               var title = new Title({
-                       chart: chart,
-                       options: options
-               });
-
-               title.update(200, 400);
-
-               expect(title.width).toEqual(0);
-               expect(title.height).toEqual(0);
-
-               // Now we have a height since we display
-               title.options.display = true;
-
-               title.update(200, 400);
-
-               expect(title.width).toEqual(34.4);
-               expect(title.height).toEqual(400);
-       });
-
-       it('should have the correct size when there are multiple lines of text', function() {
-               var chart = {
-                       options: Chart.helpers.clone(Chart.defaults)
-               };
-
-               var options = Chart.helpers.clone(Chart.defaults.plugins.title);
-               options.text = ['line1', 'line2'];
-               options.position = 'left';
-               options.display = true;
-               options.font.lineHeight = 1.5;
-
-               var title = new Title({
-                       chart: chart,
-                       options: options
-               });
-
-               title.update(200, 400);
-
-               expect(title.width).toEqual(56);
-               expect(title.height).toEqual(400);
-       });
-
-       it('should draw correctly horizontally', function() {
-               var chart = {
-                       options: Chart.helpers.clone(Chart.defaults)
-               };
-               var context = window.createMockContext();
-
-               var options = Chart.helpers.clone(Chart.defaults.plugins.title);
-               options.text = 'My title';
-
-               var title = new Title({
-                       chart: chart,
-                       options: options,
-                       ctx: context
-               });
-
-               title.update(400, 200);
-               title.draw();
-
-               expect(context.getCalls()).toEqual([]);
-
-               // Now we have a height since we display
-               title.options.display = true;
-
-               title.update(400, 200);
-               title.top = 50;
-               title.left = 100;
-               title.bottom = title.top + title.height;
-               title.right = title.left + title.width;
-               title.draw();
-
-               expect(context.getCalls()).toEqual([{
-                       name: 'save',
-                       args: []
-               }, {
-                       name: 'translate',
-                       args: [300, 67.2]
-               }, {
-                       name: 'rotate',
-                       args: [0]
-               }, {
-                       name: 'setFont',
-                       args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
-               }, {
-                       name: 'setFillStyle',
-                       args: ['#666']
-               }, {
-                       name: 'setTextAlign',
-                       args: ['center'],
-               }, {
-                       name: 'setTextBaseline',
-                       args: ['middle'],
-               }, {
-                       name: 'fillText',
-                       args: ['My title', 0, 0, 400]
-               }, {
-                       name: 'restore',
-                       args: []
-               }]);
-       });
-
-       it ('should draw correctly vertically', function() {
-               var chart = {
-                       options: Chart.helpers.clone(Chart.defaults)
-               };
-               var context = window.createMockContext();
-
-               var options = Chart.helpers.clone(Chart.defaults.plugins.title);
-               options.text = 'My title';
-               options.position = 'left';
-
-               var title = new Title({
-                       chart: chart,
-                       options: options,
-                       ctx: context
-               });
-
-               title.update(200, 400);
-               title.draw();
-
-               expect(context.getCalls()).toEqual([]);
-
-               // Now we have a height since we display
-               title.options.display = true;
-
-               title.update(200, 400);
-               title.top = 50;
-               title.left = 100;
-               title.bottom = title.top + title.height;
-               title.right = title.left + title.width;
-               title.draw();
-
-               expect(context.getCalls()).toEqual([{
-                       name: 'save',
-                       args: []
-               }, {
-                       name: 'translate',
-                       args: [117.2, 250]
-               }, {
-                       name: 'rotate',
-                       args: [-0.5 * Math.PI]
-               }, {
-                       name: 'setFont',
-                       args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
-               }, {
-                       name: 'setFillStyle',
-                       args: ['#666']
-               }, {
-                       name: 'setTextAlign',
-                       args: ['center'],
-               }, {
-                       name: 'setTextBaseline',
-                       args: ['middle'],
-               }, {
-                       name: 'fillText',
-                       args: ['My title', 0, 0, 400]
-               }, {
-                       name: 'restore',
-                       args: []
-               }]);
-
-               // Rotation is other way on right side
-               title.options.position = 'right';
-
-               // Reset call tracker
-               context.resetCalls();
-
-               title.update(200, 400);
-               title.top = 50;
-               title.left = 100;
-               title.bottom = title.top + title.height;
-               title.right = title.left + title.width;
-               title.draw();
-
-               expect(context.getCalls()).toEqual([{
-                       name: 'save',
-                       args: []
-               }, {
-                       name: 'translate',
-                       args: [117.2, 250]
-               }, {
-                       name: 'rotate',
-                       args: [0.5 * Math.PI]
-               }, {
-                       name: 'setFont',
-                       args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
-               }, {
-                       name: 'setFillStyle',
-                       args: ['#666']
-               }, {
-                       name: 'setTextAlign',
-                       args: ['center'],
-               }, {
-                       name: 'setTextBaseline',
-                       args: ['middle'],
-               }, {
-                       name: 'fillText',
-                       args: ['My title', 0, 0, 400]
-               }, {
-                       name: 'restore',
-                       args: []
-               }]);
-       });
-
-       describe('config update', function() {
-               it ('should update the options', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       plugins: {
-                                               title: {
-                                                       display: true
-                                               }
-                                       }
-                               }
-                       });
-                       expect(chart.titleBlock.options.display).toBe(true);
-
-                       chart.options.plugins.title.display = false;
-                       chart.update();
-                       expect(chart.titleBlock.options.display).toBe(false);
-               });
-
-               it ('should update the associated layout item', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {},
-                               options: {
-                                       plugins: {
-                                               title: {
-                                                       fullSize: true,
-                                                       position: 'top',
-                                                       weight: 150
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.titleBlock.fullSize).toBe(true);
-                       expect(chart.titleBlock.position).toBe('top');
-                       expect(chart.titleBlock.weight).toBe(150);
-
-                       chart.options.plugins.title.fullSize = false;
-                       chart.options.plugins.title.position = 'left';
-                       chart.options.plugins.title.weight = 42;
-                       chart.update();
-
-                       expect(chart.titleBlock.fullSize).toBe(false);
-                       expect(chart.titleBlock.position).toBe('left');
-                       expect(chart.titleBlock.weight).toBe(42);
-               });
-
-               it ('should remove the title if the new options are false', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               }
-                       });
-                       expect(chart.titleBlock).not.toBe(undefined);
-
-                       chart.options.plugins.title = false;
-                       chart.update();
-                       expect(chart.titleBlock).toBe(undefined);
-               });
-
-               it ('should create the title if the title options are changed to exist', function() {
-                       var chart = acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['A', 'B', 'C', 'D'],
-                                       datasets: [{
-                                               data: [10, 20, 30, 100]
-                                       }]
-                               },
-                               options: {
-                                       plugins: {
-                                               title: false
-                                       }
-                               }
-                       });
-                       expect(chart.titleBlock).toBe(undefined);
-
-                       chart.options.plugins.title = {};
-                       chart.update();
-                       expect(chart.titleBlock).not.toBe(undefined);
-                       expect(chart.titleBlock.options).toEqual(jasmine.objectContaining(Chart.defaults.plugins.title));
-               });
-       });
+  it('Should have the correct default config', function() {
+    expect(Chart.defaults.plugins.title).toEqual({
+      align: 'center',
+      color: Chart.defaults.color,
+      display: false,
+      position: 'top',
+      fullSize: true,
+      weight: 2000,
+      font: {
+        style: 'bold'
+      },
+      padding: 10,
+      text: ''
+    });
+  });
+
+  it('should update correctly', function() {
+    var chart = {
+      options: Chart.helpers.clone(Chart.defaults)
+    };
+
+    var options = Chart.helpers.clone(Chart.defaults.plugins.title);
+    options.text = 'My title';
+
+    var title = new Title({
+      chart: chart,
+      options: options
+    });
+
+    title.update(400, 200);
+
+    expect(title.width).toEqual(0);
+    expect(title.height).toEqual(0);
+
+    // Now we have a height since we display
+    title.options.display = true;
+
+    title.update(400, 200);
+
+    expect(title.width).toEqual(400);
+    expect(title.height).toEqual(34.4);
+  });
+
+  it('should update correctly when vertical', function() {
+    var chart = {
+      options: Chart.helpers.clone(Chart.defaults)
+    };
+
+    var options = Chart.helpers.clone(Chart.defaults.plugins.title);
+    options.text = 'My title';
+    options.position = 'left';
+
+    var title = new Title({
+      chart: chart,
+      options: options
+    });
+
+    title.update(200, 400);
+
+    expect(title.width).toEqual(0);
+    expect(title.height).toEqual(0);
+
+    // Now we have a height since we display
+    title.options.display = true;
+
+    title.update(200, 400);
+
+    expect(title.width).toEqual(34.4);
+    expect(title.height).toEqual(400);
+  });
+
+  it('should have the correct size when there are multiple lines of text', function() {
+    var chart = {
+      options: Chart.helpers.clone(Chart.defaults)
+    };
+
+    var options = Chart.helpers.clone(Chart.defaults.plugins.title);
+    options.text = ['line1', 'line2'];
+    options.position = 'left';
+    options.display = true;
+    options.font.lineHeight = 1.5;
+
+    var title = new Title({
+      chart: chart,
+      options: options
+    });
+
+    title.update(200, 400);
+
+    expect(title.width).toEqual(56);
+    expect(title.height).toEqual(400);
+  });
+
+  it('should draw correctly horizontally', function() {
+    var chart = {
+      options: Chart.helpers.clone(Chart.defaults)
+    };
+    var context = window.createMockContext();
+
+    var options = Chart.helpers.clone(Chart.defaults.plugins.title);
+    options.text = 'My title';
+
+    var title = new Title({
+      chart: chart,
+      options: options,
+      ctx: context
+    });
+
+    title.update(400, 200);
+    title.draw();
+
+    expect(context.getCalls()).toEqual([]);
+
+    // Now we have a height since we display
+    title.options.display = true;
+
+    title.update(400, 200);
+    title.top = 50;
+    title.left = 100;
+    title.bottom = title.top + title.height;
+    title.right = title.left + title.width;
+    title.draw();
+
+    expect(context.getCalls()).toEqual([{
+      name: 'save',
+      args: []
+    }, {
+      name: 'translate',
+      args: [300, 67.2]
+    }, {
+      name: 'rotate',
+      args: [0]
+    }, {
+      name: 'setFont',
+      args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
+    }, {
+      name: 'setFillStyle',
+      args: ['#666']
+    }, {
+      name: 'setTextAlign',
+      args: ['center'],
+    }, {
+      name: 'setTextBaseline',
+      args: ['middle'],
+    }, {
+      name: 'fillText',
+      args: ['My title', 0, 0, 400]
+    }, {
+      name: 'restore',
+      args: []
+    }]);
+  });
+
+  it ('should draw correctly vertically', function() {
+    var chart = {
+      options: Chart.helpers.clone(Chart.defaults)
+    };
+    var context = window.createMockContext();
+
+    var options = Chart.helpers.clone(Chart.defaults.plugins.title);
+    options.text = 'My title';
+    options.position = 'left';
+
+    var title = new Title({
+      chart: chart,
+      options: options,
+      ctx: context
+    });
+
+    title.update(200, 400);
+    title.draw();
+
+    expect(context.getCalls()).toEqual([]);
+
+    // Now we have a height since we display
+    title.options.display = true;
+
+    title.update(200, 400);
+    title.top = 50;
+    title.left = 100;
+    title.bottom = title.top + title.height;
+    title.right = title.left + title.width;
+    title.draw();
+
+    expect(context.getCalls()).toEqual([{
+      name: 'save',
+      args: []
+    }, {
+      name: 'translate',
+      args: [117.2, 250]
+    }, {
+      name: 'rotate',
+      args: [-0.5 * Math.PI]
+    }, {
+      name: 'setFont',
+      args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
+    }, {
+      name: 'setFillStyle',
+      args: ['#666']
+    }, {
+      name: 'setTextAlign',
+      args: ['center'],
+    }, {
+      name: 'setTextBaseline',
+      args: ['middle'],
+    }, {
+      name: 'fillText',
+      args: ['My title', 0, 0, 400]
+    }, {
+      name: 'restore',
+      args: []
+    }]);
+
+    // Rotation is other way on right side
+    title.options.position = 'right';
+
+    // Reset call tracker
+    context.resetCalls();
+
+    title.update(200, 400);
+    title.top = 50;
+    title.left = 100;
+    title.bottom = title.top + title.height;
+    title.right = title.left + title.width;
+    title.draw();
+
+    expect(context.getCalls()).toEqual([{
+      name: 'save',
+      args: []
+    }, {
+      name: 'translate',
+      args: [117.2, 250]
+    }, {
+      name: 'rotate',
+      args: [0.5 * Math.PI]
+    }, {
+      name: 'setFont',
+      args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"],
+    }, {
+      name: 'setFillStyle',
+      args: ['#666']
+    }, {
+      name: 'setTextAlign',
+      args: ['center'],
+    }, {
+      name: 'setTextBaseline',
+      args: ['middle'],
+    }, {
+      name: 'fillText',
+      args: ['My title', 0, 0, 400]
+    }, {
+      name: 'restore',
+      args: []
+    }]);
+  });
+
+  describe('config update', function() {
+    it ('should update the options', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          plugins: {
+            title: {
+              display: true
+            }
+          }
+        }
+      });
+      expect(chart.titleBlock.options.display).toBe(true);
+
+      chart.options.plugins.title.display = false;
+      chart.update();
+      expect(chart.titleBlock.options.display).toBe(false);
+    });
+
+    it ('should update the associated layout item', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {},
+        options: {
+          plugins: {
+            title: {
+              fullSize: true,
+              position: 'top',
+              weight: 150
+            }
+          }
+        }
+      });
+
+      expect(chart.titleBlock.fullSize).toBe(true);
+      expect(chart.titleBlock.position).toBe('top');
+      expect(chart.titleBlock.weight).toBe(150);
+
+      chart.options.plugins.title.fullSize = false;
+      chart.options.plugins.title.position = 'left';
+      chart.options.plugins.title.weight = 42;
+      chart.update();
+
+      expect(chart.titleBlock.fullSize).toBe(false);
+      expect(chart.titleBlock.position).toBe('left');
+      expect(chart.titleBlock.weight).toBe(42);
+    });
+
+    it ('should remove the title if the new options are false', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        }
+      });
+      expect(chart.titleBlock).not.toBe(undefined);
+
+      chart.options.plugins.title = false;
+      chart.update();
+      expect(chart.titleBlock).toBe(undefined);
+    });
+
+    it ('should create the title if the title options are changed to exist', function() {
+      var chart = acquireChart({
+        type: 'line',
+        data: {
+          labels: ['A', 'B', 'C', 'D'],
+          datasets: [{
+            data: [10, 20, 30, 100]
+          }]
+        },
+        options: {
+          plugins: {
+            title: false
+          }
+        }
+      });
+      expect(chart.titleBlock).toBe(undefined);
+
+      chart.options.plugins.title = {};
+      chart.update();
+      expect(chart.titleBlock).not.toBe(undefined);
+      expect(chart.titleBlock.options).toEqual(jasmine.objectContaining(Chart.defaults.plugins.title));
+    });
+  });
 });
index fabb34d3874d716e9769694c2fc9617a76f34d92..2166ee645f5c76558cccde6051121111d4414472 100644 (file)
@@ -3,1576 +3,1576 @@ const tooltipPlugin = Chart.registry.getPlugin('tooltip');
 const Tooltip = tooltipPlugin._element;
 
 describe('Plugin.Tooltip', function() {
-       describe('auto', jasmine.fixture.specs('core.tooltip'));
-
-       describe('config', function() {
-               it('should not include the dataset label in the body string if not defined', function() {
-                       var data = {
-                               datasets: [{
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       };
-                       var tooltipItem = {
-                               index: 1,
-                               datasetIndex: 0,
-                               dataset: data.datasets[0],
-                               label: 'Point 2',
-                               formattedValue: '20'
-                       };
-
-                       var label = Chart.defaults.plugins.tooltip.callbacks.label(tooltipItem);
-                       expect(label).toBe('20');
-
-                       data.datasets[0].label = 'My dataset';
-                       label = Chart.defaults.plugins.tooltip.callbacks.label(tooltipItem);
-                       expect(label).toBe('My dataset: 20');
-               });
-       });
-
-       describe('index mode', function() {
-               it('Should only use x distance when intersect is false', function(done) {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               },
-                               options: {
-                                       plugins: {
-                                               tooltip: {
-                                                       mode: 'index',
-                                                       intersect: false,
-                                               }
-                                       },
-                                       hover: {
-                                               mode: 'index',
-                                               intersect: false
-                                       }
-                               }
-                       });
-
-                       // Trigger an event over top of the
-                       var meta = chart.getDatasetMeta(0);
-                       var point = meta.data[1];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               // Check and see if tooltip was displayed
-                               var tooltip = chart.tooltip;
-                               var defaults = Chart.defaults;
-
-                               expect(tooltip.options.xPadding).toEqual(6);
-                               expect(tooltip.options.yPadding).toEqual(6);
-                               expect(tooltip.xAlign).toEqual('left');
-                               expect(tooltip.yAlign).toEqual('center');
-                               expect(tooltip.options.bodyColor).toEqual('#fff');
-
-                               expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
-                                       family: defaults.font.family,
-                                       style: defaults.font.style,
-                                       size: defaults.font.size,
-                               }));
-
-                               expect(tooltip.options).toEqual(jasmine.objectContaining({
-                                       bodyAlign: 'left',
-                                       bodySpacing: 2,
-                               }));
-
-                               expect(tooltip.options.titleColor).toEqual('#fff');
-                               expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
-                                       family: defaults.font.family,
-                                       style: 'bold',
-                                       size: defaults.font.size,
-                               }));
-
-                               expect(tooltip.options).toEqual(jasmine.objectContaining({
-                                       titleAlign: 'left',
-                                       titleSpacing: 2,
-                                       titleMarginBottom: 6,
-                               }));
-
-                               expect(tooltip.options.footerColor).toEqual('#fff');
-                               expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
-                                       family: defaults.font.family,
-                                       style: 'bold',
-                                       size: defaults.font.size,
-                               }));
-
-                               expect(tooltip.options).toEqual(jasmine.objectContaining({
-                                       footerAlign: 'left',
-                                       footerSpacing: 2,
-                                       footerMarginTop: 6,
-                               }));
-
-                               expect(tooltip.options).toEqual(jasmine.objectContaining({
-                                       // Appearance
-                                       caretSize: 5,
-                                       caretPadding: 2,
-                                       cornerRadius: 6,
-                                       backgroundColor: 'rgba(0,0,0,0.8)',
-                                       multiKeyBackground: '#fff',
-                                       displayColors: true
-                               }));
-
-                               expect(tooltip).toEqual(jasmine.objectContaining({
-                                       opacity: 1,
-
-                                       // Text
-                                       title: ['Point 2'],
-                                       beforeBody: [],
-                                       body: [{
-                                               before: [],
-                                               lines: ['Dataset 1: 20'],
-                                               after: []
-                                       }, {
-                                               before: [],
-                                               lines: ['Dataset 2: 40'],
-                                               after: []
-                                       }],
-                                       afterBody: [],
-                                       footer: [],
-                                       labelColors: [{
-                                               borderColor: defaults.borderColor,
-                                               backgroundColor: defaults.backgroundColor
-                                       }, {
-                                               borderColor: defaults.borderColor,
-                                               backgroundColor: defaults.backgroundColor
-                                       }]
-                               }));
-
-                               expect(tooltip.x).toBeCloseToPixel(267);
-                               expect(tooltip.y).toBeCloseToPixel(155);
-
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', {x: point.x, y: chart.chartArea.top + 10});
-               });
-
-               it('Should only display if intersecting if intersect is set', function(done) {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               },
-                               options: {
-                                       plugins: {
-                                               tooltip: {
-                                                       mode: 'index',
-                                                       intersect: true
-                                               }
-                                       }
-                               }
-                       });
-
-                       // Trigger an event over top of the
-                       var meta = chart.getDatasetMeta(0);
-                       var point = meta.data[1];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               // Check and see if tooltip was displayed
-                               var tooltip = chart.tooltip;
-
-                               expect(tooltip).toEqual(jasmine.objectContaining({
-                                       opacity: 0,
-                               }));
-
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', {x: point.x, y: 0});
-               });
-       });
-
-       it('Should display in single mode', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'nearest',
-                                               intersect: true
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta = chart.getDatasetMeta(0);
-               var point = meta.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip.options.xPadding).toEqual(6);
-                       expect(tooltip.options.yPadding).toEqual(6);
-                       expect(tooltip.xAlign).toEqual('left');
-                       expect(tooltip.yAlign).toEqual('center');
-
-                       expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: defaults.font.style,
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               bodyAlign: 'left',
-                               bodySpacing: 2,
-                       }));
-
-                       expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               titleAlign: 'left',
-                               titleSpacing: 2,
-                               titleMarginBottom: 6,
-                       }));
-
-                       expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               footerAlign: 'left',
-                               footerSpacing: 2,
-                               footerMarginTop: 6,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               // Appearance
-                               caretSize: 5,
-                               caretPadding: 2,
-                               cornerRadius: 6,
-                               backgroundColor: 'rgba(0,0,0,0.8)',
-                               multiKeyBackground: '#fff',
-                               displayColors: true
-                       }));
-
-                       expect(tooltip.opacity).toEqual(1);
-                       expect(tooltip.title).toEqual(['Point 2']);
-                       expect(tooltip.beforeBody).toEqual([]);
-                       expect(tooltip.body).toEqual([{
-                               before: [],
-                               lines: ['Dataset 1: 20'],
-                               after: []
-                       }]);
-                       expect(tooltip.afterBody).toEqual([]);
-                       expect(tooltip.footer).toEqual([]);
-                       expect(tooltip.labelTextColors).toEqual(['#fff']);
-
-                       expect(tooltip.labelColors).toEqual([{
-                               borderColor: defaults.borderColor,
-                               backgroundColor: defaults.backgroundColor
-                       }]);
-
-                       expect(tooltip.x).toBeCloseToPixel(267);
-                       expect(tooltip.y).toBeCloseToPixel(312);
-
-                       done();
-               });
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
-
-       it('Should display information from user callbacks', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               callbacks: {
-                                                       beforeTitle: function() {
-                                                               return 'beforeTitle';
-                                                       },
-                                                       title: function() {
-                                                               return 'title';
-                                                       },
-                                                       afterTitle: function() {
-                                                               return 'afterTitle';
-                                                       },
-                                                       beforeBody: function() {
-                                                               return 'beforeBody';
-                                                       },
-                                                       beforeLabel: function() {
-                                                               return 'beforeLabel';
-                                                       },
-                                                       label: function() {
-                                                               return 'label';
-                                                       },
-                                                       afterLabel: function() {
-                                                               return 'afterLabel';
-                                                       },
-                                                       afterBody: function() {
-                                                               return 'afterBody';
-                                                       },
-                                                       beforeFooter: function() {
-                                                               return 'beforeFooter';
-                                                       },
-                                                       footer: function() {
-                                                               return 'footer';
-                                                       },
-                                                       afterFooter: function() {
-                                                               return 'afterFooter';
-                                                       },
-                                                       labelTextColor: function() {
-                                                               return 'labelTextColor';
-                                                       },
-                                                       labelPointStyle: function() {
-                                                               return {
-                                                                       pointStyle: 'labelPointStyle',
-                                                                       rotation: 42
-                                                               };
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta = chart.getDatasetMeta(0);
-               var point = meta.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip.options.xPadding).toEqual(6);
-                       expect(tooltip.options.yPadding).toEqual(6);
-                       expect(tooltip.xAlign).toEqual('left');
-                       expect(tooltip.yAlign).toEqual('center');
-
-                       expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: defaults.font.style,
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               bodyAlign: 'left',
-                               bodySpacing: 2,
-                       }));
-
-                       expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               titleSpacing: 2,
-                               titleMarginBottom: 6,
-                       }));
-
-                       expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               footerAlign: 'left',
-                               footerSpacing: 2,
-                               footerMarginTop: 6,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               // Appearance
-                               caretSize: 5,
-                               caretPadding: 2,
-                               cornerRadius: 6,
-                               backgroundColor: 'rgba(0,0,0,0.8)',
-                               multiKeyBackground: '#fff',
-                       }));
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               opacity: 1,
-
-                               // Text
-                               title: ['beforeTitle', 'title', 'afterTitle'],
-                               beforeBody: ['beforeBody'],
-                               body: [{
-                                       before: ['beforeLabel'],
-                                       lines: ['label'],
-                                       after: ['afterLabel']
-                               }, {
-                                       before: ['beforeLabel'],
-                                       lines: ['label'],
-                                       after: ['afterLabel']
-                               }],
-                               afterBody: ['afterBody'],
-                               footer: ['beforeFooter', 'footer', 'afterFooter'],
-                               labelTextColors: ['labelTextColor', 'labelTextColor'],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }, {
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }],
-                               labelPointStyles: [{
-                                       pointStyle: 'labelPointStyle',
-                                       rotation: 42
-                               }, {
-                                       pointStyle: 'labelPointStyle',
-                                       rotation: 42
-                               }]
-                       }));
-
-                       expect(tooltip.x).toBeCloseToPixel(267);
-                       expect(tooltip.y).toBeCloseToPixel(75);
-
-                       done();
-               });
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
-
-
-       it('Should provide context object to user callbacks', function(done) {
-               const chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [{x: 1, y: 10}, {x: 2, y: 20}, {x: 3, y: 30}]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear'
-                                       }
-                               },
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               callbacks: {
-                                                       beforeLabel: function(ctx) {
-                                                               return ctx.parsed.x + ',' + ctx.parsed.y;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               const meta = chart.getDatasetMeta(0);
-               const point = meta.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       const tooltip = chart.tooltip;
-
-                       expect(tooltip.body[0].before).toEqual(['2,20']);
-
-                       done();
-               });
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
-
-       it('Should allow sorting items', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               itemSort: function(a, b) {
-                                                       return a.datasetIndex > b.datasetIndex ? -1 : 1;
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta0 = chart.getDatasetMeta(0);
-               var point0 = meta0.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               // Positioning
-                               xAlign: 'left',
-                               yAlign: 'center',
-
-                               // Text
-                               title: ['Point 2'],
-                               beforeBody: [],
-                               body: [{
-                                       before: [],
-                                       lines: ['Dataset 2: 40'],
-                                       after: []
-                               }, {
-                                       before: [],
-                                       lines: ['Dataset 1: 20'],
-                                       after: []
-                               }],
-                               afterBody: [],
-                               footer: [],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }, {
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }]
-                       }));
-
-                       expect(tooltip.x).toBeCloseToPixel(267);
-                       expect(tooltip.y).toBeCloseToPixel(155);
-
-                       done();
-               });
-               jasmine.triggerMouseEvent(chart, 'mousemove', point0);
-
-       });
-
-       it('Should allow reversing items', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               reverse: true
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta0 = chart.getDatasetMeta(0);
-               var point0 = meta0.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               // Positioning
-                               xAlign: 'left',
-                               yAlign: 'center',
-
-                               // Text
-                               title: ['Point 2'],
-                               beforeBody: [],
-                               body: [{
-                                       before: [],
-                                       lines: ['Dataset 2: 40'],
-                                       after: []
-                               }, {
-                                       before: [],
-                                       lines: ['Dataset 1: 20'],
-                                       after: []
-                               }],
-                               afterBody: [],
-                               footer: [],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }, {
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }]
-                       }));
-
-                       expect(tooltip.x).toBeCloseToPixel(267);
-                       expect(tooltip.y).toBeCloseToPixel(155);
-
-                       done();
-               });
-
-               jasmine.triggerMouseEvent(chart, 'mousemove', point0);
-       });
-
-       it('Should follow dataset order', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)',
-                                       order: 10
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)',
-                                       order: 5
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index'
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta0 = chart.getDatasetMeta(0);
-               var point0 = meta0.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               // Positioning
-                               xAlign: 'left',
-                               yAlign: 'center',
-
-                               // Text
-                               title: ['Point 2'],
-                               beforeBody: [],
-                               body: [{
-                                       before: [],
-                                       lines: ['Dataset 2: 40'],
-                                       after: []
-                               }, {
-                                       before: [],
-                                       lines: ['Dataset 1: 20'],
-                                       after: []
-                               }],
-                               afterBody: [],
-                               footer: [],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }, {
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }]
-                       }));
-
-                       expect(tooltip.x).toBeCloseToPixel(267);
-                       expect(tooltip.y).toBeCloseToPixel(155);
-
-                       done();
-               });
-
-               jasmine.triggerMouseEvent(chart, 'mousemove', point0);
-       });
-
-       it('should filter items from the tooltip using the callback', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)',
-                                       tooltipHidden: true
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               filter: function(tooltipItem, index, tooltipItems, data) {
-                                                       // For testing purposes remove the first dataset that has a tooltipHidden property
-                                                       return !data.datasets[tooltipItem.datasetIndex].tooltipHidden;
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta0 = chart.getDatasetMeta(0);
-               var point0 = meta0.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               // Positioning
-                               xAlign: 'left',
-                               yAlign: 'center',
-
-                               // Text
-                               title: ['Point 2'],
-                               beforeBody: [],
-                               body: [{
-                                       before: [],
-                                       lines: ['Dataset 2: 40'],
-                                       after: []
-                               }],
-                               afterBody: [],
-                               footer: [],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }]
-                       }));
-
-                       done();
-               });
-
-               jasmine.triggerMouseEvent(chart, 'mousemove', point0);
-       });
-
-       it('should set the caretPadding based on a config setting', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)',
-                                       tooltipHidden: true
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               caretPadding: 10
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta0 = chart.getDatasetMeta(0);
-               var point0 = meta0.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               // Positioning
-                               caretPadding: 10,
-                       }));
-
-                       done();
-               });
-
-               jasmine.triggerMouseEvent(chart, 'mousemove', point0);
-       });
-
-       ['line', 'bar'].forEach(function(type) {
-               it('Should have dataPoints in a ' + type + ' chart', function(done) {
-                       var chart = window.acquireChart({
-                               type: type,
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               },
-                               options: {
-                                       plugins: {
-                                               tooltip: {
-                                                       mode: 'nearest',
-                                                       intersect: true
-                                               }
-                                       }
-                               }
-                       });
-
-                       // Trigger an event over top of the element
-                       var pointIndex = 1;
-                       var datasetIndex = 0;
-                       var point = chart.getDatasetMeta(datasetIndex).data[pointIndex];
-
-                       afterEvent(chart, 'mousemove', function() {
-                               // Check and see if tooltip was displayed
-                               var tooltip = chart.tooltip;
-
-                               expect(tooltip instanceof Object).toBe(true);
-                               expect(tooltip.dataPoints instanceof Array).toBe(true);
-                               expect(tooltip.dataPoints.length).toBe(1);
-
-                               var tooltipItem = tooltip.dataPoints[0];
-
-                               expect(tooltipItem.dataIndex).toBe(pointIndex);
-                               expect(tooltipItem.datasetIndex).toBe(datasetIndex);
-                               expect(typeof tooltipItem.label).toBe('string');
-                               expect(tooltipItem.label).toBe(chart.data.labels[pointIndex]);
-                               expect(typeof tooltipItem.formattedValue).toBe('string');
-                               expect(tooltipItem.formattedValue).toBe('' + chart.data.datasets[datasetIndex].data[pointIndex]);
-
-                               done();
-                       });
-
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
-
-       it('Should not update if active element has not changed', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'nearest',
-                                               intersect: true,
-                                               callbacks: {
-                                                       title: function() {
-                                                               return 'registering callback...';
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta = chart.getDatasetMeta(0);
-               var firstPoint = meta.data[1];
-
-               var tooltip = chart.tooltip;
-               spyOn(tooltip, 'update').and.callThrough();
-
-               afterEvent(chart, 'mousemove', function() {
-                       expect(tooltip.update).toHaveBeenCalledWith(true);
-
-                       // Reset calls
-                       tooltip.update.calls.reset();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(tooltip.update).not.toHaveBeenCalled();
-
-                               done();
-                       });
-                       // Second dispatch change event (same event), should not update tooltip
-                       jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
-               });
-               // First dispatch change event, should update tooltip
-               jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
-       });
-
-       it('Should update if active elements are the same, but the position has changed', function(done) {
-               const chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               stacked: true,
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               },
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'nearest',
-                                               position: 'nearest',
-                                               intersect: true,
-                                               callbacks: {
-                                                       title: function() {
-                                                               return 'registering callback...';
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               const meta = chart.getDatasetMeta(0);
-               const firstPoint = meta.data[1];
-
-               const meta2 = chart.getDatasetMeta(1);
-               const secondPoint = meta2.data[1];
-
-               const tooltip = chart.tooltip;
-               spyOn(tooltip, 'update');
-
-               afterEvent(chart, 'mousemove', function() {
-                       expect(tooltip.update).toHaveBeenCalledWith(true);
-
-                       // Reset calls
-                       tooltip.update.calls.reset();
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(tooltip.update).toHaveBeenCalledWith(true);
-
-                               done();
-                       });
-                       // Second dispatch change event (same event), should update tooltip
-                       // because position mode is 'nearest'
-                       jasmine.triggerMouseEvent(chart, 'mousemove', secondPoint);
-               });
-               // First dispatch change event, should update tooltip
-               jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
-       });
-
-       describe('positioners', function() {
-               it('Should call custom positioner with correct parameters and scope', function(done) {
-
-                       tooltipPlugin.positioners.test = function() {
-                               return {x: 0, y: 0};
-                       };
-
-                       spyOn(tooltipPlugin.positioners, 'test').and.callThrough();
-
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }, {
-                                               label: 'Dataset 2',
-                                               data: [40, 40, 40],
-                                               pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               },
-                               options: {
-                                       plugins: {
-                                               tooltip: {
-                                                       mode: 'nearest',
-                                                       position: 'test'
-                                               }
-                                       }
-                               }
-                       });
-
-                       // Trigger an event over top of the
-                       var pointIndex = 1;
-                       var datasetIndex = 0;
-                       var meta = chart.getDatasetMeta(datasetIndex);
-                       var point = meta.data[pointIndex];
-                       var fn = tooltipPlugin.positioners.test;
-
-                       afterEvent(chart, 'mousemove', function() {
-                               expect(fn.calls.count()).toBe(2);
-                               expect(fn.calls.first().args[0] instanceof Array).toBe(true);
-                               expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'x')).toBe(true);
-                               expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'y')).toBe(true);
-                               expect(fn.calls.first().object instanceof Tooltip).toBe(true);
-
-                               done();
-                       });
-                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-               });
-       });
-
-       it('Should avoid tooltip truncation in x axis if there is enough space to show tooltip without truncation', function(done) {
-               var chart = window.acquireChart({
-                       type: 'pie',
-                       data: {
-                               datasets: [{
-                                       data: [
-                                               50,
-                                               50
-                                       ],
-                                       backgroundColor: [
-                                               'rgb(255, 0, 0)',
-                                               'rgb(0, 255, 0)'
-                                       ],
-                                       label: 'Dataset 1'
-                               }],
-                               labels: [
-                                       'Red long tooltip text to avoid unnecessary loop steps',
-                                       'Green long tooltip text to avoid unnecessary loop steps'
-                               ]
-                       },
-                       options: {
-                               responsive: true,
-                               animation: {
-                                       // without this slice center point is calculated wrong
-                                       animateRotate: false
-                               },
-                               plugins: {
-                                       tooltip: {
-                                               animation: false
-                                       }
-                               }
-                       }
-               });
-
-               function testSlice(slice, count) {
-                       var meta = chart.getDatasetMeta(0);
-                       var point = meta.data[slice].getCenterPoint();
-                       var tooltipPosition = meta.data[slice].tooltipPosition();
-
-                       function recursive(left) {
-                               chart.config.data.labels[slice] = chart.config.data.labels[slice] + 'XX';
-                               chart.update();
-
-                               afterEvent(chart, 'mouseout', function() {
-                                       afterEvent(chart, 'mousemove', function() {
-                                               var tooltip = chart.tooltip;
-                                               expect(tooltip.dataPoints.length).toBe(1);
-                                               expect(tooltip.x).toBeGreaterThanOrEqual(0);
-                                               if (tooltip.width <= chart.width) {
-                                                       expect(tooltip.x + tooltip.width).toBeLessThanOrEqual(chart.width);
-                                               }
-                                               expect(tooltip.caretX).toBeCloseToPixel(tooltipPosition.x);
-                                               // if tooltip is longer than chart area then all tests done
-                                               if (tooltip.width > chart.width || left === 0) {
-                                                       done(left === 0 && new Error('max iterations reached'));
-                                               } else {
-                                                       recursive(left - 1);
-                                               }
-                                       });
-                                       jasmine.triggerMouseEvent(chart, 'mousemove', point);
-                               });
-
-                               jasmine.triggerMouseEvent(chart, 'mouseout', point);
-                       }
-
-                       recursive(count);
-               }
-
-               // Trigger an event over top of the slice
-               for (var slice = 0; slice < 2; slice++) {
-                       testSlice(slice, 20);
-               }
-       });
-
-       it('Should split newlines into separate lines in user callbacks', function(done) {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       label: 'Dataset 1',
-                                       data: [10, 20, 30],
-                                       pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       label: 'Dataset 2',
-                                       data: [40, 40, 40],
-                                       pointHoverBorderColor: 'rgb(0, 0, 255)',
-                                       pointHoverBackgroundColor: 'rgb(0, 255, 255)'
-                               }],
-                               labels: ['Point 1', 'Point 2', 'Point 3']
-                       },
-                       options: {
-                               plugins: {
-                                       tooltip: {
-                                               mode: 'index',
-                                               callbacks: {
-                                                       beforeTitle: function() {
-                                                               return 'beforeTitle\nnewline';
-                                                       },
-                                                       title: function() {
-                                                               return 'title\nnewline';
-                                                       },
-                                                       afterTitle: function() {
-                                                               return 'afterTitle\nnewline';
-                                                       },
-                                                       beforeBody: function() {
-                                                               return 'beforeBody\nnewline';
-                                                       },
-                                                       beforeLabel: function() {
-                                                               return 'beforeLabel\nnewline';
-                                                       },
-                                                       label: function() {
-                                                               return 'label';
-                                                       },
-                                                       afterLabel: function() {
-                                                               return 'afterLabel\nnewline';
-                                                       },
-                                                       afterBody: function() {
-                                                               return 'afterBody\nnewline';
-                                                       },
-                                                       beforeFooter: function() {
-                                                               return 'beforeFooter\nnewline';
-                                                       },
-                                                       footer: function() {
-                                                               return 'footer\nnewline';
-                                                       },
-                                                       afterFooter: function() {
-                                                               return 'afterFooter\nnewline';
-                                                       },
-                                                       labelTextColor: function() {
-                                                               return 'labelTextColor';
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Trigger an event over top of the
-               var meta = chart.getDatasetMeta(0);
-               var point = meta.data[1];
-
-               afterEvent(chart, 'mousemove', function() {
-                       // Check and see if tooltip was displayed
-                       var tooltip = chart.tooltip;
-                       var defaults = Chart.defaults;
-
-                       expect(tooltip.options.xPadding).toEqual(6);
-                       expect(tooltip.options.yPadding).toEqual(6);
-                       expect(tooltip.xAlign).toEqual('center');
-                       expect(tooltip.yAlign).toEqual('top');
-
-                       expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: defaults.font.style,
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               bodyAlign: 'left',
-                               bodySpacing: 2,
-                       }));
-
-                       expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               titleAlign: 'left',
-                               titleSpacing: 2,
-                               titleMarginBottom: 6,
-                       }));
-
-                       expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
-                               family: defaults.font.family,
-                               style: 'bold',
-                               size: defaults.font.size,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               footerAlign: 'left',
-                               footerSpacing: 2,
-                               footerMarginTop: 6,
-                       }));
-
-                       expect(tooltip.options).toEqual(jasmine.objectContaining({
-                               // Appearance
-                               caretSize: 5,
-                               caretPadding: 2,
-                               cornerRadius: 6,
-                               backgroundColor: 'rgba(0,0,0,0.8)',
-                               multiKeyBackground: '#fff',
-                       }));
-
-                       expect(tooltip).toEqual(jasmine.objectContaining({
-                               opacity: 1,
-
-                               // Text
-                               title: ['beforeTitle', 'newline', 'title', 'newline', 'afterTitle', 'newline'],
-                               beforeBody: ['beforeBody', 'newline'],
-                               body: [{
-                                       before: ['beforeLabel', 'newline'],
-                                       lines: ['label'],
-                                       after: ['afterLabel', 'newline']
-                               }, {
-                                       before: ['beforeLabel', 'newline'],
-                                       lines: ['label'],
-                                       after: ['afterLabel', 'newline']
-                               }],
-                               afterBody: ['afterBody', 'newline'],
-                               footer: ['beforeFooter', 'newline', 'footer', 'newline', 'afterFooter', 'newline'],
-                               labelTextColors: ['labelTextColor', 'labelTextColor'],
-                               labelColors: [{
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }, {
-                                       borderColor: defaults.borderColor,
-                                       backgroundColor: defaults.backgroundColor
-                               }]
-                       }));
-
-                       done();
-               });
-
-               jasmine.triggerMouseEvent(chart, 'mousemove', point);
-       });
-
-       describe('text align', function() {
-               var defaults = Chart.defaults;
-               var makeView = function(title, body, footer) {
-                       return {
-                               // Positioning
-                               x: 100,
-                               y: 100,
-                               width: 100,
-                               height: 100,
-                               xAlign: 'left',
-                               yAlign: 'top',
-
-                               options: {
-                                       enabled: true,
-
-                                       xPadding: 5,
-                                       yPadding: 5,
-
-                                       // Body
-                                       bodyFont: {
-                                               family: defaults.font.family,
-                                               style: defaults.font.style,
-                                               size: defaults.font.size,
-                                       },
-                                       bodyColor: '#fff',
-                                       bodyAlign: body,
-                                       bodySpacing: 2,
-
-                                       // Title
-                                       titleFont: {
-                                               family: defaults.font.family,
-                                               style: 'bold',
-                                               size: defaults.font.size,
-                                       },
-                                       titleColor: '#fff',
-                                       titleAlign: title,
-                                       titleSpacing: 2,
-                                       titleMarginBottom: 6,
-
-                                       // Footer
-                                       footerFont: {
-                                               family: defaults.font.family,
-                                               style: 'bold',
-                                               size: defaults.font.size,
-                                       },
-                                       footerColor: '#fff',
-                                       footerAlign: footer,
-                                       footerSpacing: 2,
-                                       footerMarginTop: 6,
-
-                                       // Appearance
-                                       caretSize: 5,
-                                       cornerRadius: 6,
-                                       caretPadding: 2,
-                                       borderColor: '#aaa',
-                                       borderWidth: 1,
-                                       backgroundColor: 'rgba(0,0,0,0.8)',
-                                       multiKeyBackground: '#fff',
-                                       displayColors: false
-
-                               },
-                               opacity: 1,
-
-                               // Text
-                               title: ['title'],
-                               beforeBody: [],
-                               body: [{
-                                       before: [],
-                                       lines: ['label'],
-                                       after: []
-                               }],
-                               afterBody: [],
-                               footer: ['footer'],
-                               labelTextColors: ['#fff'],
-                               labelColors: [{
-                                       borderColor: 'rgb(255, 0, 0)',
-                                       backgroundColor: 'rgb(0, 255, 0)'
-                               }, {
-                                       borderColor: 'rgb(0, 0, 255)',
-                                       backgroundColor: 'rgb(0, 255, 255)'
-                               }]
-                       };
-               };
-               var drawBody = [
-                       {name: 'save', args: []},
-                       {name: 'setFillStyle', args: ['rgba(0,0,0,0.8)']},
-                       {name: 'setStrokeStyle', args: ['#aaa']},
-                       {name: 'setLineWidth', args: [1]},
-                       {name: 'beginPath', args: []},
-                       {name: 'moveTo', args: [106, 100]},
-                       {name: 'lineTo', args: [106, 100]},
-                       {name: 'lineTo', args: [111, 95]},
-                       {name: 'lineTo', args: [116, 100]},
-                       {name: 'lineTo', args: [194, 100]},
-                       {name: 'quadraticCurveTo', args: [200, 100, 200, 106]},
-                       {name: 'lineTo', args: [200, 194]},
-                       {name: 'quadraticCurveTo', args: [200, 200, 194, 200]},
-                       {name: 'lineTo', args: [106, 200]},
-                       {name: 'quadraticCurveTo', args: [100, 200, 100, 194]},
-                       {name: 'lineTo', args: [100, 106]},
-                       {name: 'quadraticCurveTo', args: [100, 100, 106, 100]},
-                       {name: 'closePath', args: []},
-                       {name: 'fill', args: []},
-                       {name: 'stroke', args: []}
-               ];
-
-               var mockContext = window.createMockContext();
-               var tooltip = new Tooltip({
-                       _chart: {
-                               options: {
-                                       plugins: {
-                                               tooltip: {
-                                                       animation: false,
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               it('Should go left', function() {
-                       mockContext.resetCalls();
-                       Chart.helpers.merge(tooltip, makeView('left', 'left', 'left'));
-                       tooltip.draw(mockContext);
-
-                       expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
-                               {name: 'setTextAlign', args: ['left']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['title', 105, 111]},
-                               {name: 'setTextAlign', args: ['left']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'fillText', args: ['label', 105, 129]},
-                               {name: 'setTextAlign', args: ['left']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['footer', 105, 147]},
-                               {name: 'restore', args: []}
-                       ]));
-               });
-
-               it('Should go right', function() {
-                       mockContext.resetCalls();
-                       Chart.helpers.merge(tooltip, makeView('right', 'right', 'right'));
-                       tooltip.draw(mockContext);
-
-                       expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
-                               {name: 'setTextAlign', args: ['right']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['title', 195, 111]},
-                               {name: 'setTextAlign', args: ['right']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'fillText', args: ['label', 195, 129]},
-                               {name: 'setTextAlign', args: ['right']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['footer', 195, 147]},
-                               {name: 'restore', args: []}
-                       ]));
-               });
-
-               it('Should center', function() {
-                       mockContext.resetCalls();
-                       Chart.helpers.merge(tooltip, makeView('center', 'center', 'center'));
-                       tooltip.draw(mockContext);
-
-                       expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
-                               {name: 'setTextAlign', args: ['center']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['title', 150, 111]},
-                               {name: 'setTextAlign', args: ['center']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'fillText', args: ['label', 150, 129]},
-                               {name: 'setTextAlign', args: ['center']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['footer', 150, 147]},
-                               {name: 'restore', args: []}
-                       ]));
-               });
-
-               it('Should allow mixed', function() {
-                       mockContext.resetCalls();
-                       Chart.helpers.merge(tooltip, makeView('right', 'center', 'left'));
-                       tooltip.draw(mockContext);
-
-                       expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
-                               {name: 'setTextAlign', args: ['right']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['title', 195, 111]},
-                               {name: 'setTextAlign', args: ['center']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'fillText', args: ['label', 150, 129]},
-                               {name: 'setTextAlign', args: ['left']},
-                               {name: 'setTextBaseline', args: ['middle']},
-                               {name: 'setFillStyle', args: ['#fff']},
-                               {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
-                               {name: 'fillText', args: ['footer', 105, 147]},
-                               {name: 'restore', args: []}
-                       ]));
-               });
-       });
-
-       describe('active events', function() {
-               it('should set the active events', function() {
-                       var chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               label: 'Dataset 1',
-                                               data: [10, 20, 30],
-                                               pointHoverBorderColor: 'rgb(255, 0, 0)',
-                                               pointHoverBackgroundColor: 'rgb(0, 255, 0)'
-                                       }],
-                                       labels: ['Point 1', 'Point 2', 'Point 3']
-                               },
-                       });
-
-                       const meta = chart.getDatasetMeta(0);
-                       chart.tooltip.setActiveElements([{datasetIndex: 0, index: 0}], {x: 0, y: 0});
-                       expect(chart.tooltip.getActiveElements()[0].element).toBe(meta.data[0]);
-               });
-       });
+  describe('auto', jasmine.fixture.specs('core.tooltip'));
+
+  describe('config', function() {
+    it('should not include the dataset label in the body string if not defined', function() {
+      var data = {
+        datasets: [{
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      };
+      var tooltipItem = {
+        index: 1,
+        datasetIndex: 0,
+        dataset: data.datasets[0],
+        label: 'Point 2',
+        formattedValue: '20'
+      };
+
+      var label = Chart.defaults.plugins.tooltip.callbacks.label(tooltipItem);
+      expect(label).toBe('20');
+
+      data.datasets[0].label = 'My dataset';
+      label = Chart.defaults.plugins.tooltip.callbacks.label(tooltipItem);
+      expect(label).toBe('My dataset: 20');
+    });
+  });
+
+  describe('index mode', function() {
+    it('Should only use x distance when intersect is false', function(done) {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+        options: {
+          plugins: {
+            tooltip: {
+              mode: 'index',
+              intersect: false,
+            }
+          },
+          hover: {
+            mode: 'index',
+            intersect: false
+          }
+        }
+      });
+
+      // Trigger an event over top of the
+      var meta = chart.getDatasetMeta(0);
+      var point = meta.data[1];
+
+      afterEvent(chart, 'mousemove', function() {
+        // Check and see if tooltip was displayed
+        var tooltip = chart.tooltip;
+        var defaults = Chart.defaults;
+
+        expect(tooltip.options.xPadding).toEqual(6);
+        expect(tooltip.options.yPadding).toEqual(6);
+        expect(tooltip.xAlign).toEqual('left');
+        expect(tooltip.yAlign).toEqual('center');
+        expect(tooltip.options.bodyColor).toEqual('#fff');
+
+        expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
+          family: defaults.font.family,
+          style: defaults.font.style,
+          size: defaults.font.size,
+        }));
+
+        expect(tooltip.options).toEqual(jasmine.objectContaining({
+          bodyAlign: 'left',
+          bodySpacing: 2,
+        }));
+
+        expect(tooltip.options.titleColor).toEqual('#fff');
+        expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
+          family: defaults.font.family,
+          style: 'bold',
+          size: defaults.font.size,
+        }));
+
+        expect(tooltip.options).toEqual(jasmine.objectContaining({
+          titleAlign: 'left',
+          titleSpacing: 2,
+          titleMarginBottom: 6,
+        }));
+
+        expect(tooltip.options.footerColor).toEqual('#fff');
+        expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
+          family: defaults.font.family,
+          style: 'bold',
+          size: defaults.font.size,
+        }));
+
+        expect(tooltip.options).toEqual(jasmine.objectContaining({
+          footerAlign: 'left',
+          footerSpacing: 2,
+          footerMarginTop: 6,
+        }));
+
+        expect(tooltip.options).toEqual(jasmine.objectContaining({
+          // Appearance
+          caretSize: 5,
+          caretPadding: 2,
+          cornerRadius: 6,
+          backgroundColor: 'rgba(0,0,0,0.8)',
+          multiKeyBackground: '#fff',
+          displayColors: true
+        }));
+
+        expect(tooltip).toEqual(jasmine.objectContaining({
+          opacity: 1,
+
+          // Text
+          title: ['Point 2'],
+          beforeBody: [],
+          body: [{
+            before: [],
+            lines: ['Dataset 1: 20'],
+            after: []
+          }, {
+            before: [],
+            lines: ['Dataset 2: 40'],
+            after: []
+          }],
+          afterBody: [],
+          footer: [],
+          labelColors: [{
+            borderColor: defaults.borderColor,
+            backgroundColor: defaults.backgroundColor
+          }, {
+            borderColor: defaults.borderColor,
+            backgroundColor: defaults.backgroundColor
+          }]
+        }));
+
+        expect(tooltip.x).toBeCloseToPixel(267);
+        expect(tooltip.y).toBeCloseToPixel(155);
+
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', {x: point.x, y: chart.chartArea.top + 10});
+    });
+
+    it('Should only display if intersecting if intersect is set', function(done) {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+        options: {
+          plugins: {
+            tooltip: {
+              mode: 'index',
+              intersect: true
+            }
+          }
+        }
+      });
+
+      // Trigger an event over top of the
+      var meta = chart.getDatasetMeta(0);
+      var point = meta.data[1];
+
+      afterEvent(chart, 'mousemove', function() {
+        // Check and see if tooltip was displayed
+        var tooltip = chart.tooltip;
+
+        expect(tooltip).toEqual(jasmine.objectContaining({
+          opacity: 0,
+        }));
+
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', {x: point.x, y: 0});
+    });
+  });
+
+  it('Should display in single mode', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'nearest',
+            intersect: true
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip.options.xPadding).toEqual(6);
+      expect(tooltip.options.yPadding).toEqual(6);
+      expect(tooltip.xAlign).toEqual('left');
+      expect(tooltip.yAlign).toEqual('center');
+
+      expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: defaults.font.style,
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        bodyAlign: 'left',
+        bodySpacing: 2,
+      }));
+
+      expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        titleAlign: 'left',
+        titleSpacing: 2,
+        titleMarginBottom: 6,
+      }));
+
+      expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        footerAlign: 'left',
+        footerSpacing: 2,
+        footerMarginTop: 6,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        // Appearance
+        caretSize: 5,
+        caretPadding: 2,
+        cornerRadius: 6,
+        backgroundColor: 'rgba(0,0,0,0.8)',
+        multiKeyBackground: '#fff',
+        displayColors: true
+      }));
+
+      expect(tooltip.opacity).toEqual(1);
+      expect(tooltip.title).toEqual(['Point 2']);
+      expect(tooltip.beforeBody).toEqual([]);
+      expect(tooltip.body).toEqual([{
+        before: [],
+        lines: ['Dataset 1: 20'],
+        after: []
+      }]);
+      expect(tooltip.afterBody).toEqual([]);
+      expect(tooltip.footer).toEqual([]);
+      expect(tooltip.labelTextColors).toEqual(['#fff']);
+
+      expect(tooltip.labelColors).toEqual([{
+        borderColor: defaults.borderColor,
+        backgroundColor: defaults.backgroundColor
+      }]);
+
+      expect(tooltip.x).toBeCloseToPixel(267);
+      expect(tooltip.y).toBeCloseToPixel(312);
+
+      done();
+    });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
+
+  it('Should display information from user callbacks', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            callbacks: {
+              beforeTitle: function() {
+                return 'beforeTitle';
+              },
+              title: function() {
+                return 'title';
+              },
+              afterTitle: function() {
+                return 'afterTitle';
+              },
+              beforeBody: function() {
+                return 'beforeBody';
+              },
+              beforeLabel: function() {
+                return 'beforeLabel';
+              },
+              label: function() {
+                return 'label';
+              },
+              afterLabel: function() {
+                return 'afterLabel';
+              },
+              afterBody: function() {
+                return 'afterBody';
+              },
+              beforeFooter: function() {
+                return 'beforeFooter';
+              },
+              footer: function() {
+                return 'footer';
+              },
+              afterFooter: function() {
+                return 'afterFooter';
+              },
+              labelTextColor: function() {
+                return 'labelTextColor';
+              },
+              labelPointStyle: function() {
+                return {
+                  pointStyle: 'labelPointStyle',
+                  rotation: 42
+                };
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip.options.xPadding).toEqual(6);
+      expect(tooltip.options.yPadding).toEqual(6);
+      expect(tooltip.xAlign).toEqual('left');
+      expect(tooltip.yAlign).toEqual('center');
+
+      expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: defaults.font.style,
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        bodyAlign: 'left',
+        bodySpacing: 2,
+      }));
+
+      expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        titleSpacing: 2,
+        titleMarginBottom: 6,
+      }));
+
+      expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        footerAlign: 'left',
+        footerSpacing: 2,
+        footerMarginTop: 6,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        // Appearance
+        caretSize: 5,
+        caretPadding: 2,
+        cornerRadius: 6,
+        backgroundColor: 'rgba(0,0,0,0.8)',
+        multiKeyBackground: '#fff',
+      }));
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        opacity: 1,
+
+        // Text
+        title: ['beforeTitle', 'title', 'afterTitle'],
+        beforeBody: ['beforeBody'],
+        body: [{
+          before: ['beforeLabel'],
+          lines: ['label'],
+          after: ['afterLabel']
+        }, {
+          before: ['beforeLabel'],
+          lines: ['label'],
+          after: ['afterLabel']
+        }],
+        afterBody: ['afterBody'],
+        footer: ['beforeFooter', 'footer', 'afterFooter'],
+        labelTextColors: ['labelTextColor', 'labelTextColor'],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }, {
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }],
+        labelPointStyles: [{
+          pointStyle: 'labelPointStyle',
+          rotation: 42
+        }, {
+          pointStyle: 'labelPointStyle',
+          rotation: 42
+        }]
+      }));
+
+      expect(tooltip.x).toBeCloseToPixel(267);
+      expect(tooltip.y).toBeCloseToPixel(75);
+
+      done();
+    });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
+
+
+  it('Should provide context object to user callbacks', function(done) {
+    const chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [{x: 1, y: 10}, {x: 2, y: 20}, {x: 3, y: 30}]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear'
+          }
+        },
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            callbacks: {
+              beforeLabel: function(ctx) {
+                return ctx.parsed.x + ',' + ctx.parsed.y;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    const meta = chart.getDatasetMeta(0);
+    const point = meta.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      const tooltip = chart.tooltip;
+
+      expect(tooltip.body[0].before).toEqual(['2,20']);
+
+      done();
+    });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
+
+  it('Should allow sorting items', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            itemSort: function(a, b) {
+              return a.datasetIndex > b.datasetIndex ? -1 : 1;
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta0 = chart.getDatasetMeta(0);
+    var point0 = meta0.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        // Positioning
+        xAlign: 'left',
+        yAlign: 'center',
+
+        // Text
+        title: ['Point 2'],
+        beforeBody: [],
+        body: [{
+          before: [],
+          lines: ['Dataset 2: 40'],
+          after: []
+        }, {
+          before: [],
+          lines: ['Dataset 1: 20'],
+          after: []
+        }],
+        afterBody: [],
+        footer: [],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }, {
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }]
+      }));
+
+      expect(tooltip.x).toBeCloseToPixel(267);
+      expect(tooltip.y).toBeCloseToPixel(155);
+
+      done();
+    });
+    jasmine.triggerMouseEvent(chart, 'mousemove', point0);
+
+  });
+
+  it('Should allow reversing items', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            reverse: true
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta0 = chart.getDatasetMeta(0);
+    var point0 = meta0.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        // Positioning
+        xAlign: 'left',
+        yAlign: 'center',
+
+        // Text
+        title: ['Point 2'],
+        beforeBody: [],
+        body: [{
+          before: [],
+          lines: ['Dataset 2: 40'],
+          after: []
+        }, {
+          before: [],
+          lines: ['Dataset 1: 20'],
+          after: []
+        }],
+        afterBody: [],
+        footer: [],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }, {
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }]
+      }));
+
+      expect(tooltip.x).toBeCloseToPixel(267);
+      expect(tooltip.y).toBeCloseToPixel(155);
+
+      done();
+    });
+
+    jasmine.triggerMouseEvent(chart, 'mousemove', point0);
+  });
+
+  it('Should follow dataset order', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)',
+          order: 10
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)',
+          order: 5
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index'
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta0 = chart.getDatasetMeta(0);
+    var point0 = meta0.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        // Positioning
+        xAlign: 'left',
+        yAlign: 'center',
+
+        // Text
+        title: ['Point 2'],
+        beforeBody: [],
+        body: [{
+          before: [],
+          lines: ['Dataset 2: 40'],
+          after: []
+        }, {
+          before: [],
+          lines: ['Dataset 1: 20'],
+          after: []
+        }],
+        afterBody: [],
+        footer: [],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }, {
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }]
+      }));
+
+      expect(tooltip.x).toBeCloseToPixel(267);
+      expect(tooltip.y).toBeCloseToPixel(155);
+
+      done();
+    });
+
+    jasmine.triggerMouseEvent(chart, 'mousemove', point0);
+  });
+
+  it('should filter items from the tooltip using the callback', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)',
+          tooltipHidden: true
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            filter: function(tooltipItem, index, tooltipItems, data) {
+              // For testing purposes remove the first dataset that has a tooltipHidden property
+              return !data.datasets[tooltipItem.datasetIndex].tooltipHidden;
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta0 = chart.getDatasetMeta(0);
+    var point0 = meta0.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        // Positioning
+        xAlign: 'left',
+        yAlign: 'center',
+
+        // Text
+        title: ['Point 2'],
+        beforeBody: [],
+        body: [{
+          before: [],
+          lines: ['Dataset 2: 40'],
+          after: []
+        }],
+        afterBody: [],
+        footer: [],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }]
+      }));
+
+      done();
+    });
+
+    jasmine.triggerMouseEvent(chart, 'mousemove', point0);
+  });
+
+  it('should set the caretPadding based on a config setting', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)',
+          tooltipHidden: true
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            caretPadding: 10
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta0 = chart.getDatasetMeta(0);
+    var point0 = meta0.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        // Positioning
+        caretPadding: 10,
+      }));
+
+      done();
+    });
+
+    jasmine.triggerMouseEvent(chart, 'mousemove', point0);
+  });
+
+  ['line', 'bar'].forEach(function(type) {
+    it('Should have dataPoints in a ' + type + ' chart', function(done) {
+      var chart = window.acquireChart({
+        type: type,
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+        options: {
+          plugins: {
+            tooltip: {
+              mode: 'nearest',
+              intersect: true
+            }
+          }
+        }
+      });
+
+      // Trigger an event over top of the element
+      var pointIndex = 1;
+      var datasetIndex = 0;
+      var point = chart.getDatasetMeta(datasetIndex).data[pointIndex];
+
+      afterEvent(chart, 'mousemove', function() {
+        // Check and see if tooltip was displayed
+        var tooltip = chart.tooltip;
+
+        expect(tooltip instanceof Object).toBe(true);
+        expect(tooltip.dataPoints instanceof Array).toBe(true);
+        expect(tooltip.dataPoints.length).toBe(1);
+
+        var tooltipItem = tooltip.dataPoints[0];
+
+        expect(tooltipItem.dataIndex).toBe(pointIndex);
+        expect(tooltipItem.datasetIndex).toBe(datasetIndex);
+        expect(typeof tooltipItem.label).toBe('string');
+        expect(tooltipItem.label).toBe(chart.data.labels[pointIndex]);
+        expect(typeof tooltipItem.formattedValue).toBe('string');
+        expect(tooltipItem.formattedValue).toBe('' + chart.data.datasets[datasetIndex].data[pointIndex]);
+
+        done();
+      });
+
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
+
+  it('Should not update if active element has not changed', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'nearest',
+            intersect: true,
+            callbacks: {
+              title: function() {
+                return 'registering callback...';
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta = chart.getDatasetMeta(0);
+    var firstPoint = meta.data[1];
+
+    var tooltip = chart.tooltip;
+    spyOn(tooltip, 'update').and.callThrough();
+
+    afterEvent(chart, 'mousemove', function() {
+      expect(tooltip.update).toHaveBeenCalledWith(true);
+
+      // Reset calls
+      tooltip.update.calls.reset();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(tooltip.update).not.toHaveBeenCalled();
+
+        done();
+      });
+      // Second dispatch change event (same event), should not update tooltip
+      jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
+    });
+    // First dispatch change event, should update tooltip
+    jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
+  });
+
+  it('Should update if active elements are the same, but the position has changed', function(done) {
+    const chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        scales: {
+          x: {
+            stacked: true,
+          },
+          y: {
+            stacked: true
+          }
+        },
+        plugins: {
+          tooltip: {
+            mode: 'nearest',
+            position: 'nearest',
+            intersect: true,
+            callbacks: {
+              title: function() {
+                return 'registering callback...';
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    const meta = chart.getDatasetMeta(0);
+    const firstPoint = meta.data[1];
+
+    const meta2 = chart.getDatasetMeta(1);
+    const secondPoint = meta2.data[1];
+
+    const tooltip = chart.tooltip;
+    spyOn(tooltip, 'update');
+
+    afterEvent(chart, 'mousemove', function() {
+      expect(tooltip.update).toHaveBeenCalledWith(true);
+
+      // Reset calls
+      tooltip.update.calls.reset();
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(tooltip.update).toHaveBeenCalledWith(true);
+
+        done();
+      });
+      // Second dispatch change event (same event), should update tooltip
+      // because position mode is 'nearest'
+      jasmine.triggerMouseEvent(chart, 'mousemove', secondPoint);
+    });
+    // First dispatch change event, should update tooltip
+    jasmine.triggerMouseEvent(chart, 'mousemove', firstPoint);
+  });
+
+  describe('positioners', function() {
+    it('Should call custom positioner with correct parameters and scope', function(done) {
+
+      tooltipPlugin.positioners.test = function() {
+        return {x: 0, y: 0};
+      };
+
+      spyOn(tooltipPlugin.positioners, 'test').and.callThrough();
+
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }, {
+            label: 'Dataset 2',
+            data: [40, 40, 40],
+            pointHoverBorderColor: 'rgb(0, 0, 255)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+        options: {
+          plugins: {
+            tooltip: {
+              mode: 'nearest',
+              position: 'test'
+            }
+          }
+        }
+      });
+
+      // Trigger an event over top of the
+      var pointIndex = 1;
+      var datasetIndex = 0;
+      var meta = chart.getDatasetMeta(datasetIndex);
+      var point = meta.data[pointIndex];
+      var fn = tooltipPlugin.positioners.test;
+
+      afterEvent(chart, 'mousemove', function() {
+        expect(fn.calls.count()).toBe(2);
+        expect(fn.calls.first().args[0] instanceof Array).toBe(true);
+        expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'x')).toBe(true);
+        expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'y')).toBe(true);
+        expect(fn.calls.first().object instanceof Tooltip).toBe(true);
+
+        done();
+      });
+      jasmine.triggerMouseEvent(chart, 'mousemove', point);
+    });
+  });
+
+  it('Should avoid tooltip truncation in x axis if there is enough space to show tooltip without truncation', function(done) {
+    var chart = window.acquireChart({
+      type: 'pie',
+      data: {
+        datasets: [{
+          data: [
+            50,
+            50
+          ],
+          backgroundColor: [
+            'rgb(255, 0, 0)',
+            'rgb(0, 255, 0)'
+          ],
+          label: 'Dataset 1'
+        }],
+        labels: [
+          'Red long tooltip text to avoid unnecessary loop steps',
+          'Green long tooltip text to avoid unnecessary loop steps'
+        ]
+      },
+      options: {
+        responsive: true,
+        animation: {
+          // without this slice center point is calculated wrong
+          animateRotate: false
+        },
+        plugins: {
+          tooltip: {
+            animation: false
+          }
+        }
+      }
+    });
+
+    function testSlice(slice, count) {
+      var meta = chart.getDatasetMeta(0);
+      var point = meta.data[slice].getCenterPoint();
+      var tooltipPosition = meta.data[slice].tooltipPosition();
+
+      function recursive(left) {
+        chart.config.data.labels[slice] = chart.config.data.labels[slice] + 'XX';
+        chart.update();
+
+        afterEvent(chart, 'mouseout', function() {
+          afterEvent(chart, 'mousemove', function() {
+            var tooltip = chart.tooltip;
+            expect(tooltip.dataPoints.length).toBe(1);
+            expect(tooltip.x).toBeGreaterThanOrEqual(0);
+            if (tooltip.width <= chart.width) {
+              expect(tooltip.x + tooltip.width).toBeLessThanOrEqual(chart.width);
+            }
+            expect(tooltip.caretX).toBeCloseToPixel(tooltipPosition.x);
+            // if tooltip is longer than chart area then all tests done
+            if (tooltip.width > chart.width || left === 0) {
+              done(left === 0 && new Error('max iterations reached'));
+            } else {
+              recursive(left - 1);
+            }
+          });
+          jasmine.triggerMouseEvent(chart, 'mousemove', point);
+        });
+
+        jasmine.triggerMouseEvent(chart, 'mouseout', point);
+      }
+
+      recursive(count);
+    }
+
+    // Trigger an event over top of the slice
+    for (var slice = 0; slice < 2; slice++) {
+      testSlice(slice, 20);
+    }
+  });
+
+  it('Should split newlines into separate lines in user callbacks', function(done) {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          label: 'Dataset 1',
+          data: [10, 20, 30],
+          pointHoverBorderColor: 'rgb(255, 0, 0)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          label: 'Dataset 2',
+          data: [40, 40, 40],
+          pointHoverBorderColor: 'rgb(0, 0, 255)',
+          pointHoverBackgroundColor: 'rgb(0, 255, 255)'
+        }],
+        labels: ['Point 1', 'Point 2', 'Point 3']
+      },
+      options: {
+        plugins: {
+          tooltip: {
+            mode: 'index',
+            callbacks: {
+              beforeTitle: function() {
+                return 'beforeTitle\nnewline';
+              },
+              title: function() {
+                return 'title\nnewline';
+              },
+              afterTitle: function() {
+                return 'afterTitle\nnewline';
+              },
+              beforeBody: function() {
+                return 'beforeBody\nnewline';
+              },
+              beforeLabel: function() {
+                return 'beforeLabel\nnewline';
+              },
+              label: function() {
+                return 'label';
+              },
+              afterLabel: function() {
+                return 'afterLabel\nnewline';
+              },
+              afterBody: function() {
+                return 'afterBody\nnewline';
+              },
+              beforeFooter: function() {
+                return 'beforeFooter\nnewline';
+              },
+              footer: function() {
+                return 'footer\nnewline';
+              },
+              afterFooter: function() {
+                return 'afterFooter\nnewline';
+              },
+              labelTextColor: function() {
+                return 'labelTextColor';
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Trigger an event over top of the
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[1];
+
+    afterEvent(chart, 'mousemove', function() {
+      // Check and see if tooltip was displayed
+      var tooltip = chart.tooltip;
+      var defaults = Chart.defaults;
+
+      expect(tooltip.options.xPadding).toEqual(6);
+      expect(tooltip.options.yPadding).toEqual(6);
+      expect(tooltip.xAlign).toEqual('center');
+      expect(tooltip.yAlign).toEqual('top');
+
+      expect(tooltip.options.bodyFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: defaults.font.style,
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        bodyAlign: 'left',
+        bodySpacing: 2,
+      }));
+
+      expect(tooltip.options.titleFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        titleAlign: 'left',
+        titleSpacing: 2,
+        titleMarginBottom: 6,
+      }));
+
+      expect(tooltip.options.footerFont).toEqual(jasmine.objectContaining({
+        family: defaults.font.family,
+        style: 'bold',
+        size: defaults.font.size,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        footerAlign: 'left',
+        footerSpacing: 2,
+        footerMarginTop: 6,
+      }));
+
+      expect(tooltip.options).toEqual(jasmine.objectContaining({
+        // Appearance
+        caretSize: 5,
+        caretPadding: 2,
+        cornerRadius: 6,
+        backgroundColor: 'rgba(0,0,0,0.8)',
+        multiKeyBackground: '#fff',
+      }));
+
+      expect(tooltip).toEqual(jasmine.objectContaining({
+        opacity: 1,
+
+        // Text
+        title: ['beforeTitle', 'newline', 'title', 'newline', 'afterTitle', 'newline'],
+        beforeBody: ['beforeBody', 'newline'],
+        body: [{
+          before: ['beforeLabel', 'newline'],
+          lines: ['label'],
+          after: ['afterLabel', 'newline']
+        }, {
+          before: ['beforeLabel', 'newline'],
+          lines: ['label'],
+          after: ['afterLabel', 'newline']
+        }],
+        afterBody: ['afterBody', 'newline'],
+        footer: ['beforeFooter', 'newline', 'footer', 'newline', 'afterFooter', 'newline'],
+        labelTextColors: ['labelTextColor', 'labelTextColor'],
+        labelColors: [{
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }, {
+          borderColor: defaults.borderColor,
+          backgroundColor: defaults.backgroundColor
+        }]
+      }));
+
+      done();
+    });
+
+    jasmine.triggerMouseEvent(chart, 'mousemove', point);
+  });
+
+  describe('text align', function() {
+    var defaults = Chart.defaults;
+    var makeView = function(title, body, footer) {
+      return {
+        // Positioning
+        x: 100,
+        y: 100,
+        width: 100,
+        height: 100,
+        xAlign: 'left',
+        yAlign: 'top',
+
+        options: {
+          enabled: true,
+
+          xPadding: 5,
+          yPadding: 5,
+
+          // Body
+          bodyFont: {
+            family: defaults.font.family,
+            style: defaults.font.style,
+            size: defaults.font.size,
+          },
+          bodyColor: '#fff',
+          bodyAlign: body,
+          bodySpacing: 2,
+
+          // Title
+          titleFont: {
+            family: defaults.font.family,
+            style: 'bold',
+            size: defaults.font.size,
+          },
+          titleColor: '#fff',
+          titleAlign: title,
+          titleSpacing: 2,
+          titleMarginBottom: 6,
+
+          // Footer
+          footerFont: {
+            family: defaults.font.family,
+            style: 'bold',
+            size: defaults.font.size,
+          },
+          footerColor: '#fff',
+          footerAlign: footer,
+          footerSpacing: 2,
+          footerMarginTop: 6,
+
+          // Appearance
+          caretSize: 5,
+          cornerRadius: 6,
+          caretPadding: 2,
+          borderColor: '#aaa',
+          borderWidth: 1,
+          backgroundColor: 'rgba(0,0,0,0.8)',
+          multiKeyBackground: '#fff',
+          displayColors: false
+
+        },
+        opacity: 1,
+
+        // Text
+        title: ['title'],
+        beforeBody: [],
+        body: [{
+          before: [],
+          lines: ['label'],
+          after: []
+        }],
+        afterBody: [],
+        footer: ['footer'],
+        labelTextColors: ['#fff'],
+        labelColors: [{
+          borderColor: 'rgb(255, 0, 0)',
+          backgroundColor: 'rgb(0, 255, 0)'
+        }, {
+          borderColor: 'rgb(0, 0, 255)',
+          backgroundColor: 'rgb(0, 255, 255)'
+        }]
+      };
+    };
+    var drawBody = [
+      {name: 'save', args: []},
+      {name: 'setFillStyle', args: ['rgba(0,0,0,0.8)']},
+      {name: 'setStrokeStyle', args: ['#aaa']},
+      {name: 'setLineWidth', args: [1]},
+      {name: 'beginPath', args: []},
+      {name: 'moveTo', args: [106, 100]},
+      {name: 'lineTo', args: [106, 100]},
+      {name: 'lineTo', args: [111, 95]},
+      {name: 'lineTo', args: [116, 100]},
+      {name: 'lineTo', args: [194, 100]},
+      {name: 'quadraticCurveTo', args: [200, 100, 200, 106]},
+      {name: 'lineTo', args: [200, 194]},
+      {name: 'quadraticCurveTo', args: [200, 200, 194, 200]},
+      {name: 'lineTo', args: [106, 200]},
+      {name: 'quadraticCurveTo', args: [100, 200, 100, 194]},
+      {name: 'lineTo', args: [100, 106]},
+      {name: 'quadraticCurveTo', args: [100, 100, 106, 100]},
+      {name: 'closePath', args: []},
+      {name: 'fill', args: []},
+      {name: 'stroke', args: []}
+    ];
+
+    var mockContext = window.createMockContext();
+    var tooltip = new Tooltip({
+      _chart: {
+        options: {
+          plugins: {
+            tooltip: {
+              animation: false,
+            }
+          }
+        }
+      }
+    });
+
+    it('Should go left', function() {
+      mockContext.resetCalls();
+      Chart.helpers.merge(tooltip, makeView('left', 'left', 'left'));
+      tooltip.draw(mockContext);
+
+      expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+        {name: 'setTextAlign', args: ['left']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['title', 105, 111]},
+        {name: 'setTextAlign', args: ['left']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'fillText', args: ['label', 105, 129]},
+        {name: 'setTextAlign', args: ['left']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['footer', 105, 147]},
+        {name: 'restore', args: []}
+      ]));
+    });
+
+    it('Should go right', function() {
+      mockContext.resetCalls();
+      Chart.helpers.merge(tooltip, makeView('right', 'right', 'right'));
+      tooltip.draw(mockContext);
+
+      expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+        {name: 'setTextAlign', args: ['right']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['title', 195, 111]},
+        {name: 'setTextAlign', args: ['right']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'fillText', args: ['label', 195, 129]},
+        {name: 'setTextAlign', args: ['right']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['footer', 195, 147]},
+        {name: 'restore', args: []}
+      ]));
+    });
+
+    it('Should center', function() {
+      mockContext.resetCalls();
+      Chart.helpers.merge(tooltip, makeView('center', 'center', 'center'));
+      tooltip.draw(mockContext);
+
+      expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+        {name: 'setTextAlign', args: ['center']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['title', 150, 111]},
+        {name: 'setTextAlign', args: ['center']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'fillText', args: ['label', 150, 129]},
+        {name: 'setTextAlign', args: ['center']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['footer', 150, 147]},
+        {name: 'restore', args: []}
+      ]));
+    });
+
+    it('Should allow mixed', function() {
+      mockContext.resetCalls();
+      Chart.helpers.merge(tooltip, makeView('right', 'center', 'left'));
+      tooltip.draw(mockContext);
+
+      expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
+        {name: 'setTextAlign', args: ['right']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['title', 195, 111]},
+        {name: 'setTextAlign', args: ['center']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFont', args: ["normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'fillText', args: ['label', 150, 129]},
+        {name: 'setTextAlign', args: ['left']},
+        {name: 'setTextBaseline', args: ['middle']},
+        {name: 'setFillStyle', args: ['#fff']},
+        {name: 'setFont', args: ["bold 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"]},
+        {name: 'fillText', args: ['footer', 105, 147]},
+        {name: 'restore', args: []}
+      ]));
+    });
+  });
+
+  describe('active events', function() {
+    it('should set the active events', function() {
+      var chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            label: 'Dataset 1',
+            data: [10, 20, 30],
+            pointHoverBorderColor: 'rgb(255, 0, 0)',
+            pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+          }],
+          labels: ['Point 1', 'Point 2', 'Point 3']
+        },
+      });
+
+      const meta = chart.getDatasetMeta(0);
+      chart.tooltip.setActiveElements([{datasetIndex: 0, index: 0}], {x: 0, y: 0});
+      expect(chart.tooltip.getActiveElements()[0].element).toBe(meta.data[0]);
+    });
+  });
 });
index 884627af6ab7c3c7676d140093fed34b2abfc13e..5fc3872e1a2391e534f61dfb5e80d43a1a229497 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Category scale tests', function() {
-       describe('auto', jasmine.fixture.specs('scale.category'));
-
-       it('Should register the constructor with the registry', function() {
-               var Constructor = Chart.registry.getScale('category');
-               expect(Constructor).not.toBe(undefined);
-               expect(typeof Constructor).toBe('function');
-       });
-
-       it('Should have the correct default config', function() {
-               var defaultConfig = Chart.defaults.scales.category;
-               expect(defaultConfig).toEqual({
-                       ticks: {
-                               callback: Chart.registry.getScale('category').prototype.getLabelForValue
-                       }
-               });
-       });
-
-
-       it('Should generate ticks from the data xLabels', function() {
-               var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               xLabels: labels,
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.x;
-               expect(getLabels(scale)).toEqual(labels);
-       });
-
-       it('Should generate ticks from the data yLabels', function() {
-               var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               yLabels: labels,
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'category'
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.y;
-               expect(getLabels(scale)).toEqual(labels);
-       });
-
-       it('Should generate ticks from the axis labels', function() {
-               var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               labels: labels
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.x;
-               expect(getLabels(scale)).toEqual(labels);
-       });
-
-       it('Should generate missing labels', function() {
-               var labels = ['a', 'b', 'c', 'd'];
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: {a: 1, b: 3, c: -1, d: 10}
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               labels: ['a']
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.x;
-               expect(getLabels(scale)).toEqual(labels);
-
-       });
-
-       it('should get the correct label for the index', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.x;
-
-               expect(scale.getLabelForValue(1)).toBe('tick2');
-       });
-
-       it('Should get the correct pixel for a value when horizontal', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue(0)).toBeCloseToPixel(23 + 6); // plus lineHeight
-               expect(xScale.getValueForPixel(23)).toBe(0);
-
-               expect(xScale.getPixelForValue(4)).toBeCloseToPixel(487);
-               expect(xScale.getValueForPixel(487)).toBe(4);
-
-               xScale.options.offset = true;
-               chart.update();
-
-               expect(xScale.getPixelForValue(0)).toBeCloseToPixel(71 + 6); // plus lineHeight
-               expect(xScale.getValueForPixel(69)).toBe(0);
-
-               expect(xScale.getPixelForValue(4)).toBeCloseToPixel(461);
-               expect(xScale.getValueForPixel(417)).toBe(4);
-       });
-
-       it('Should get the correct pixel for a value when there are repeated labels', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue('tick1')).toBeCloseToPixel(23 + 6); // plus lineHeight
-       });
-
-       it('Should get the correct pixel for a value when horizontal and zoomed', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom',
-                                               min: 'tick2',
-                                               max: 'tick4'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue(1)).toBeCloseToPixel(23 + 6); // plus lineHeight
-               expect(xScale.getPixelForValue(3)).toBeCloseToPixel(496);
-
-               xScale.options.offset = true;
-               chart.update();
-
-               expect(xScale.getPixelForValue(1)).toBeCloseToPixel(103 + 6); // plus lineHeight
-               expect(xScale.getPixelForValue(3)).toBeCloseToPixel(429);
-       });
-
-       it('should get the correct pixel for a value when vertical', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: ['3', '5', '1', '4', '2']
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-                               yLabels: ['1', '2', '3', '4', '5']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom',
-                                       },
-                                       y: {
-                                               type: 'category',
-                                               position: 'left'
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-               expect(yScale.getPixelForValue(0)).toBeCloseToPixel(32);
-               expect(yScale.getValueForPixel(257)).toBe(2);
-
-               expect(yScale.getPixelForValue(4)).toBeCloseToPixel(481);
-               expect(yScale.getValueForPixel(144)).toBe(1);
-
-               yScale.options.offset = true;
-               chart.update();
-
-               expect(yScale.getPixelForValue(0)).toBeCloseToPixel(77);
-               expect(yScale.getValueForPixel(256)).toBe(2);
-
-               expect(yScale.getPixelForValue(4)).toBeCloseToPixel(436);
-               expect(yScale.getValueForPixel(167)).toBe(1);
-       });
-
-       it('should get the correct pixel for a value when vertical and zoomed', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: ['3', '5', '1', '4', '2']
-                               }],
-                               labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
-                               yLabels: ['1', '2', '3', '4', '5']
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom',
-                                       },
-                                       y: {
-                                               type: 'category',
-                                               position: 'left',
-                                               min: '2',
-                                               max: '4'
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-
-               expect(yScale.getPixelForValue(1)).toBeCloseToPixel(32);
-               expect(yScale.getPixelForValue(3)).toBeCloseToPixel(482);
-
-               yScale.options.offset = true;
-               chart.update();
-
-               expect(yScale.getPixelForValue(1)).toBeCloseToPixel(107);
-               expect(yScale.getPixelForValue(3)).toBeCloseToPixel(407);
-       });
-
-       it('Should get the correct pixel for an object value when horizontal', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [
-                                               {x: 0, y: 10},
-                                               {x: 1, y: 5},
-                                               {x: 2, y: 0},
-                                               {x: 3, y: 25},
-                                               {x: 0, y: 78}
-                                       ]
-                               }],
-                               labels: [0, 1, 2, 3]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue(0)).toBeCloseToPixel(29);
-               expect(xScale.getPixelForValue(3)).toBeCloseToPixel(506);
-               expect(xScale.getPixelForValue(4)).toBeCloseToPixel(664);
-       });
-
-       it('Should get the correct pixel for an object value when vertical', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [
-                                               {x: 0, y: 2},
-                                               {x: 1, y: 4},
-                                               {x: 2, y: 0},
-                                               {x: 3, y: 3},
-                                               {x: 0, y: 1}
-                                       ]
-                               }],
-                               labels: [0, 1, 2, 3],
-                               yLabels: [0, 1, 2, 3, 4]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'category',
-                                               position: 'left'
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-               expect(yScale.getPixelForValue(0)).toBeCloseToPixel(32);
-               expect(yScale.getPixelForValue(4)).toBeCloseToPixel(481);
-       });
-
-       it('Should get the correct pixel for an object value in a bar chart', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [
-                                               {x: 0, y: 10},
-                                               {x: 1, y: 5},
-                                               {x: 2, y: 0},
-                                               {x: 3, y: 25},
-                                               {x: 0, y: 78}
-                                       ]
-                               }],
-                               labels: [0, 1, 2, 3]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue(0)).toBeCloseToPixel(89);
-               expect(xScale.getPixelForValue(3)).toBeCloseToPixel(449);
-               expect(xScale.getPixelForValue(4)).toBeCloseToPixel(569);
-       });
-
-       it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [
-                                               {x: 10, y: 0},
-                                               {x: 5, y: 1},
-                                               {x: 0, y: 2},
-                                               {x: 25, y: 3},
-                                               {x: 78, y: 0}
-                                       ]
-                               }],
-                               labels: [0, 1, 2, 3]
-                       },
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'category'
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-               expect(yScale.getPixelForValue(0)).toBeCloseToPixel(88);
-               expect(yScale.getPixelForValue(3)).toBeCloseToPixel(426);
-               expect(yScale.getPixelForValue(4)).toBeCloseToPixel(538);
-       });
-
-       it('Should be consistent on pixels and values with autoSkipped ticks', function() {
-               var labels = [];
-               for (let i = 0; i < 50; i++) {
-                       labels.push('very long label ' + i);
-               }
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               labels,
-                               datasets: [{
-                                       data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-                               }]
-                       }
-               });
-
-               var scale = chart.scales.x;
-               expect(scale.ticks.length).toBeLessThan(50);
-
-               let x = 0;
-               for (let i = 0; i < 50; i++) {
-                       var x2 = scale.getPixelForValue(labels[i]);
-                       var x3 = scale.getPixelForValue(i);
-                       expect(x2).toEqual(x3);
-                       expect(x2).toBeGreaterThan(x);
-                       expect(scale.getValueForPixel(x2)).toBe(i);
-                       x = x2;
-               }
-       });
-
-       it('Should bound to ticks/data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['a', 'b', 'c', 'd'],
-                               datasets: [{
-                                       data: {b: 1, c: 99}
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'category',
-                                               bounds: 'data'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.min).toEqual(1);
-               expect(chart.scales.x.max).toEqual(2);
-
-               chart.options.scales.x.bounds = 'ticks';
-               chart.update();
-
-               expect(chart.scales.x.min).toEqual(0);
-               expect(chart.scales.x.max).toEqual(3);
-       });
+  describe('auto', jasmine.fixture.specs('scale.category'));
+
+  it('Should register the constructor with the registry', function() {
+    var Constructor = Chart.registry.getScale('category');
+    expect(Constructor).not.toBe(undefined);
+    expect(typeof Constructor).toBe('function');
+  });
+
+  it('Should have the correct default config', function() {
+    var defaultConfig = Chart.defaults.scales.category;
+    expect(defaultConfig).toEqual({
+      ticks: {
+        callback: Chart.registry.getScale('category').prototype.getLabelForValue
+      }
+    });
+  });
+
+
+  it('Should generate ticks from the data xLabels', function() {
+    var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        xLabels: labels,
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.x;
+    expect(getLabels(scale)).toEqual(labels);
+  });
+
+  it('Should generate ticks from the data yLabels', function() {
+    var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        yLabels: labels,
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'category'
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.y;
+    expect(getLabels(scale)).toEqual(labels);
+  });
+
+  it('Should generate ticks from the axis labels', function() {
+    var labels = ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'];
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            labels: labels
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.x;
+    expect(getLabels(scale)).toEqual(labels);
+  });
+
+  it('Should generate missing labels', function() {
+    var labels = ['a', 'b', 'c', 'd'];
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: {a: 1, b: 3, c: -1, d: 10}
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            labels: ['a']
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.x;
+    expect(getLabels(scale)).toEqual(labels);
+
+  });
+
+  it('should get the correct label for the index', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.x;
+
+    expect(scale.getLabelForValue(1)).toBe('tick2');
+  });
+
+  it('Should get the correct pixel for a value when horizontal', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue(0)).toBeCloseToPixel(23 + 6); // plus lineHeight
+    expect(xScale.getValueForPixel(23)).toBe(0);
+
+    expect(xScale.getPixelForValue(4)).toBeCloseToPixel(487);
+    expect(xScale.getValueForPixel(487)).toBe(4);
+
+    xScale.options.offset = true;
+    chart.update();
+
+    expect(xScale.getPixelForValue(0)).toBeCloseToPixel(71 + 6); // plus lineHeight
+    expect(xScale.getValueForPixel(69)).toBe(0);
+
+    expect(xScale.getPixelForValue(4)).toBeCloseToPixel(461);
+    expect(xScale.getValueForPixel(417)).toBe(4);
+  });
+
+  it('Should get the correct pixel for a value when there are repeated labels', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue('tick1')).toBeCloseToPixel(23 + 6); // plus lineHeight
+  });
+
+  it('Should get the correct pixel for a value when horizontal and zoomed', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick_last']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom',
+            min: 'tick2',
+            max: 'tick4'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue(1)).toBeCloseToPixel(23 + 6); // plus lineHeight
+    expect(xScale.getPixelForValue(3)).toBeCloseToPixel(496);
+
+    xScale.options.offset = true;
+    chart.update();
+
+    expect(xScale.getPixelForValue(1)).toBeCloseToPixel(103 + 6); // plus lineHeight
+    expect(xScale.getPixelForValue(3)).toBeCloseToPixel(429);
+  });
+
+  it('should get the correct pixel for a value when vertical', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: ['3', '5', '1', '4', '2']
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+        yLabels: ['1', '2', '3', '4', '5']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom',
+          },
+          y: {
+            type: 'category',
+            position: 'left'
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+    expect(yScale.getPixelForValue(0)).toBeCloseToPixel(32);
+    expect(yScale.getValueForPixel(257)).toBe(2);
+
+    expect(yScale.getPixelForValue(4)).toBeCloseToPixel(481);
+    expect(yScale.getValueForPixel(144)).toBe(1);
+
+    yScale.options.offset = true;
+    chart.update();
+
+    expect(yScale.getPixelForValue(0)).toBeCloseToPixel(77);
+    expect(yScale.getValueForPixel(256)).toBe(2);
+
+    expect(yScale.getPixelForValue(4)).toBeCloseToPixel(436);
+    expect(yScale.getValueForPixel(167)).toBe(1);
+  });
+
+  it('should get the correct pixel for a value when vertical and zoomed', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: ['3', '5', '1', '4', '2']
+        }],
+        labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5'],
+        yLabels: ['1', '2', '3', '4', '5']
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom',
+          },
+          y: {
+            type: 'category',
+            position: 'left',
+            min: '2',
+            max: '4'
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+
+    expect(yScale.getPixelForValue(1)).toBeCloseToPixel(32);
+    expect(yScale.getPixelForValue(3)).toBeCloseToPixel(482);
+
+    yScale.options.offset = true;
+    chart.update();
+
+    expect(yScale.getPixelForValue(1)).toBeCloseToPixel(107);
+    expect(yScale.getPixelForValue(3)).toBeCloseToPixel(407);
+  });
+
+  it('Should get the correct pixel for an object value when horizontal', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [
+            {x: 0, y: 10},
+            {x: 1, y: 5},
+            {x: 2, y: 0},
+            {x: 3, y: 25},
+            {x: 0, y: 78}
+          ]
+        }],
+        labels: [0, 1, 2, 3]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue(0)).toBeCloseToPixel(29);
+    expect(xScale.getPixelForValue(3)).toBeCloseToPixel(506);
+    expect(xScale.getPixelForValue(4)).toBeCloseToPixel(664);
+  });
+
+  it('Should get the correct pixel for an object value when vertical', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [
+            {x: 0, y: 2},
+            {x: 1, y: 4},
+            {x: 2, y: 0},
+            {x: 3, y: 3},
+            {x: 0, y: 1}
+          ]
+        }],
+        labels: [0, 1, 2, 3],
+        yLabels: [0, 1, 2, 3, 4]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'category',
+            position: 'left'
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+    expect(yScale.getPixelForValue(0)).toBeCloseToPixel(32);
+    expect(yScale.getPixelForValue(4)).toBeCloseToPixel(481);
+  });
+
+  it('Should get the correct pixel for an object value in a bar chart', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [
+            {x: 0, y: 10},
+            {x: 1, y: 5},
+            {x: 2, y: 0},
+            {x: 3, y: 25},
+            {x: 0, y: 78}
+          ]
+        }],
+        labels: [0, 1, 2, 3]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue(0)).toBeCloseToPixel(89);
+    expect(xScale.getPixelForValue(3)).toBeCloseToPixel(449);
+    expect(xScale.getPixelForValue(4)).toBeCloseToPixel(569);
+  });
+
+  it('Should get the correct pixel for an object value in a horizontal bar chart', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [
+            {x: 10, y: 0},
+            {x: 5, y: 1},
+            {x: 0, y: 2},
+            {x: 25, y: 3},
+            {x: 78, y: 0}
+          ]
+        }],
+        labels: [0, 1, 2, 3]
+      },
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'category'
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+    expect(yScale.getPixelForValue(0)).toBeCloseToPixel(88);
+    expect(yScale.getPixelForValue(3)).toBeCloseToPixel(426);
+    expect(yScale.getPixelForValue(4)).toBeCloseToPixel(538);
+  });
+
+  it('Should be consistent on pixels and values with autoSkipped ticks', function() {
+    var labels = [];
+    for (let i = 0; i < 50; i++) {
+      labels.push('very long label ' + i);
+    }
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        labels,
+        datasets: [{
+          data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+        }]
+      }
+    });
+
+    var scale = chart.scales.x;
+    expect(scale.ticks.length).toBeLessThan(50);
+
+    let x = 0;
+    for (let i = 0; i < 50; i++) {
+      var x2 = scale.getPixelForValue(labels[i]);
+      var x3 = scale.getPixelForValue(i);
+      expect(x2).toEqual(x3);
+      expect(x2).toBeGreaterThan(x);
+      expect(scale.getValueForPixel(x2)).toBe(i);
+      x = x2;
+    }
+  });
+
+  it('Should bound to ticks/data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: ['a', 'b', 'c', 'd'],
+        datasets: [{
+          data: {b: 1, c: 99}
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'category',
+            bounds: 'data'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.min).toEqual(1);
+    expect(chart.scales.x.max).toEqual(2);
+
+    chart.options.scales.x.bounds = 'ticks';
+    chart.update();
+
+    expect(chart.scales.x.min).toEqual(0);
+    expect(chart.scales.x.max).toEqual(3);
+  });
 });
index e7b5d055d87be40b0468e082af24cc13018a347c..36bdf225827629869f4b394d61c8568595d67593 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Linear Scale', function() {
-       describe('auto', jasmine.fixture.specs('scale.linear'));
-
-       it('Should register the constructor with the registry', function() {
-               var Constructor = Chart.registry.getScale('linear');
-               expect(Constructor).not.toBe(undefined);
-               expect(typeof Constructor).toBe('function');
-       });
-
-       it('Should have the correct default config', function() {
-               var defaultConfig = Chart.defaults.scales.linear;
-
-               expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
-       });
-
-       it('Should correctly determine the max & min data values', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, -5, 78, -100]
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [-1000, 1000],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [150]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear'
-                                       },
-                                       y2: {
-                                               type: 'linear',
-                                               position: 'right',
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-100);
-               expect(chart.scales.y.max).toBe(150);
-       });
-
-       it('Should correctly determine the max & min of string data values', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: ['10', '5', '0', '-5', '78', '-100']
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: ['-1000', '1000'],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: ['150']
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear'
-                                       },
-                                       y2: {
-                                               type: 'linear',
-                                               position: 'right'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-100);
-               expect(chart.scales.y.max).toBe(150);
-       });
-
-       it('Should correctly determine the max & min when no values provided and suggested minimum and maximum are set', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: []
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               suggestedMin: -10,
-                                               suggestedMax: 15
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-10);
-               expect(chart.scales.y.max).toBe(15);
-       });
-
-       it('Should correctly determine the max & min when no datasets are associated and suggested minimum and maximum are set', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               suggestedMin: -10,
-                                               suggestedMax: 0
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toBe(-10);
-               expect(chart.scales.y.max).toBe(0);
-       });
-
-       it('Should correctly determine the max & min data values ignoring hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: ['10', '5', '0', '-5', '78', '-100']
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: ['-1000', '1000'],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: ['150'],
-                                       hidden: true
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear'
-                                       },
-                                       y2: {
-                                               position: 'right',
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-100);
-               expect(chart.scales.y.max).toBe(80);
-       });
-
-       it('Should correctly determine the max & min data values ignoring data that is NaN', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [null, 90, NaN, undefined, 45, 30, Infinity, -Infinity]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toBe(30);
-               expect(chart.scales.y.max).toBe(90);
-
-               // Scale is now stacked
-               chart.scales.y.options.stacked = true;
-               chart.update();
-
-               expect(chart.scales.y.min).toBe(0);
-               expect(chart.scales.y.max).toBe(90);
-       });
-
-       it('Should correctly determine the max & min data values for small numbers', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [-1e-8, 3e-8, -4e-8, 6e-8]
-                               }],
-                               labels: ['a', 'b', 'c', 'd']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min * 1e8).toBeCloseTo(-4);
-               expect(chart.scales.y.max * 1e8).toBeCloseTo(6);
-       });
-
-       it('Should correctly determine the max & min for scatter data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [{
-                                               x: 10,
-                                               y: 100
-                                       }, {
-                                               x: -10,
-                                               y: 0
-                                       }, {
-                                               x: 0,
-                                               y: 0
-                                       }, {
-                                               x: 99,
-                                               y: 7
-                                       }]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-               chart.update();
-
-               expect(chart.scales.x.min).toBe(-20);
-               expect(chart.scales.x.max).toBe(100);
-               expect(chart.scales.y.min).toBe(0);
-               expect(chart.scales.y.max).toBe(100);
-       });
-
-       it('Should correctly get the label for the given index', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [{
-                                               x: 10,
-                                               y: 100
-                                       }, {
-                                               x: -10,
-                                               y: 0
-                                       }, {
-                                               x: 0,
-                                               y: 0
-                                       }, {
-                                               x: 99,
-                                               y: 7
-                                       }]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-               chart.update();
-
-               expect(chart.scales.y.getLabelForValue(7)).toBe('7');
-       });
-
-       it('Should correctly determine the min and max data values when stacked mode is turned on', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, -5, 78, -100],
-                                       type: 'bar'
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [-1000, 1000],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [150, 0, 0, -100, -10, 9],
-                                       type: 'bar'
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [10, 10, 10, 10, 10, 10],
-                                       type: 'line'
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               stacked: true
-                                       },
-                                       y2: {
-                                               position: 'right',
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-               chart.update();
-
-               expect(chart.scales.y.min).toBe(-150);
-               expect(chart.scales.y.max).toBe(200);
-       });
-
-       it('Should correctly determine the min and max data values when stacked mode is turned on and there are hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, -5, 78, -100],
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [-1000, 1000],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [150, 0, 0, -100, -10, 9],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [10, 20, 30, 40, 50, 60],
-                                       hidden: true
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               stacked: true
-                                       },
-                                       y2: {
-                                               position: 'right',
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-               chart.update();
-
-               expect(chart.scales.y.min).toBe(-150);
-               expect(chart.scales.y.max).toBe(200);
-       });
-
-       it('Should correctly determine the min and max data values when stacked mode is turned on there are multiple types of datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       type: 'bar',
-                                       data: [10, 5, 0, -5, 78, -100]
-                               }, {
-                                       type: 'line',
-                                       data: [10, 10, 10, 10, 10, 10],
-                               }, {
-                                       type: 'bar',
-                                       data: [150, 0, 0, -100, -10, 9]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               chart.scales.y.determineDataLimits();
-               expect(chart.scales.y.min).toBe(-105);
-               expect(chart.scales.y.max).toBe(160);
-       });
-
-       it('Should ensure that the scale has a max and min that are not equal', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(0);
-               expect(chart.scales.y.max).toBe(1);
-       });
-
-       it('Should ensure that the scale has a max and min that are not equal when beginAtZero is set', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               beginAtZero: true
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(0);
-               expect(chart.scales.y.max).toBe(1);
-       });
-
-       it('Should use the suggestedMin and suggestedMax options', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               suggestedMax: 10,
-                                               suggestedMin: -10
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-10);
-               expect(chart.scales.y.max).toBe(10);
-       });
-
-       it('Should use the min and max options', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               max: 1010,
-                                               min: -1010
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(-1010);
-               expect(chart.scales.y.max).toBe(1010);
-               var labels = getLabels(chart.scales.y);
-               expect(labels[0]).toBe('-1,010');
-               expect(labels[labels.length - 1]).toBe('1,010');
-       });
-
-       it('Should use min, max and stepSize to create fixed spaced ticks', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 3, 6, 8, 3, 1]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               min: 1,
-                                               max: 11,
-                                               ticks: {
-                                                       stepSize: 2
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(1);
-               expect(chart.scales.y.max).toBe(11);
-               expect(getLabels(chart.scales.y)).toEqual(['1', '3', '5', '7', '9', '11']);
-       });
-
-       it('Should create decimal steps if stepSize is a decimal number', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 3, 6, 8, 3, 1]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               ticks: {
-                                                       stepSize: 2.5
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(0);
-               expect(chart.scales.y.max).toBe(10);
-               expect(getLabels(chart.scales.y)).toEqual(['0', '2.5', '5', '7.5', '10']);
-       });
-
-       describe('precision', function() {
-               it('Should create integer steps if precision is 0', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [{
-                                               yAxisID: 'y',
-                                               data: [0, 1, 2, 1, 0, 1]
-                                       }],
-                                       labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                               },
-                               options: {
-                                       scales: {
-                                               y: {
-                                                       type: 'linear',
-                                                       ticks: {
-                                                               precision: 0
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.y).not.toEqual(undefined); // must construct
-                       expect(chart.scales.y.min).toBe(0);
-                       expect(chart.scales.y.max).toBe(2);
-                       expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2']);
-               });
-
-               it('Should round the step size to the given number of decimal places', function() {
-                       var chart = window.acquireChart({
-                               type: 'bar',
-                               data: {
-                                       datasets: [{
-                                               yAxisID: 'y',
-                                               data: [0, 0.001, 0.002, 0.003, 0, 0.001]
-                                       }],
-                                       labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                               },
-                               options: {
-                                       scales: {
-                                               y: {
-                                                       type: 'linear',
-                                                       ticks: {
-                                                               precision: 2
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-
-                       expect(chart.scales.y).not.toEqual(undefined); // must construct
-                       expect(chart.scales.y.min).toBe(0);
-                       expect(chart.scales.y.max).toBe(0.01);
-                       expect(getLabels(chart.scales.y)).toEqual(['0', '0.01']);
-               });
-       });
-
-
-       it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [20, 30, 40, 50]
-                               }],
-                               labels: ['a', 'b', 'c', 'd']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(getLabels(chart.scales.y)).toEqual(['20', '25', '30', '35', '40', '45', '50']);
-
-               chart.scales.y.options.beginAtZero = true;
-               chart.update();
-               expect(getLabels(chart.scales.y)).toEqual(['0', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50']);
-
-               chart.data.datasets[0].data = [-20, -30, -40, -50];
-               chart.update();
-               expect(getLabels(chart.scales.y)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20', '-15', '-10', '-5', '0']);
-
-               chart.scales.y.options.beginAtZero = false;
-               chart.update();
-               expect(getLabels(chart.scales.y)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20']);
-       });
-
-       it('Should generate tick marks in the correct order in reversed mode', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['a', 'b', 'c', 'd']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               reverse: true
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.y)).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '0']);
-               expect(chart.scales.y.start).toBe(80);
-               expect(chart.scales.y.end).toBe(0);
-       });
-
-       it('should use the correct number of decimal places in the default format function', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [0.06, 0.005, 0, 0.025, 0.0078]
-                               }],
-                               labels: ['a', 'b', 'c', 'd']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                       }
-                               }
-                       }
-               });
-               expect(getLabels(chart.scales.y)).toEqual(['0', '0.01', '0.02', '0.03', '0.04', '0.05', '0.06']);
-       });
-
-       it('Should correctly limit the maximum number of ticks', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               labels: ['a', 'b'],
-                               datasets: [{
-                                       data: [0.5, 2.5]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.y.ticks.maxTicksLimit = 11;
-               chart.update();
-
-               expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.y.ticks.maxTicksLimit = 21;
-               chart.update();
-
-               expect(getLabels(chart.scales.y)).toEqual([
-                       '0.5',
-                       '0.6', '0.7', '0.8', '0.9', '1.0', '1.1', '1.2', '1.3', '1.4', '1.5',
-                       '1.6', '1.7', '1.8', '1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5'
-               ]);
-
-               chart.options.scales.y.ticks.maxTicksLimit = 11;
-               chart.options.scales.y.ticks.stepSize = 0.01;
-               chart.update();
-
-               expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.y.min = 0.3;
-               chart.options.scales.y.max = 2.8;
-               chart.update();
-
-               expect(getLabels(chart.scales.y)).toEqual(['0.3', '0.8', '1.3', '1.8', '2.3', '2.8']);
-       });
-
-       it('Should bound to data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['a', 'b'],
-                               datasets: [{
-                                       data: [1, 99]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               bounds: 'data'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toEqual(1);
-               expect(chart.scales.y.max).toEqual(99);
-       });
-
-       it('Should build labels using the user supplied callback', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['a', 'b', 'c', 'd']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                               ticks: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Just the index
-               expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']);
-       });
-
-       it('Should get the correct pixel value for a point', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: [-1, 1],
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [-1, 1]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               expect(xScale.getPixelForValue(1)).toBeCloseToPixel(501); // right - paddingRight
-               expect(xScale.getPixelForValue(-1)).toBeCloseToPixel(31 + 6); // left + paddingLeft + lineSpace
-               expect(xScale.getPixelForValue(0)).toBeCloseToPixel(266 + 6 / 2); // halfway*/
-
-               expect(xScale.getValueForPixel(501)).toBeCloseTo(1, 1e-2);
-               expect(xScale.getValueForPixel(31)).toBeCloseTo(-1, 1e-2);
-               expect(xScale.getValueForPixel(266)).toBeCloseTo(0, 1e-2);
-
-               var yScale = chart.scales.y;
-               expect(yScale.getPixelForValue(1)).toBeCloseToPixel(32); // right - paddingRight
-               expect(yScale.getPixelForValue(-1)).toBeCloseToPixel(484); // left + paddingLeft
-               expect(yScale.getPixelForValue(0)).toBeCloseToPixel(258); // halfway*/
-
-               expect(yScale.getValueForPixel(32)).toBeCloseTo(1, 1e-2);
-               expect(yScale.getValueForPixel(484)).toBeCloseTo(-1, 1e-2);
-               expect(yScale.getValueForPixel(258)).toBeCloseTo(0, 1e-2);
-       });
-
-       it('should fit correctly', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [{
-                                               x: 10,
-                                               y: 100
-                                       }, {
-                                               x: -10,
-                                               y: 0
-                                       }, {
-                                               x: 0,
-                                               y: 0
-                                       }, {
-                                               x: 99,
-                                               y: 7
-                                       }]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               var yScale = chart.scales.y;
-               expect(xScale.paddingTop).toBeCloseToPixel(0);
-               expect(xScale.paddingBottom).toBeCloseToPixel(0);
-               expect(xScale.paddingLeft).toBeCloseToPixel(12);
-               expect(xScale.paddingRight).toBeCloseToPixel(13.5);
-               expect(xScale.width).toBeCloseToPixel(468 - 6); // minus lineSpace
-               expect(xScale.height).toBeCloseToPixel(30);
-
-               expect(yScale.paddingTop).toBeCloseToPixel(7);
-               expect(yScale.paddingBottom).toBeCloseToPixel(7);
-               expect(yScale.paddingLeft).toBeCloseToPixel(0);
-               expect(yScale.paddingRight).toBeCloseToPixel(0);
-               expect(yScale.width).toBeCloseToPixel(30 + 6); // plus lineSpace
-               expect(yScale.height).toBeCloseToPixel(450);
-
-               // Extra size when scale label showing
-               xScale.options.scaleLabel.display = true;
-               yScale.options.scaleLabel.display = true;
-               chart.update();
-
-               expect(xScale.paddingTop).toBeCloseToPixel(0);
-               expect(xScale.paddingBottom).toBeCloseToPixel(0);
-               expect(xScale.paddingLeft).toBeCloseToPixel(12);
-               expect(xScale.paddingRight).toBeCloseToPixel(13.5);
-               expect(xScale.width).toBeCloseToPixel(440);
-               expect(xScale.height).toBeCloseToPixel(53);
-
-               expect(yScale.paddingTop).toBeCloseToPixel(7);
-               expect(yScale.paddingBottom).toBeCloseToPixel(7);
-               expect(yScale.paddingLeft).toBeCloseToPixel(0);
-               expect(yScale.paddingRight).toBeCloseToPixel(0);
-               expect(yScale.width).toBeCloseToPixel(58);
-               expect(yScale.height).toBeCloseToPixel(427);
-       });
-
-       it('should fit correctly when display is turned off', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       yAxisID: 'y',
-                                       data: [{
-                                               x: 10,
-                                               y: 100
-                                       }, {
-                                               x: -10,
-                                               y: 0
-                                       }, {
-                                               x: 0,
-                                               y: 0
-                                       }, {
-                                               x: 99,
-                                               y: 7
-                                       }]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               gridLines: {
-                                                       drawTicks: false,
-                                                       drawBorder: false
-                                               },
-                                               scaleLabel: {
-                                                       display: false,
-                                                       lineHeight: 1.2
-                                               },
-                                               ticks: {
-                                                       display: false,
-                                                       padding: 0
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-               expect(yScale.width).toBeCloseToPixel(0);
-       });
-
-       it('max and min value should be valid and finite when charts datasets are hidden', function() {
-               var barData = {
-                       labels: ['S1', 'S2', 'S3'],
-                       datasets: [{
-                               label: 'Closed',
-                               backgroundColor: '#382765',
-                               data: [2500, 2000, 1500]
-                       }, {
-                               label: 'In Progress',
-                               backgroundColor: '#7BC225',
-                               data: [1000, 2000, 1500]
-                       }, {
-                               label: 'Assigned',
-                               backgroundColor: '#ffC225',
-                               data: [1000, 2000, 1500]
-                       }]
-               };
-
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: barData,
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               stacked: true
-                                       },
-                                       y: {
-                                               stacked: true
-                                       }
-                               }
-                       }
-               });
-
-               barData.datasets.forEach(function(data, index) {
-                       var meta = chart.getDatasetMeta(index);
-                       meta.hidden = true;
-                       chart.update();
-               });
-
-               expect(chart.scales.x.min).toEqual(0);
-               expect(chart.scales.x.max).toEqual(1);
-       });
-
-       it('max and min value should be valid when min is set and all datasets are hidden', function() {
-               var barData = {
-                       labels: ['S1', 'S2', 'S3'],
-                       datasets: [{
-                               label: 'dataset 1',
-                               backgroundColor: '#382765',
-                               data: [2500, 2000, 1500],
-                               hidden: true,
-                       }]
-               };
-
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: barData,
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               min: 20
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.min).toEqual(20);
-               expect(chart.scales.x.max).toEqual(21);
-       });
-
-       it('min settings should be used if set to zero', function() {
-               var barData = {
-                       labels: ['S1', 'S2', 'S3'],
-                       datasets: [{
-                               label: 'dataset 1',
-                               backgroundColor: '#382765',
-                               data: [2500, 2000, 1500]
-                       }]
-               };
-
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: barData,
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               min: 0,
-                                               max: 3000
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.min).toEqual(0);
-       });
-
-       it('max settings should be used if set to zero', function() {
-               var barData = {
-                       labels: ['S1', 'S2', 'S3'],
-                       datasets: [{
-                               label: 'dataset 1',
-                               backgroundColor: '#382765',
-                               data: [-2500, -2000, -1500]
-                       }]
-               };
-
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: barData,
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               min: -3000,
-                                               max: 0
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.max).toEqual(0);
-       });
-
-       it('Should get correct pixel values when horizontal', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [0.05, -25, 10, 15, 20, 25, 30, 35]
-                               }]
-                       },
-                       options: {
-                               indexAxis: 'y',
-                               scales: {
-                                       x: {
-                                               type: 'linear',
-                                       }
-                               }
-                       }
-               });
-
-               var start = chart.chartArea.left;
-               var end = chart.chartArea.right;
-               var min = -30;
-               var max = 40;
-               var scale = chart.scales.x;
-
-               expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
-               expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
-               expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
-               expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
-
-               scale.options.reverse = true;
-               chart.update();
-
-               start = chart.chartArea.left;
-               end = chart.chartArea.right;
-
-               expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
-               expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
-               expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
-               expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
-       });
-
-       it('Should get correct pixel values when vertical', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [0.05, -25, 10, 15, 20, 25, 30, 35]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'linear',
-                                       }
-                               }
-                       }
-               });
-
-               var start = chart.chartArea.bottom;
-               var end = chart.chartArea.top;
-               var min = -30;
-               var max = 40;
-               var scale = chart.scales.y;
-
-               expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
-               expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
-               expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
-               expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
-
-               scale.options.reverse = true;
-               chart.update();
-
-               start = chart.chartArea.bottom;
-               end = chart.chartArea.top;
-
-               expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
-               expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
-               expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
-               expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
-       });
+  describe('auto', jasmine.fixture.specs('scale.linear'));
+
+  it('Should register the constructor with the registry', function() {
+    var Constructor = Chart.registry.getScale('linear');
+    expect(Constructor).not.toBe(undefined);
+    expect(typeof Constructor).toBe('function');
+  });
+
+  it('Should have the correct default config', function() {
+    var defaultConfig = Chart.defaults.scales.linear;
+
+    expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
+  });
+
+  it('Should correctly determine the max & min data values', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, -5, 78, -100]
+        }, {
+          yAxisID: 'y2',
+          data: [-1000, 1000],
+        }, {
+          yAxisID: 'y',
+          data: [150]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear'
+          },
+          y2: {
+            type: 'linear',
+            position: 'right',
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-100);
+    expect(chart.scales.y.max).toBe(150);
+  });
+
+  it('Should correctly determine the max & min of string data values', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: ['10', '5', '0', '-5', '78', '-100']
+        }, {
+          yAxisID: 'y2',
+          data: ['-1000', '1000'],
+        }, {
+          yAxisID: 'y',
+          data: ['150']
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear'
+          },
+          y2: {
+            type: 'linear',
+            position: 'right'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-100);
+    expect(chart.scales.y.max).toBe(150);
+  });
+
+  it('Should correctly determine the max & min when no values provided and suggested minimum and maximum are set', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: []
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            suggestedMin: -10,
+            suggestedMax: 15
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-10);
+    expect(chart.scales.y.max).toBe(15);
+  });
+
+  it('Should correctly determine the max & min when no datasets are associated and suggested minimum and maximum are set', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            suggestedMin: -10,
+            suggestedMax: 0
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toBe(-10);
+    expect(chart.scales.y.max).toBe(0);
+  });
+
+  it('Should correctly determine the max & min data values ignoring hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: ['10', '5', '0', '-5', '78', '-100']
+        }, {
+          yAxisID: 'y2',
+          data: ['-1000', '1000'],
+        }, {
+          yAxisID: 'y',
+          data: ['150'],
+          hidden: true
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear'
+          },
+          y2: {
+            position: 'right',
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-100);
+    expect(chart.scales.y.max).toBe(80);
+  });
+
+  it('Should correctly determine the max & min data values ignoring data that is NaN', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [null, 90, NaN, undefined, 45, 30, Infinity, -Infinity]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toBe(30);
+    expect(chart.scales.y.max).toBe(90);
+
+    // Scale is now stacked
+    chart.scales.y.options.stacked = true;
+    chart.update();
+
+    expect(chart.scales.y.min).toBe(0);
+    expect(chart.scales.y.max).toBe(90);
+  });
+
+  it('Should correctly determine the max & min data values for small numbers', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [-1e-8, 3e-8, -4e-8, 6e-8]
+        }],
+        labels: ['a', 'b', 'c', 'd']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min * 1e8).toBeCloseTo(-4);
+    expect(chart.scales.y.max * 1e8).toBeCloseTo(6);
+  });
+
+  it('Should correctly determine the max & min for scatter data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [{
+            x: 10,
+            y: 100
+          }, {
+            x: -10,
+            y: 0
+          }, {
+            x: 0,
+            y: 0
+          }, {
+            x: 99,
+            y: 7
+          }]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+    chart.update();
+
+    expect(chart.scales.x.min).toBe(-20);
+    expect(chart.scales.x.max).toBe(100);
+    expect(chart.scales.y.min).toBe(0);
+    expect(chart.scales.y.max).toBe(100);
+  });
+
+  it('Should correctly get the label for the given index', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [{
+            x: 10,
+            y: 100
+          }, {
+            x: -10,
+            y: 0
+          }, {
+            x: 0,
+            y: 0
+          }, {
+            x: 99,
+            y: 7
+          }]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+    chart.update();
+
+    expect(chart.scales.y.getLabelForValue(7)).toBe('7');
+  });
+
+  it('Should correctly determine the min and max data values when stacked mode is turned on', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, -5, 78, -100],
+          type: 'bar'
+        }, {
+          yAxisID: 'y2',
+          data: [-1000, 1000],
+        }, {
+          yAxisID: 'y',
+          data: [150, 0, 0, -100, -10, 9],
+          type: 'bar'
+        }, {
+          yAxisID: 'y',
+          data: [10, 10, 10, 10, 10, 10],
+          type: 'line'
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            stacked: true
+          },
+          y2: {
+            position: 'right',
+            type: 'linear'
+          }
+        }
+      }
+    });
+    chart.update();
+
+    expect(chart.scales.y.min).toBe(-150);
+    expect(chart.scales.y.max).toBe(200);
+  });
+
+  it('Should correctly determine the min and max data values when stacked mode is turned on and there are hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, -5, 78, -100],
+        }, {
+          yAxisID: 'y2',
+          data: [-1000, 1000],
+        }, {
+          yAxisID: 'y',
+          data: [150, 0, 0, -100, -10, 9],
+        }, {
+          yAxisID: 'y',
+          data: [10, 20, 30, 40, 50, 60],
+          hidden: true
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            stacked: true
+          },
+          y2: {
+            position: 'right',
+            type: 'linear'
+          }
+        }
+      }
+    });
+    chart.update();
+
+    expect(chart.scales.y.min).toBe(-150);
+    expect(chart.scales.y.max).toBe(200);
+  });
+
+  it('Should correctly determine the min and max data values when stacked mode is turned on there are multiple types of datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          type: 'bar',
+          data: [10, 5, 0, -5, 78, -100]
+        }, {
+          type: 'line',
+          data: [10, 10, 10, 10, 10, 10],
+        }, {
+          type: 'bar',
+          data: [150, 0, 0, -100, -10, 9]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            stacked: true
+          }
+        }
+      }
+    });
+
+    chart.scales.y.determineDataLimits();
+    expect(chart.scales.y.min).toBe(-105);
+    expect(chart.scales.y.max).toBe(160);
+  });
+
+  it('Should ensure that the scale has a max and min that are not equal', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(0);
+    expect(chart.scales.y.max).toBe(1);
+  });
+
+  it('Should ensure that the scale has a max and min that are not equal when beginAtZero is set', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            beginAtZero: true
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(0);
+    expect(chart.scales.y.max).toBe(1);
+  });
+
+  it('Should use the suggestedMin and suggestedMax options', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            suggestedMax: 10,
+            suggestedMin: -10
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-10);
+    expect(chart.scales.y.max).toBe(10);
+  });
+
+  it('Should use the min and max options', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            max: 1010,
+            min: -1010
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(-1010);
+    expect(chart.scales.y.max).toBe(1010);
+    var labels = getLabels(chart.scales.y);
+    expect(labels[0]).toBe('-1,010');
+    expect(labels[labels.length - 1]).toBe('1,010');
+  });
+
+  it('Should use min, max and stepSize to create fixed spaced ticks', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 3, 6, 8, 3, 1]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            min: 1,
+            max: 11,
+            ticks: {
+              stepSize: 2
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(1);
+    expect(chart.scales.y.max).toBe(11);
+    expect(getLabels(chart.scales.y)).toEqual(['1', '3', '5', '7', '9', '11']);
+  });
+
+  it('Should create decimal steps if stepSize is a decimal number', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 3, 6, 8, 3, 1]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            ticks: {
+              stepSize: 2.5
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(0);
+    expect(chart.scales.y.max).toBe(10);
+    expect(getLabels(chart.scales.y)).toEqual(['0', '2.5', '5', '7.5', '10']);
+  });
+
+  describe('precision', function() {
+    it('Should create integer steps if precision is 0', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [{
+            yAxisID: 'y',
+            data: [0, 1, 2, 1, 0, 1]
+          }],
+          labels: ['a', 'b', 'c', 'd', 'e', 'f']
+        },
+        options: {
+          scales: {
+            y: {
+              type: 'linear',
+              ticks: {
+                precision: 0
+              }
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.y).not.toEqual(undefined); // must construct
+      expect(chart.scales.y.min).toBe(0);
+      expect(chart.scales.y.max).toBe(2);
+      expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2']);
+    });
+
+    it('Should round the step size to the given number of decimal places', function() {
+      var chart = window.acquireChart({
+        type: 'bar',
+        data: {
+          datasets: [{
+            yAxisID: 'y',
+            data: [0, 0.001, 0.002, 0.003, 0, 0.001]
+          }],
+          labels: ['a', 'b', 'c', 'd', 'e', 'f']
+        },
+        options: {
+          scales: {
+            y: {
+              type: 'linear',
+              ticks: {
+                precision: 2
+              }
+            }
+          }
+        }
+      });
+
+      expect(chart.scales.y).not.toEqual(undefined); // must construct
+      expect(chart.scales.y.min).toBe(0);
+      expect(chart.scales.y.max).toBe(0.01);
+      expect(getLabels(chart.scales.y)).toEqual(['0', '0.01']);
+    });
+  });
+
+
+  it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [20, 30, 40, 50]
+        }],
+        labels: ['a', 'b', 'c', 'd']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(getLabels(chart.scales.y)).toEqual(['20', '25', '30', '35', '40', '45', '50']);
+
+    chart.scales.y.options.beginAtZero = true;
+    chart.update();
+    expect(getLabels(chart.scales.y)).toEqual(['0', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50']);
+
+    chart.data.datasets[0].data = [-20, -30, -40, -50];
+    chart.update();
+    expect(getLabels(chart.scales.y)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20', '-15', '-10', '-5', '0']);
+
+    chart.scales.y.options.beginAtZero = false;
+    chart.update();
+    expect(getLabels(chart.scales.y)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20']);
+  });
+
+  it('Should generate tick marks in the correct order in reversed mode', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['a', 'b', 'c', 'd']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            reverse: true
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.y)).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '0']);
+    expect(chart.scales.y.start).toBe(80);
+    expect(chart.scales.y.end).toBe(0);
+  });
+
+  it('should use the correct number of decimal places in the default format function', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [0.06, 0.005, 0, 0.025, 0.0078]
+        }],
+        labels: ['a', 'b', 'c', 'd']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+          }
+        }
+      }
+    });
+    expect(getLabels(chart.scales.y)).toEqual(['0', '0.01', '0.02', '0.03', '0.04', '0.05', '0.06']);
+  });
+
+  it('Should correctly limit the maximum number of ticks', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        labels: ['a', 'b'],
+        datasets: [{
+          data: [0.5, 2.5]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.y.ticks.maxTicksLimit = 11;
+    chart.update();
+
+    expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.y.ticks.maxTicksLimit = 21;
+    chart.update();
+
+    expect(getLabels(chart.scales.y)).toEqual([
+      '0.5',
+      '0.6', '0.7', '0.8', '0.9', '1.0', '1.1', '1.2', '1.3', '1.4', '1.5',
+      '1.6', '1.7', '1.8', '1.9', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5'
+    ]);
+
+    chart.options.scales.y.ticks.maxTicksLimit = 11;
+    chart.options.scales.y.ticks.stepSize = 0.01;
+    chart.update();
+
+    expect(getLabels(chart.scales.y)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.y.min = 0.3;
+    chart.options.scales.y.max = 2.8;
+    chart.update();
+
+    expect(getLabels(chart.scales.y)).toEqual(['0.3', '0.8', '1.3', '1.8', '2.3', '2.8']);
+  });
+
+  it('Should bound to data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: ['a', 'b'],
+        datasets: [{
+          data: [1, 99]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            bounds: 'data'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toEqual(1);
+    expect(chart.scales.y.max).toEqual(99);
+  });
+
+  it('Should build labels using the user supplied callback', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['a', 'b', 'c', 'd']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+            ticks: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Just the index
+    expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']);
+  });
+
+  it('Should get the correct pixel value for a point', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: [-1, 1],
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [-1, 1]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    expect(xScale.getPixelForValue(1)).toBeCloseToPixel(501); // right - paddingRight
+    expect(xScale.getPixelForValue(-1)).toBeCloseToPixel(31 + 6); // left + paddingLeft + lineSpace
+    expect(xScale.getPixelForValue(0)).toBeCloseToPixel(266 + 6 / 2); // halfway*/
+
+    expect(xScale.getValueForPixel(501)).toBeCloseTo(1, 1e-2);
+    expect(xScale.getValueForPixel(31)).toBeCloseTo(-1, 1e-2);
+    expect(xScale.getValueForPixel(266)).toBeCloseTo(0, 1e-2);
+
+    var yScale = chart.scales.y;
+    expect(yScale.getPixelForValue(1)).toBeCloseToPixel(32); // right - paddingRight
+    expect(yScale.getPixelForValue(-1)).toBeCloseToPixel(484); // left + paddingLeft
+    expect(yScale.getPixelForValue(0)).toBeCloseToPixel(258); // halfway*/
+
+    expect(yScale.getValueForPixel(32)).toBeCloseTo(1, 1e-2);
+    expect(yScale.getValueForPixel(484)).toBeCloseTo(-1, 1e-2);
+    expect(yScale.getValueForPixel(258)).toBeCloseTo(0, 1e-2);
+  });
+
+  it('should fit correctly', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [{
+            x: 10,
+            y: 100
+          }, {
+            x: -10,
+            y: 0
+          }, {
+            x: 0,
+            y: 0
+          }, {
+            x: 99,
+            y: 7
+          }]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    var yScale = chart.scales.y;
+    expect(xScale.paddingTop).toBeCloseToPixel(0);
+    expect(xScale.paddingBottom).toBeCloseToPixel(0);
+    expect(xScale.paddingLeft).toBeCloseToPixel(12);
+    expect(xScale.paddingRight).toBeCloseToPixel(13.5);
+    expect(xScale.width).toBeCloseToPixel(468 - 6); // minus lineSpace
+    expect(xScale.height).toBeCloseToPixel(30);
+
+    expect(yScale.paddingTop).toBeCloseToPixel(7);
+    expect(yScale.paddingBottom).toBeCloseToPixel(7);
+    expect(yScale.paddingLeft).toBeCloseToPixel(0);
+    expect(yScale.paddingRight).toBeCloseToPixel(0);
+    expect(yScale.width).toBeCloseToPixel(30 + 6); // plus lineSpace
+    expect(yScale.height).toBeCloseToPixel(450);
+
+    // Extra size when scale label showing
+    xScale.options.scaleLabel.display = true;
+    yScale.options.scaleLabel.display = true;
+    chart.update();
+
+    expect(xScale.paddingTop).toBeCloseToPixel(0);
+    expect(xScale.paddingBottom).toBeCloseToPixel(0);
+    expect(xScale.paddingLeft).toBeCloseToPixel(12);
+    expect(xScale.paddingRight).toBeCloseToPixel(13.5);
+    expect(xScale.width).toBeCloseToPixel(440);
+    expect(xScale.height).toBeCloseToPixel(53);
+
+    expect(yScale.paddingTop).toBeCloseToPixel(7);
+    expect(yScale.paddingBottom).toBeCloseToPixel(7);
+    expect(yScale.paddingLeft).toBeCloseToPixel(0);
+    expect(yScale.paddingRight).toBeCloseToPixel(0);
+    expect(yScale.width).toBeCloseToPixel(58);
+    expect(yScale.height).toBeCloseToPixel(427);
+  });
+
+  it('should fit correctly when display is turned off', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          yAxisID: 'y',
+          data: [{
+            x: 10,
+            y: 100
+          }, {
+            x: -10,
+            y: 0
+          }, {
+            x: 0,
+            y: 0
+          }, {
+            x: 99,
+            y: 7
+          }]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'linear',
+            position: 'bottom'
+          },
+          y: {
+            type: 'linear',
+            gridLines: {
+              drawTicks: false,
+              drawBorder: false
+            },
+            scaleLabel: {
+              display: false,
+              lineHeight: 1.2
+            },
+            ticks: {
+              display: false,
+              padding: 0
+            }
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+    expect(yScale.width).toBeCloseToPixel(0);
+  });
+
+  it('max and min value should be valid and finite when charts datasets are hidden', function() {
+    var barData = {
+      labels: ['S1', 'S2', 'S3'],
+      datasets: [{
+        label: 'Closed',
+        backgroundColor: '#382765',
+        data: [2500, 2000, 1500]
+      }, {
+        label: 'In Progress',
+        backgroundColor: '#7BC225',
+        data: [1000, 2000, 1500]
+      }, {
+        label: 'Assigned',
+        backgroundColor: '#ffC225',
+        data: [1000, 2000, 1500]
+      }]
+    };
+
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: barData,
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            stacked: true
+          },
+          y: {
+            stacked: true
+          }
+        }
+      }
+    });
+
+    barData.datasets.forEach(function(data, index) {
+      var meta = chart.getDatasetMeta(index);
+      meta.hidden = true;
+      chart.update();
+    });
+
+    expect(chart.scales.x.min).toEqual(0);
+    expect(chart.scales.x.max).toEqual(1);
+  });
+
+  it('max and min value should be valid when min is set and all datasets are hidden', function() {
+    var barData = {
+      labels: ['S1', 'S2', 'S3'],
+      datasets: [{
+        label: 'dataset 1',
+        backgroundColor: '#382765',
+        data: [2500, 2000, 1500],
+        hidden: true,
+      }]
+    };
+
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: barData,
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            min: 20
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.min).toEqual(20);
+    expect(chart.scales.x.max).toEqual(21);
+  });
+
+  it('min settings should be used if set to zero', function() {
+    var barData = {
+      labels: ['S1', 'S2', 'S3'],
+      datasets: [{
+        label: 'dataset 1',
+        backgroundColor: '#382765',
+        data: [2500, 2000, 1500]
+      }]
+    };
+
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: barData,
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            min: 0,
+            max: 3000
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.min).toEqual(0);
+  });
+
+  it('max settings should be used if set to zero', function() {
+    var barData = {
+      labels: ['S1', 'S2', 'S3'],
+      datasets: [{
+        label: 'dataset 1',
+        backgroundColor: '#382765',
+        data: [-2500, -2000, -1500]
+      }]
+    };
+
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: barData,
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            min: -3000,
+            max: 0
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.max).toEqual(0);
+  });
+
+  it('Should get correct pixel values when horizontal', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [0.05, -25, 10, 15, 20, 25, 30, 35]
+        }]
+      },
+      options: {
+        indexAxis: 'y',
+        scales: {
+          x: {
+            type: 'linear',
+          }
+        }
+      }
+    });
+
+    var start = chart.chartArea.left;
+    var end = chart.chartArea.right;
+    var min = -30;
+    var max = 40;
+    var scale = chart.scales.x;
+
+    expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
+    expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
+    expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
+    expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
+
+    scale.options.reverse = true;
+    chart.update();
+
+    start = chart.chartArea.left;
+    end = chart.chartArea.right;
+
+    expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
+    expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
+    expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
+    expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
+  });
+
+  it('Should get correct pixel values when vertical', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [0.05, -25, 10, 15, 20, 25, 30, 35]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'linear',
+          }
+        }
+      }
+    });
+
+    var start = chart.chartArea.bottom;
+    var end = chart.chartArea.top;
+    var min = -30;
+    var max = 40;
+    var scale = chart.scales.y;
+
+    expect(scale.getPixelForValue(max)).toBeCloseToPixel(end);
+    expect(scale.getPixelForValue(min)).toBeCloseToPixel(start);
+    expect(scale.getValueForPixel(end)).toBeCloseTo(max, 4);
+    expect(scale.getValueForPixel(start)).toBeCloseTo(min, 4);
+
+    scale.options.reverse = true;
+    chart.update();
+
+    start = chart.chartArea.bottom;
+    end = chart.chartArea.top;
+
+    expect(scale.getPixelForValue(max)).toBeCloseToPixel(start);
+    expect(scale.getPixelForValue(min)).toBeCloseToPixel(end);
+    expect(scale.getValueForPixel(end)).toBeCloseTo(min, 4);
+    expect(scale.getValueForPixel(start)).toBeCloseTo(max, 4);
+  });
 });
index 332860fe5dad76774d25255b8c425a9e4718e1ea..0f0dc3303ebf25c877f6b126ede53076b62ef1a8 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 describe('Logarithmic Scale tests', function() {
-       it('should register', function() {
-               var Constructor = Chart.registry.getScale('logarithmic');
-               expect(Constructor).not.toBe(undefined);
-               expect(typeof Constructor).toBe('function');
-       });
-
-       it('should have the correct default config', function() {
-               var defaultConfig = Chart.defaults.scales.logarithmic;
-               expect(defaultConfig).toEqual({
-                       ticks: {
-                               callback: Chart.Ticks.formatters.logarithmic,
-                               major: {
-                                       enabled: true
-                               }
-                       }
-               });
-
-               // Is this actually a function
-               expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
-       });
-
-       it('should correctly determine the max & min data values', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [42, 1000, 64, 100],
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [10, 5, 5000, 78, 450]
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [150]
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [20, 0, 150, 1800, 3040]
-                               }, {
-                                       yAxisID: 'y3',
-                                       data: [67, 0.0004, 0, 820, 0.001]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               id: 'y',
-                                               type: 'logarithmic'
-                                       },
-                                       y1: {
-                                               type: 'logarithmic',
-                                               position: 'right'
-                                       },
-                                       y2: {
-                                               type: 'logarithmic',
-                                               position: 'right'
-                                       },
-                                       y3: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(10);
-               expect(chart.scales.y.max).toBe(1000);
-
-               expect(chart.scales.y1).not.toEqual(undefined); // must construct
-               expect(chart.scales.y1.min).toBe(1);
-               expect(chart.scales.y1.max).toBe(5000);
-
-               expect(chart.scales.y2).not.toEqual(undefined); // must construct
-               expect(chart.scales.y2.min).toBe(10);
-               expect(chart.scales.y2.max).toBe(4000);
-
-               expect(chart.scales.y3).not.toEqual(undefined); // must construct
-               expect(chart.scales.y3.min).toBeCloseTo(0.0001, 4);
-               expect(chart.scales.y3.max).toBe(900);
-       });
-
-       it('should correctly determine the max & min of string data values', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: ['42', '1000', '64', '100'],
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: ['10', '5', '5000', '78', '450']
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: ['150']
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: ['20', '0', '150', '1800', '3040']
-                               }, {
-                                       yAxisID: 'y3',
-                                       data: ['67', '0.0004', '0', '820', '0.001']
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       },
-                                       y2: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       },
-                                       y3: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(10);
-               expect(chart.scales.y.max).toBe(1000);
-
-               expect(chart.scales.y1).not.toEqual(undefined); // must construct
-               expect(chart.scales.y1.min).toBe(1);
-               expect(chart.scales.y1.max).toBe(5000);
-
-               expect(chart.scales.y2).not.toEqual(undefined); // must construct
-               expect(chart.scales.y2.min).toBe(10);
-               expect(chart.scales.y2.max).toBe(4000);
-
-               expect(chart.scales.y3).not.toEqual(undefined); // must construct
-               expect(chart.scales.y3.min).toBeCloseTo(0.0001, 4);
-               expect(chart.scales.y3.max).toBe(900);
-       });
-
-       it('should correctly determine the max & min data values when there are hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y1',
-                                       data: [10, 5, 5000, 78, 450]
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [42, 1000, 64, 100],
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [50000],
-                                       hidden: true
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [20, 0, 7400, 14, 291]
-                               }, {
-                                       yAxisID: 'y2',
-                                       data: [6, 0.0007, 9, 890, 60000],
-                                       hidden: true
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       },
-                                       y2: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y1).not.toEqual(undefined); // must construct
-               expect(chart.scales.y1.min).toBe(1);
-               expect(chart.scales.y1.max).toBe(5000);
-
-               expect(chart.scales.y2).not.toEqual(undefined); // must construct
-               expect(chart.scales.y2.min).toBe(10);
-               expect(chart.scales.y2.max).toBe(8000);
-       });
-
-       it('should correctly determine the max & min data values when there is NaN data', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [undefined, 10, null, 5, 5000, NaN, 78, 450]
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [undefined, 28, null, 1000, 500, NaN, 50, 42, Infinity, -Infinity]
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [undefined, 30, null, 9400, 0, NaN, 54, 836]
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [undefined, 0, null, 800, 9, NaN, 894, 21]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(1);
-               expect(chart.scales.y.max).toBe(5000);
-
-               // Turn on stacked mode since it uses it's own
-               chart.options.scales.y.stacked = true;
-               chart.update();
-
-               expect(chart.scales.y.min).toBe(1);
-               expect(chart.scales.y.max).toBe(6000);
-
-               expect(chart.scales.y1).not.toEqual(undefined); // must construct
-               expect(chart.scales.y1.min).toBe(1);
-               expect(chart.scales.y1.max).toBe(10000);
-       });
-
-       it('should correctly determine the max & min for scatter data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [
-                                               {x: 10, y: 100},
-                                               {x: 2, y: 6},
-                                               {x: 65, y: 121},
-                                               {x: 99, y: 7}
-                                       ]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'logarithmic',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.min).toBe(1);
-               expect(chart.scales.x.max).toBe(100);
-
-               expect(chart.scales.y.min).toBe(1);
-               expect(chart.scales.y.max).toBe(200);
-       });
-
-       it('should correctly determine the max & min for scatter data when 0 values are present', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [
-                                               {x: 7, y: 950},
-                                               {x: 289, y: 0},
-                                               {x: 0, y: 8},
-                                               {x: 23, y: 0.04}
-                                       ]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'logarithmic',
-                                               position: 'bottom'
-                                       },
-                                       y: {
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.x.min).toBe(1);
-               expect(chart.scales.x.max).toBe(30);
-
-               expect(chart.scales.y.min).toBe(0.01);
-               expect(chart.scales.y.max).toBe(1000);
-       });
-
-       it('should correctly determine the min and max data values when stacked mode is turned on', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       type: 'bar',
-                                       yAxisID: 'y',
-                                       data: [10, 5, 1, 5, 78, 100]
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [0, 1000],
-                               }, {
-                                       type: 'bar',
-                                       yAxisID: 'y',
-                                       data: [150, 10, 10, 100, 10, 9]
-                               }, {
-                                       type: 'line',
-                                       yAxisID: 'y',
-                                       data: [100, 100, 100, 100, 100, 100]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               stacked: true
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toBe(0.1);
-               expect(chart.scales.y.max).toBe(200);
-       });
-
-       it('should correctly determine the min and max data values when stacked mode is turned on ignoring hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 1, 5, 78, 100],
-                                       type: 'bar'
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [0, 1000],
-                                       type: 'bar'
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [150, 10, 10, 100, 10, 9],
-                                       type: 'bar'
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [10000, 10000, 10000, 10000, 10000, 10000],
-                                       hidden: true,
-                                       type: 'bar'
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               stacked: true
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toBe(0.1);
-               expect(chart.scales.y.max).toBe(200);
-       });
-
-       it('should ensure that the scale has a max and min that are not equal', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toBe(1);
-               expect(chart.scales.y.max).toBe(10);
-
-               chart.data.datasets[0].data = [0.15, 0.15];
-               chart.update();
-
-               expect(chart.scales.y.min).toBe(0.01);
-               expect(chart.scales.y.max).toBe(1);
-       });
-
-       it('should use the min and max options', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               min: 10,
-                                               max: 1010,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var yScale = chart.scales.y;
-               var tickCount = yScale.ticks.length;
-               expect(yScale.min).toBe(10);
-               expect(yScale.max).toBe(1010);
-               expect(yScale.ticks[0].value).toBe(10);
-               expect(yScale.ticks[tickCount - 1].value).toBe(1010);
-       });
-
-       it('should ignore negative min and max options', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               min: -10,
-                                               max: -1010,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var y = chart.scales.y;
-               expect(y.min).toBe(0.1);
-               expect(y.max).toBe(2);
-       });
-
-       it('should ignore invalid min and max options', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               min: 'zero',
-                                               max: null,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var y = chart.scales.y;
-               expect(y.min).toBe(0.1);
-               expect(y.max).toBe(2);
-       });
-
-       it('should generate tick marks', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 2, 25, 78]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.y;
-               expect(getLabels(scale)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80]);
-               expect(scale.start).toEqual(1);
-               expect(scale.end).toEqual(80);
-       });
-
-       it('should generate tick marks when 0 values are present', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [11, 0.8, 0, 28, 7]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.y;
-               // Counts down because the lines are drawn top to bottom
-               expect(getLabels(scale)).toEqual([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30]);
-               expect(scale.start).toEqual(0.1);
-               expect(scale.end).toEqual(30);
-       });
-
-
-       it('should generate tick marks in the correct order in reversed mode', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 1, 25, 78]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               reverse: true,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.y;
-               expect(getLabels(scale)).toEqual([80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
-               expect(scale.start).toEqual(80);
-               expect(scale.end).toEqual(1);
-       });
-
-       it('should generate tick marks in the correct order in reversed mode when 0 values are present', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [21, 9, 0, 10, 25]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               reverse: true,
-                                               ticks: {
-                                                       callback: function(value) {
-                                                               return value;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.y;
-               expect(getLabels(scale)).toEqual([30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
-               expect(scale.start).toEqual(30);
-               expect(scale.end).toEqual(1);
-       });
-
-       it('should build labels using the default template', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 1.1, 25, 0, 78]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.y)).toEqual(['1', '2', '', '', '5', '', '', '', '', '10', '20', '', '', '50', '', '', '']);
-       });
-
-       it('should build labels using the user supplied callback', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 2, 25, 78]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               ticks: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               // Just the index
-               expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16']);
-       });
-
-       it('should correctly get the correct label for a data item', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: [10, 5, 5000, 78, 450]
-                               }, {
-                                       yAxisID: 'y1',
-                                       data: [1, 1000, 10, 100],
-                               }, {
-                                       yAxisID: 'y',
-                                       data: [150]
-                               }],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic'
-                                       },
-                                       y1: {
-                                               position: 'right',
-                                               type: 'logarithmic'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.getLabelForValue(150)).toBe('150');
-       });
-
-       describe('when', function() {
-               var data = [
-                       {
-                               data: [1, 39],
-                               stack: 'stack'
-                       },
-                       {
-                               data: [1, 39],
-                               stack: 'stack'
-                       },
-               ];
-               var dataWithEmptyStacks = [
-                       {
-                               data: []
-                       },
-                       {
-                               data: []
-                       }
-               ].concat(data);
-               var config = [
-                       {
-                               axis: 'y',
-                               firstTick: 1, // start of the axis (minimum)
-                               describe: 'all stacks are defined'
-                       },
-                       {
-                               axis: 'y',
-                               data: dataWithEmptyStacks,
-                               firstTick: 1,
-                               describe: 'not all stacks are defined'
-                       },
-                       {
-                               axis: 'y',
-                               scale: {
-                                       y: {
-                                               min: 0
-                                       }
-                               },
-                               firstTick: 0.1,
-                               describe: 'all stacks are defined and min: 0'
-                       },
-                       {
-                               axis: 'y',
-                               data: dataWithEmptyStacks,
-                               scale: {
-                                       y: {
-                                               min: 0
-                                       }
-                               },
-                               firstTick: 0.1,
-                               describe: 'not stacks are defined and min: 0'
-                       },
-                       {
-                               axis: 'x',
-                               firstTick: 1,
-                               describe: 'all stacks are defined'
-                       },
-                       {
-                               axis: 'x',
-                               data: dataWithEmptyStacks,
-                               firstTick: 1,
-                               describe: 'not all stacks are defined'
-                       },
-                       {
-                               axis: 'x',
-                               scale: {
-                                       x: {
-                                               min: 0
-                                       }
-                               },
-                               firstTick: 0.1,
-                               describe: 'all stacks are defined and min: 0'
-                       },
-                       {
-                               axis: 'x',
-                               data: dataWithEmptyStacks,
-                               scale: {
-                                       x: {
-                                               min: 0
-                                       }
-                               },
-                               firstTick: 0.1,
-                               describe: 'not all stacks are defined and min: 0'
-                       },
-               ];
-               config.forEach(function(setup) {
-                       var scaleConfig = {};
-                       var indexAxis, chartStart, chartEnd;
-
-                       if (setup.axis === 'x') {
-                               indexAxis = 'y';
-                               chartStart = 'left';
-                               chartEnd = 'right';
-                       } else {
-                               indexAxis = 'x';
-                               chartStart = 'bottom';
-                               chartEnd = 'top';
-                       }
-                       scaleConfig[setup.axis] = {
-                               type: 'logarithmic',
-                               beginAtZero: false
-                       };
-                       Object.assign(scaleConfig, setup.scale);
-                       scaleConfig[setup.axis].type = 'logarithmic';
-
-                       var description = 'dataset has stack option and ' + setup.describe
+  it('should register', function() {
+    var Constructor = Chart.registry.getScale('logarithmic');
+    expect(Constructor).not.toBe(undefined);
+    expect(typeof Constructor).toBe('function');
+  });
+
+  it('should have the correct default config', function() {
+    var defaultConfig = Chart.defaults.scales.logarithmic;
+    expect(defaultConfig).toEqual({
+      ticks: {
+        callback: Chart.Ticks.formatters.logarithmic,
+        major: {
+          enabled: true
+        }
+      }
+    });
+
+    // Is this actually a function
+    expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
+  });
+
+  it('should correctly determine the max & min data values', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [42, 1000, 64, 100],
+        }, {
+          yAxisID: 'y1',
+          data: [10, 5, 5000, 78, 450]
+        }, {
+          yAxisID: 'y1',
+          data: [150]
+        }, {
+          yAxisID: 'y2',
+          data: [20, 0, 150, 1800, 3040]
+        }, {
+          yAxisID: 'y3',
+          data: [67, 0.0004, 0, 820, 0.001]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e']
+      },
+      options: {
+        scales: {
+          y: {
+            id: 'y',
+            type: 'logarithmic'
+          },
+          y1: {
+            type: 'logarithmic',
+            position: 'right'
+          },
+          y2: {
+            type: 'logarithmic',
+            position: 'right'
+          },
+          y3: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(10);
+    expect(chart.scales.y.max).toBe(1000);
+
+    expect(chart.scales.y1).not.toEqual(undefined); // must construct
+    expect(chart.scales.y1.min).toBe(1);
+    expect(chart.scales.y1.max).toBe(5000);
+
+    expect(chart.scales.y2).not.toEqual(undefined); // must construct
+    expect(chart.scales.y2.min).toBe(10);
+    expect(chart.scales.y2.max).toBe(4000);
+
+    expect(chart.scales.y3).not.toEqual(undefined); // must construct
+    expect(chart.scales.y3.min).toBeCloseTo(0.0001, 4);
+    expect(chart.scales.y3.max).toBe(900);
+  });
+
+  it('should correctly determine the max & min of string data values', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: ['42', '1000', '64', '100'],
+        }, {
+          yAxisID: 'y1',
+          data: ['10', '5', '5000', '78', '450']
+        }, {
+          yAxisID: 'y1',
+          data: ['150']
+        }, {
+          yAxisID: 'y2',
+          data: ['20', '0', '150', '1800', '3040']
+        }, {
+          yAxisID: 'y3',
+          data: ['67', '0.0004', '0', '820', '0.001']
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          },
+          y2: {
+            position: 'right',
+            type: 'logarithmic'
+          },
+          y3: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(10);
+    expect(chart.scales.y.max).toBe(1000);
+
+    expect(chart.scales.y1).not.toEqual(undefined); // must construct
+    expect(chart.scales.y1.min).toBe(1);
+    expect(chart.scales.y1.max).toBe(5000);
+
+    expect(chart.scales.y2).not.toEqual(undefined); // must construct
+    expect(chart.scales.y2.min).toBe(10);
+    expect(chart.scales.y2.max).toBe(4000);
+
+    expect(chart.scales.y3).not.toEqual(undefined); // must construct
+    expect(chart.scales.y3.min).toBeCloseTo(0.0001, 4);
+    expect(chart.scales.y3.max).toBe(900);
+  });
+
+  it('should correctly determine the max & min data values when there are hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          yAxisID: 'y1',
+          data: [10, 5, 5000, 78, 450]
+        }, {
+          yAxisID: 'y',
+          data: [42, 1000, 64, 100],
+        }, {
+          yAxisID: 'y1',
+          data: [50000],
+          hidden: true
+        }, {
+          yAxisID: 'y2',
+          data: [20, 0, 7400, 14, 291]
+        }, {
+          yAxisID: 'y2',
+          data: [6, 0.0007, 9, 890, 60000],
+          hidden: true
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          },
+          y2: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y1).not.toEqual(undefined); // must construct
+    expect(chart.scales.y1.min).toBe(1);
+    expect(chart.scales.y1.max).toBe(5000);
+
+    expect(chart.scales.y2).not.toEqual(undefined); // must construct
+    expect(chart.scales.y2.min).toBe(10);
+    expect(chart.scales.y2.max).toBe(8000);
+  });
+
+  it('should correctly determine the max & min data values when there is NaN data', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [undefined, 10, null, 5, 5000, NaN, 78, 450]
+        }, {
+          yAxisID: 'y',
+          data: [undefined, 28, null, 1000, 500, NaN, 50, 42, Infinity, -Infinity]
+        }, {
+          yAxisID: 'y1',
+          data: [undefined, 30, null, 9400, 0, NaN, 54, 836]
+        }, {
+          yAxisID: 'y1',
+          data: [undefined, 0, null, 800, 9, NaN, 894, 21]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(1);
+    expect(chart.scales.y.max).toBe(5000);
+
+    // Turn on stacked mode since it uses it's own
+    chart.options.scales.y.stacked = true;
+    chart.update();
+
+    expect(chart.scales.y.min).toBe(1);
+    expect(chart.scales.y.max).toBe(6000);
+
+    expect(chart.scales.y1).not.toEqual(undefined); // must construct
+    expect(chart.scales.y1.min).toBe(1);
+    expect(chart.scales.y1.max).toBe(10000);
+  });
+
+  it('should correctly determine the max & min for scatter data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [
+            {x: 10, y: 100},
+            {x: 2, y: 6},
+            {x: 65, y: 121},
+            {x: 99, y: 7}
+          ]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'logarithmic',
+            position: 'bottom'
+          },
+          y: {
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.min).toBe(1);
+    expect(chart.scales.x.max).toBe(100);
+
+    expect(chart.scales.y.min).toBe(1);
+    expect(chart.scales.y.max).toBe(200);
+  });
+
+  it('should correctly determine the max & min for scatter data when 0 values are present', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [
+            {x: 7, y: 950},
+            {x: 289, y: 0},
+            {x: 0, y: 8},
+            {x: 23, y: 0.04}
+          ]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'logarithmic',
+            position: 'bottom'
+          },
+          y: {
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.x.min).toBe(1);
+    expect(chart.scales.x.max).toBe(30);
+
+    expect(chart.scales.y.min).toBe(0.01);
+    expect(chart.scales.y.max).toBe(1000);
+  });
+
+  it('should correctly determine the min and max data values when stacked mode is turned on', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          type: 'bar',
+          yAxisID: 'y',
+          data: [10, 5, 1, 5, 78, 100]
+        }, {
+          yAxisID: 'y1',
+          data: [0, 1000],
+        }, {
+          type: 'bar',
+          yAxisID: 'y',
+          data: [150, 10, 10, 100, 10, 9]
+        }, {
+          type: 'line',
+          yAxisID: 'y',
+          data: [100, 100, 100, 100, 100, 100]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            stacked: true
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toBe(0.1);
+    expect(chart.scales.y.max).toBe(200);
+  });
+
+  it('should correctly determine the min and max data values when stacked mode is turned on ignoring hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 1, 5, 78, 100],
+          type: 'bar'
+        }, {
+          yAxisID: 'y1',
+          data: [0, 1000],
+          type: 'bar'
+        }, {
+          yAxisID: 'y',
+          data: [150, 10, 10, 100, 10, 9],
+          type: 'bar'
+        }, {
+          yAxisID: 'y',
+          data: [10000, 10000, 10000, 10000, 10000, 10000],
+          hidden: true,
+          type: 'bar'
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            stacked: true
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toBe(0.1);
+    expect(chart.scales.y.max).toBe(200);
+  });
+
+  it('should ensure that the scale has a max and min that are not equal', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: []
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toBe(1);
+    expect(chart.scales.y.max).toBe(10);
+
+    chart.data.datasets[0].data = [0.15, 0.15];
+    chart.update();
+
+    expect(chart.scales.y.min).toBe(0.01);
+    expect(chart.scales.y.max).toBe(1);
+  });
+
+  it('should use the min and max options', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            min: 10,
+            max: 1010,
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var yScale = chart.scales.y;
+    var tickCount = yScale.ticks.length;
+    expect(yScale.min).toBe(10);
+    expect(yScale.max).toBe(1010);
+    expect(yScale.ticks[0].value).toBe(10);
+    expect(yScale.ticks[tickCount - 1].value).toBe(1010);
+  });
+
+  it('should ignore negative min and max options', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            min: -10,
+            max: -1010,
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var y = chart.scales.y;
+    expect(y.min).toBe(0.1);
+    expect(y.max).toBe(2);
+  });
+
+  it('should ignore invalid min and max options', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            min: 'zero',
+            max: null,
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var y = chart.scales.y;
+    expect(y.min).toBe(0.1);
+    expect(y.max).toBe(2);
+  });
+
+  it('should generate tick marks', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [10, 5, 2, 25, 78]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.y;
+    expect(getLabels(scale)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80]);
+    expect(scale.start).toEqual(1);
+    expect(scale.end).toEqual(80);
+  });
+
+  it('should generate tick marks when 0 values are present', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [11, 0.8, 0, 28, 7]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.y;
+    // Counts down because the lines are drawn top to bottom
+    expect(getLabels(scale)).toEqual([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30]);
+    expect(scale.start).toEqual(0.1);
+    expect(scale.end).toEqual(30);
+  });
+
+
+  it('should generate tick marks in the correct order in reversed mode', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 5, 1, 25, 78]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            reverse: true,
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.y;
+    expect(getLabels(scale)).toEqual([80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+    expect(scale.start).toEqual(80);
+    expect(scale.end).toEqual(1);
+  });
+
+  it('should generate tick marks in the correct order in reversed mode when 0 values are present', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [21, 9, 0, 10, 25]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            reverse: true,
+            ticks: {
+              callback: function(value) {
+                return value;
+              }
+            }
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.y;
+    expect(getLabels(scale)).toEqual([30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
+    expect(scale.start).toEqual(30);
+    expect(scale.end).toEqual(1);
+  });
+
+  it('should build labels using the default template', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, 5, 1.1, 25, 0, 78]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.y)).toEqual(['1', '2', '', '', '5', '', '', '', '', '10', '20', '', '', '50', '', '', '']);
+  });
+
+  it('should build labels using the user supplied callback', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [10, 5, 2, 25, 78]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            ticks: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    // Just the index
+    expect(getLabels(chart.scales.y)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16']);
+  });
+
+  it('should correctly get the correct label for a data item', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: [10, 5, 5000, 78, 450]
+        }, {
+          yAxisID: 'y1',
+          data: [1, 1000, 10, 100],
+        }, {
+          yAxisID: 'y',
+          data: [150]
+        }],
+        labels: []
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic'
+          },
+          y1: {
+            position: 'right',
+            type: 'logarithmic'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.getLabelForValue(150)).toBe('150');
+  });
+
+  describe('when', function() {
+    var data = [
+      {
+        data: [1, 39],
+        stack: 'stack'
+      },
+      {
+        data: [1, 39],
+        stack: 'stack'
+      },
+    ];
+    var dataWithEmptyStacks = [
+      {
+        data: []
+      },
+      {
+        data: []
+      }
+    ].concat(data);
+    var config = [
+      {
+        axis: 'y',
+        firstTick: 1, // start of the axis (minimum)
+        describe: 'all stacks are defined'
+      },
+      {
+        axis: 'y',
+        data: dataWithEmptyStacks,
+        firstTick: 1,
+        describe: 'not all stacks are defined'
+      },
+      {
+        axis: 'y',
+        scale: {
+          y: {
+            min: 0
+          }
+        },
+        firstTick: 0.1,
+        describe: 'all stacks are defined and min: 0'
+      },
+      {
+        axis: 'y',
+        data: dataWithEmptyStacks,
+        scale: {
+          y: {
+            min: 0
+          }
+        },
+        firstTick: 0.1,
+        describe: 'not stacks are defined and min: 0'
+      },
+      {
+        axis: 'x',
+        firstTick: 1,
+        describe: 'all stacks are defined'
+      },
+      {
+        axis: 'x',
+        data: dataWithEmptyStacks,
+        firstTick: 1,
+        describe: 'not all stacks are defined'
+      },
+      {
+        axis: 'x',
+        scale: {
+          x: {
+            min: 0
+          }
+        },
+        firstTick: 0.1,
+        describe: 'all stacks are defined and min: 0'
+      },
+      {
+        axis: 'x',
+        data: dataWithEmptyStacks,
+        scale: {
+          x: {
+            min: 0
+          }
+        },
+        firstTick: 0.1,
+        describe: 'not all stacks are defined and min: 0'
+      },
+    ];
+    config.forEach(function(setup) {
+      var scaleConfig = {};
+      var indexAxis, chartStart, chartEnd;
+
+      if (setup.axis === 'x') {
+        indexAxis = 'y';
+        chartStart = 'left';
+        chartEnd = 'right';
+      } else {
+        indexAxis = 'x';
+        chartStart = 'bottom';
+        chartEnd = 'top';
+      }
+      scaleConfig[setup.axis] = {
+        type: 'logarithmic',
+        beginAtZero: false
+      };
+      Object.assign(scaleConfig, setup.scale);
+      scaleConfig[setup.axis].type = 'logarithmic';
+
+      var description = 'dataset has stack option and ' + setup.describe
                                + ' and axis is "' + setup.axis + '";';
-                       describe(description, function() {
-                               it('should define the correct axis limits', function() {
-                                       var chart = window.acquireChart({
-                                               type: 'bar',
-                                               data: {
-                                                       labels: ['category 1', 'category 2'],
-                                                       datasets: setup.data || data,
-                                               },
-                                               options: {
-                                                       indexAxis,
-                                                       scales: scaleConfig
-                                               }
-                                       });
-
-                                       var axisID = setup.axis;
-                                       var scale = chart.scales[axisID];
-                                       var firstTick = setup.firstTick;
-                                       var lastTick = 80; // last tick (should be first available tick after: 2 * 39)
-                                       var start = chart.chartArea[chartStart];
-                                       var end = chart.chartArea[chartEnd];
-
-                                       expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
-                                       expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-
-                                       expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
-                                       expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-
-                                       chart.scales[axisID].options.reverse = true; // Reverse mode
-                                       chart.update();
-
-                                       // chartArea might have been resized in update
-                                       start = chart.chartArea[chartEnd];
-                                       end = chart.chartArea[chartStart];
-
-                                       expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
-                                       expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-
-                                       expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
-                                       expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-                               });
-                       });
-               });
-       });
-
-       describe('when', function() {
-               var config = [
-                       {
-                               dataset: [],
-                               firstTick: 1, // value of the first tick
-                               lastTick: 10, // value of the last tick
-                               describe: 'empty dataset, without min/max'
-                       },
-                       {
-                               dataset: [],
-                               scale: {stacked: true},
-                               firstTick: 1,
-                               lastTick: 10,
-                               describe: 'empty dataset, without min/max, with stacked: true'
-                       },
-                       {
-                               data: {
-                                       datasets: [
-                                               {data: [], stack: 'stack'},
-                                               {data: [], stack: 'stack'},
-                                       ],
-                               },
-                               type: 'bar',
-                               firstTick: 1,
-                               lastTick: 10,
-                               describe: 'empty dataset with stack option, without min/max'
-                       },
-                       {
-                               dataset: [],
-                               scale: {min: 1},
-                               firstTick: 1,
-                               lastTick: 10,
-                               describe: 'empty dataset, min: 1, without max'
-                       },
-                       {
-                               dataset: [],
-                               scale: {max: 80},
-                               firstTick: 1,
-                               lastTick: 80,
-                               describe: 'empty dataset, max: 80, without min'
-                       },
-                       {
-                               dataset: [],
-                               scale: {max: 0.8},
-                               firstTick: 0.01,
-                               lastTick: 0.8,
-                               describe: 'empty dataset, max: 0.8, without min'
-                       },
-                       {
-                               dataset: [{x: 10, y: 10}, {x: 5, y: 5}, {x: 1, y: 1}, {x: 25, y: 25}, {x: 78, y: 78}],
-                               firstTick: 1,
-                               lastTick: 80,
-                               describe: 'dataset min point {x: 1, y: 1}, max point {x:78, y:78}'
-                       },
-               ];
-               config.forEach(function(setup) {
-                       var axes = [
-                               {
-                                       id: 'x', // horizontal scale
-                                       start: 'left',
-                                       end: 'right'
-                               },
-                               {
-                                       id: 'y', // vertical scale
-                                       start: 'bottom',
-                                       end: 'top'
-                               }
-                       ];
-                       axes.forEach(function(axis) {
-                               var expectation = 'min = ' + setup.firstTick + ', max = ' + setup.lastTick;
-                               describe(setup.describe + ' and axis is "' + axis.id + '"; expect: ' + expectation + ';', function() {
-                                       beforeEach(function() {
-                                               var xConfig = {
-                                                       type: 'logarithmic',
-                                                       position: 'bottom'
-                                               };
-                                               var yConfig = {
-                                                       type: 'logarithmic',
-                                                       position: 'left'
-                                               };
-                                               var data = setup.data || {
-                                                       datasets: [{
-                                                               data: setup.dataset
-                                                       }],
-                                               };
-                                               Object.assign(xConfig, setup.scale);
-                                               Object.assign(yConfig, setup.scale);
-                                               Object.assign(data, setup.data || {});
-                                               this.chart = window.acquireChart({
-                                                       type: 'line',
-                                                       data: data,
-                                                       options: {
-                                                               scales: {
-                                                                       x: xConfig,
-                                                                       y: yConfig
-                                                               }
-                                                       }
-                                               });
-                                       });
-
-                                       it('should get the correct pixel value for a point', function() {
-                                               var chart = this.chart;
-                                               var axisID = axis.id;
-                                               var scale = chart.scales[axisID];
-                                               var firstTick = setup.firstTick;
-                                               var lastTick = setup.lastTick;
-                                               var start = chart.chartArea[axis.start];
-                                               var end = chart.chartArea[axis.end];
-
-                                               expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
-                                               expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-                                               expect(scale.getPixelForValue(0)).toBeCloseToPixel(start); // 0 is invalid, put it at the start.
-
-                                               expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
-                                               expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-
-                                               chart.scales[axisID].options.reverse = true; // Reverse mode
-                                               chart.update();
-
-                                               // chartArea might have been resized in update
-                                               start = chart.chartArea[axis.end];
-                                               end = chart.chartArea[axis.start];
-
-                                               expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
-                                               expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-
-                                               expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
-                                               expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-                                       });
-                               });
-                       });
-               });
-       });
-
-       describe('when', function() {
-               var config = [
-                       {
-                               dataset: [],
-                               scale: {min: 0},
-                               lastTick: 10, // value of the last tick
-                               describe: 'empty dataset, min: 0, without max'
-                       },
-                       {
-                               dataset: [],
-                               scale: {min: 0, max: 80},
-                               lastTick: 80,
-                               describe: 'empty dataset, min: 0, max: 80'
-                       },
-                       {
-                               dataset: [],
-                               scale: {min: 0, max: 0.8},
-                               lastTick: 0.8,
-                               describe: 'empty dataset, min: 0, max: 0.8'
-                       },
-                       {
-                               dataset: [{x: 0, y: 0}, {x: 10, y: 10}, {x: 1.2, y: 1.2}, {x: 25, y: 25}, {x: 78, y: 78}],
-                               lastTick: 80,
-                               describe: 'dataset min point {x: 0, y: 0}, max point {x:78, y:78}'
-                       },
-                       {
-                               dataset: [{x: 0, y: 0}, {x: 10, y: 10}, {x: 6.3, y: 6.3}, {x: 25, y: 25}, {x: 78, y: 78}],
-                               lastTick: 80,
-                               describe: 'dataset min point {x: 0, y: 0}, max point {x:78, y:78}'
-                       },
-                       {
-                               dataset: [{x: 10, y: 10}, {x: 1.2, y: 1.2}, {x: 25, y: 25}, {x: 78, y: 78}],
-                               scale: {min: 0},
-                               lastTick: 80,
-                               describe: 'dataset min point {x: 1.2, y: 1.2}, max point {x:78, y:78}, min: 0'
-                       },
-                       {
-                               dataset: [{x: 10, y: 10}, {x: 6.3, y: 6.3}, {x: 25, y: 25}, {x: 78, y: 78}],
-                               scale: {min: 0},
-                               lastTick: 80,
-                               describe: 'dataset min point {x: 6.3, y: 6.3}, max point {x:78, y:78}, min: 0'
-                       },
-               ];
-               config.forEach(function(setup) {
-                       var axes = [
-                               {
-                                       id: 'x', // horizontal scale
-                                       start: 'left',
-                                       end: 'right'
-                               },
-                               {
-                                       id: 'y', // vertical scale
-                                       start: 'bottom',
-                                       end: 'top'
-                               }
-                       ];
-                       axes.forEach(function(axis) {
-                               var expectation = 'min = 0, max = ' + setup.lastTick;
-                               describe(setup.describe + ' and axis is "' + axis.id + '"; expect: ' + expectation + ';', function() {
-                                       beforeEach(function() {
-                                               var xConfig = {
-                                                       type: 'logarithmic',
-                                                       position: 'bottom'
-                                               };
-                                               var yConfig = {
-                                                       type: 'logarithmic',
-                                                       position: 'left'
-                                               };
-                                               var data = setup.data || {
-                                                       datasets: [{
-                                                               data: setup.dataset
-                                                       }],
-                                               };
-                                               Object.assign(xConfig, setup.scale);
-                                               Object.assign(yConfig, setup.scale);
-                                               Object.assign(data, setup.data || {});
-                                               this.chart = window.acquireChart({
-                                                       type: 'line',
-                                                       data: data,
-                                                       options: {
-                                                               scales: {
-                                                                       x: xConfig,
-                                                                       y: yConfig
-                                                               }
-                                                       }
-                                               });
-                                       });
-
-                                       it('should get the correct pixel value for a point', function() {
-                                               var chart = this.chart;
-                                               var axisID = axis.id;
-                                               var scale = chart.scales[axisID];
-                                               var lastTick = setup.lastTick;
-                                               var start = chart.chartArea[axis.start];
-                                               var end = chart.chartArea[axis.end];
-
-                                               expect(scale.getPixelForValue(0)).toBeCloseToPixel(start);
-                                               expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-
-                                               expect(scale.getValueForPixel(start)).toBeCloseTo(scale.min, 4);
-                                               expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-
-                                               chart.scales[axisID].options.reverse = true; // Reverse mode
-                                               chart.update();
-
-                                               // chartArea might have been resized in update
-                                               start = chart.chartArea[axis.end];
-                                               end = chart.chartArea[axis.start];
-
-                                               expect(scale.getPixelForValue(0)).toBeCloseToPixel(start);
-                                               expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
-
-                                               expect(scale.getValueForPixel(start)).toBeCloseTo(scale.min, 4);
-                                               expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
-                                       });
-                               });
-                       });
-               });
-       });
-
-       it('Should correctly determine the max & min when no values provided and suggested minimum and maximum are set', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       yAxisID: 'y',
-                                       data: []
-                               }],
-                               labels: ['a', 'b', 'c', 'd', 'e', 'f']
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               suggestedMin: 10,
-                                               suggestedMax: 100
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y).not.toEqual(undefined); // must construct
-               expect(chart.scales.y.min).toBe(10);
-               expect(chart.scales.y.max).toBe(100);
-       });
-
-       it('Should bound to data', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['a', 'b'],
-                               datasets: [{
-                                       data: [1.1, 99]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       y: {
-                                               type: 'logarithmic',
-                                               bounds: 'data'
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.y.min).toEqual(1.1);
-               expect(chart.scales.y.max).toEqual(99);
-       });
+      describe(description, function() {
+        it('should define the correct axis limits', function() {
+          var chart = window.acquireChart({
+            type: 'bar',
+            data: {
+              labels: ['category 1', 'category 2'],
+              datasets: setup.data || data,
+            },
+            options: {
+              indexAxis,
+              scales: scaleConfig
+            }
+          });
+
+          var axisID = setup.axis;
+          var scale = chart.scales[axisID];
+          var firstTick = setup.firstTick;
+          var lastTick = 80; // last tick (should be first available tick after: 2 * 39)
+          var start = chart.chartArea[chartStart];
+          var end = chart.chartArea[chartEnd];
+
+          expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
+          expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+
+          expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
+          expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+
+          chart.scales[axisID].options.reverse = true; // Reverse mode
+          chart.update();
+
+          // chartArea might have been resized in update
+          start = chart.chartArea[chartEnd];
+          end = chart.chartArea[chartStart];
+
+          expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
+          expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+
+          expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
+          expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+        });
+      });
+    });
+  });
+
+  describe('when', function() {
+    var config = [
+      {
+        dataset: [],
+        firstTick: 1, // value of the first tick
+        lastTick: 10, // value of the last tick
+        describe: 'empty dataset, without min/max'
+      },
+      {
+        dataset: [],
+        scale: {stacked: true},
+        firstTick: 1,
+        lastTick: 10,
+        describe: 'empty dataset, without min/max, with stacked: true'
+      },
+      {
+        data: {
+          datasets: [
+            {data: [], stack: 'stack'},
+            {data: [], stack: 'stack'},
+          ],
+        },
+        type: 'bar',
+        firstTick: 1,
+        lastTick: 10,
+        describe: 'empty dataset with stack option, without min/max'
+      },
+      {
+        dataset: [],
+        scale: {min: 1},
+        firstTick: 1,
+        lastTick: 10,
+        describe: 'empty dataset, min: 1, without max'
+      },
+      {
+        dataset: [],
+        scale: {max: 80},
+        firstTick: 1,
+        lastTick: 80,
+        describe: 'empty dataset, max: 80, without min'
+      },
+      {
+        dataset: [],
+        scale: {max: 0.8},
+        firstTick: 0.01,
+        lastTick: 0.8,
+        describe: 'empty dataset, max: 0.8, without min'
+      },
+      {
+        dataset: [{x: 10, y: 10}, {x: 5, y: 5}, {x: 1, y: 1}, {x: 25, y: 25}, {x: 78, y: 78}],
+        firstTick: 1,
+        lastTick: 80,
+        describe: 'dataset min point {x: 1, y: 1}, max point {x:78, y:78}'
+      },
+    ];
+    config.forEach(function(setup) {
+      var axes = [
+        {
+          id: 'x', // horizontal scale
+          start: 'left',
+          end: 'right'
+        },
+        {
+          id: 'y', // vertical scale
+          start: 'bottom',
+          end: 'top'
+        }
+      ];
+      axes.forEach(function(axis) {
+        var expectation = 'min = ' + setup.firstTick + ', max = ' + setup.lastTick;
+        describe(setup.describe + ' and axis is "' + axis.id + '"; expect: ' + expectation + ';', function() {
+          beforeEach(function() {
+            var xConfig = {
+              type: 'logarithmic',
+              position: 'bottom'
+            };
+            var yConfig = {
+              type: 'logarithmic',
+              position: 'left'
+            };
+            var data = setup.data || {
+              datasets: [{
+                data: setup.dataset
+              }],
+            };
+            Object.assign(xConfig, setup.scale);
+            Object.assign(yConfig, setup.scale);
+            Object.assign(data, setup.data || {});
+            this.chart = window.acquireChart({
+              type: 'line',
+              data: data,
+              options: {
+                scales: {
+                  x: xConfig,
+                  y: yConfig
+                }
+              }
+            });
+          });
+
+          it('should get the correct pixel value for a point', function() {
+            var chart = this.chart;
+            var axisID = axis.id;
+            var scale = chart.scales[axisID];
+            var firstTick = setup.firstTick;
+            var lastTick = setup.lastTick;
+            var start = chart.chartArea[axis.start];
+            var end = chart.chartArea[axis.end];
+
+            expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
+            expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+            expect(scale.getPixelForValue(0)).toBeCloseToPixel(start); // 0 is invalid, put it at the start.
+
+            expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
+            expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+
+            chart.scales[axisID].options.reverse = true; // Reverse mode
+            chart.update();
+
+            // chartArea might have been resized in update
+            start = chart.chartArea[axis.end];
+            end = chart.chartArea[axis.start];
+
+            expect(scale.getPixelForValue(firstTick)).toBeCloseToPixel(start);
+            expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+
+            expect(scale.getValueForPixel(start)).toBeCloseTo(firstTick, 4);
+            expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+          });
+        });
+      });
+    });
+  });
+
+  describe('when', function() {
+    var config = [
+      {
+        dataset: [],
+        scale: {min: 0},
+        lastTick: 10, // value of the last tick
+        describe: 'empty dataset, min: 0, without max'
+      },
+      {
+        dataset: [],
+        scale: {min: 0, max: 80},
+        lastTick: 80,
+        describe: 'empty dataset, min: 0, max: 80'
+      },
+      {
+        dataset: [],
+        scale: {min: 0, max: 0.8},
+        lastTick: 0.8,
+        describe: 'empty dataset, min: 0, max: 0.8'
+      },
+      {
+        dataset: [{x: 0, y: 0}, {x: 10, y: 10}, {x: 1.2, y: 1.2}, {x: 25, y: 25}, {x: 78, y: 78}],
+        lastTick: 80,
+        describe: 'dataset min point {x: 0, y: 0}, max point {x:78, y:78}'
+      },
+      {
+        dataset: [{x: 0, y: 0}, {x: 10, y: 10}, {x: 6.3, y: 6.3}, {x: 25, y: 25}, {x: 78, y: 78}],
+        lastTick: 80,
+        describe: 'dataset min point {x: 0, y: 0}, max point {x:78, y:78}'
+      },
+      {
+        dataset: [{x: 10, y: 10}, {x: 1.2, y: 1.2}, {x: 25, y: 25}, {x: 78, y: 78}],
+        scale: {min: 0},
+        lastTick: 80,
+        describe: 'dataset min point {x: 1.2, y: 1.2}, max point {x:78, y:78}, min: 0'
+      },
+      {
+        dataset: [{x: 10, y: 10}, {x: 6.3, y: 6.3}, {x: 25, y: 25}, {x: 78, y: 78}],
+        scale: {min: 0},
+        lastTick: 80,
+        describe: 'dataset min point {x: 6.3, y: 6.3}, max point {x:78, y:78}, min: 0'
+      },
+    ];
+    config.forEach(function(setup) {
+      var axes = [
+        {
+          id: 'x', // horizontal scale
+          start: 'left',
+          end: 'right'
+        },
+        {
+          id: 'y', // vertical scale
+          start: 'bottom',
+          end: 'top'
+        }
+      ];
+      axes.forEach(function(axis) {
+        var expectation = 'min = 0, max = ' + setup.lastTick;
+        describe(setup.describe + ' and axis is "' + axis.id + '"; expect: ' + expectation + ';', function() {
+          beforeEach(function() {
+            var xConfig = {
+              type: 'logarithmic',
+              position: 'bottom'
+            };
+            var yConfig = {
+              type: 'logarithmic',
+              position: 'left'
+            };
+            var data = setup.data || {
+              datasets: [{
+                data: setup.dataset
+              }],
+            };
+            Object.assign(xConfig, setup.scale);
+            Object.assign(yConfig, setup.scale);
+            Object.assign(data, setup.data || {});
+            this.chart = window.acquireChart({
+              type: 'line',
+              data: data,
+              options: {
+                scales: {
+                  x: xConfig,
+                  y: yConfig
+                }
+              }
+            });
+          });
+
+          it('should get the correct pixel value for a point', function() {
+            var chart = this.chart;
+            var axisID = axis.id;
+            var scale = chart.scales[axisID];
+            var lastTick = setup.lastTick;
+            var start = chart.chartArea[axis.start];
+            var end = chart.chartArea[axis.end];
+
+            expect(scale.getPixelForValue(0)).toBeCloseToPixel(start);
+            expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+
+            expect(scale.getValueForPixel(start)).toBeCloseTo(scale.min, 4);
+            expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+
+            chart.scales[axisID].options.reverse = true; // Reverse mode
+            chart.update();
+
+            // chartArea might have been resized in update
+            start = chart.chartArea[axis.end];
+            end = chart.chartArea[axis.start];
+
+            expect(scale.getPixelForValue(0)).toBeCloseToPixel(start);
+            expect(scale.getPixelForValue(lastTick)).toBeCloseToPixel(end);
+
+            expect(scale.getValueForPixel(start)).toBeCloseTo(scale.min, 4);
+            expect(scale.getValueForPixel(end)).toBeCloseTo(lastTick, 4);
+          });
+        });
+      });
+    });
+  });
+
+  it('Should correctly determine the max & min when no values provided and suggested minimum and maximum are set', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          yAxisID: 'y',
+          data: []
+        }],
+        labels: ['a', 'b', 'c', 'd', 'e', 'f']
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            suggestedMin: 10,
+            suggestedMax: 100
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y).not.toEqual(undefined); // must construct
+    expect(chart.scales.y.min).toBe(10);
+    expect(chart.scales.y.max).toBe(100);
+  });
+
+  it('Should bound to data', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: ['a', 'b'],
+        datasets: [{
+          data: [1.1, 99]
+        }]
+      },
+      options: {
+        scales: {
+          y: {
+            type: 'logarithmic',
+            bounds: 'data'
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.y.min).toEqual(1.1);
+    expect(chart.scales.y.max).toEqual(99);
+  });
 });
index be0c701ae6b51e99674e56f9bcb592441d3349f7..745e95d1a87818bfea85f7501fcb3dddc0569c90 100644 (file)
 function getLabels(scale) {
-       return scale.ticks.map(t => t.label);
+  return scale.ticks.map(t => t.label);
 }
 
 // Tests for the radial linear scale used by the polar area and radar charts
 describe('Test the radial linear scale', function() {
-       describe('auto', jasmine.fixture.specs('scale.radialLinear'));
-
-       it('Should register the constructor with the registry', function() {
-               var Constructor = Chart.registry.getScale('radialLinear');
-               expect(Constructor).not.toBe(undefined);
-               expect(typeof Constructor).toBe('function');
-       });
-
-       it('Should have the correct default config', function() {
-               var defaultConfig = Chart.defaults.scales.radialLinear;
-               expect(defaultConfig).toEqual({
-                       display: true,
-                       animate: true,
-                       position: 'chartArea',
-
-                       angleLines: {
-                               display: true,
-                               color: 'rgba(0,0,0,0.1)',
-                               lineWidth: 1,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-
-                       gridLines: {
-                               circular: false
-                       },
-
-                       ticks: {
-                               color: Chart.defaults.color,
-                               showLabelBackdrop: true,
-                               backdropColor: 'rgba(255,255,255,0.75)',
-                               backdropPaddingY: 2,
-                               backdropPaddingX: 2,
-                               callback: defaultConfig.ticks.callback
-                       },
-
-                       pointLabels: {
-                               color: Chart.defaults.color,
-                               display: true,
-                               font: {
-                                       size: 10
-                               },
-                               callback: defaultConfig.pointLabels.callback
-                       }
-               });
-
-               // Is this actually a function
-               expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
-               expect(defaultConfig.pointLabels.callback).toEqual(jasmine.any(Function));
-       });
-
-       it('Should correctly determine the max & min data values', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, -5, 78, -100]
-                               }, {
-                                       data: [150]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
-                       },
-                       options: {
-                               scales: {}
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(-100);
-               expect(chart.scales.r.max).toBe(150);
-       });
-
-       it('Should correctly determine the max & min of string data values', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: ['10', '5', '0', '-5', '78', '-100']
-                               }, {
-                                       data: ['150']
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
-                       },
-                       options: {
-                               scales: {}
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(-100);
-               expect(chart.scales.r.max).toBe(150);
-       });
-
-       it('Should correctly determine the max & min data values when there are hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: ['10', '5', '0', '-5', '78', '-100']
-                               }, {
-                                       data: ['150']
-                               }, {
-                                       data: [1000],
-                                       hidden: true
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
-                       },
-                       options: {
-                               scales: {}
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(-100);
-               expect(chart.scales.r.max).toBe(150);
-       });
-
-       it('Should correctly determine the max & min data values when there is NaN data', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [50, 60, NaN, 70, null, undefined, Infinity, -Infinity]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6', 'label7', 'label8']
-                       },
-                       options: {
-                               scales: {}
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(50);
-               expect(chart.scales.r.max).toBe(70);
-       });
-
-       it('Should ensure that the scale has a max and min that are not equal', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [],
-                               labels: []
-                       },
-                       options: {
-                               scales: {
-                                       rScale: {}
-                               }
-                       }
-               });
-
-               var scale = chart.scales.rScale;
-
-               expect(scale.min).toBe(-1);
-               expect(scale.max).toBe(1);
-       });
-
-       it('Should use the suggestedMin and suggestedMax options', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               suggestedMin: -10,
-                                               suggestedMax: 10
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(-10);
-               expect(chart.scales.r.max).toBe(10);
-       });
-
-       it('Should use the min and max options', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [1, 1, 1, 2, 1, 0]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               min: -1010,
-                                               max: 1010
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.min).toBe(-1010);
-               expect(chart.scales.r.max).toBe(1010);
-               expect(getLabels(chart.scales.r)).toEqual(['-1,010', '-1,000', '-500', '0', '500', '1,000', '1,010']);
-       });
-
-       it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [20, 30, 40, 50]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               beginAtZero: false
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.r)).toEqual(['20', '25', '30', '35', '40', '45', '50']);
-
-               chart.scales.r.options.beginAtZero = true;
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['0', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50']);
-
-               chart.data.datasets[0].data = [-20, -30, -40, -50];
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20', '-15', '-10', '-5', '0']);
-
-               chart.scales.r.options.beginAtZero = false;
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20']);
-       });
-
-       it('Should generate tick marks in the correct order in reversed mode', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               reverse: true
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.r)).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '0']);
-               expect(chart.scales.r.start).toBe(80);
-               expect(chart.scales.r.end).toBe(0);
-       });
-
-       it('Should correctly limit the maximum number of ticks', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               labels: ['label1', 'label2', 'label3'],
-                               datasets: [{
-                                       data: [0.5, 1.5, 2.5]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       display: false
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.r.ticks.maxTicksLimit = 11;
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.r.ticks.stepSize = 0.01;
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
-
-               chart.options.scales.r.min = 0.3;
-               chart.options.scales.r.max = 2.8;
-               chart.update();
-
-               expect(getLabels(chart.scales.r)).toEqual(['0.3', '0.8', '1.3', '1.8', '2.3', '2.8']);
-       });
-
-       it('Should build labels using the user supplied callback', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               ticks: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.r)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']);
-               expect(chart.scales.r.pointLabels).toEqual(['label1', 'label2', 'label3', 'label4', 'label5']);
-       });
-
-       it('Should build point labels using the user supplied callback', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.pointLabels).toEqual(['0', '1', '2', '3', '4']);
-       });
-
-       it('Should build point labels from falsy values', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78, 20]
-                               }],
-                               labels: [0, '', undefined, null, NaN, false]
-                       }
-               });
-
-               expect(chart.scales.r.pointLabels).toEqual([0, '', '', '', '', '']);
-       });
-
-       it('should correctly set the center point', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.drawingArea).toBe(227);
-               expect(chart.scales.r.xCenter).toBe(256);
-               expect(chart.scales.r.yCenter).toBe(284);
-       });
-
-       it('should correctly get the label for a given data index', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-               expect(chart.scales.r.getLabelForValue(5)).toBe('5');
-       });
-
-       it('should get the correct distance from the center point', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.min)).toBe(0);
-               expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.max)).toBe(227);
-
-               var position = chart.scales.r.getPointPositionForValue(1, 5);
-               expect(position.x).toBeCloseToPixel(270);
-               expect(position.y).toBeCloseToPixel(278);
-
-               chart.scales.r.options.reverse = true;
-               chart.update();
-
-               expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.min)).toBe(227);
-               expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.max)).toBe(0);
-       });
-
-       it('should get the correct value for a distance from the center point', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               expect(chart.scales.r.getValueForDistanceFromCenter(0)).toBe(chart.scales.r.min);
-               expect(chart.scales.r.getValueForDistanceFromCenter(227)).toBe(chart.scales.r.max);
-
-               var dist = chart.scales.r.getDistanceFromCenterForValue(5);
-               expect(chart.scales.r.getValueForDistanceFromCenter(dist)).toBe(5);
-
-               chart.scales.r.options.reverse = true;
-               chart.update();
-
-               expect(chart.scales.r.getValueForDistanceFromCenter(0)).toBe(chart.scales.r.max);
-               expect(chart.scales.r.getValueForDistanceFromCenter(227)).toBe(chart.scales.r.min);
-       });
-
-       it('should correctly get angles for all points', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               }
-                                       }
-                               },
-                               startAngle: 15
-                       }
-               });
-
-               var radToNearestDegree = function(rad) {
-                       return Math.round((360 * rad) / (2 * Math.PI));
-               };
-
-               var slice = 72; // (360 / 5)
-
-               for (var i = 0; i < 5; i++) {
-                       expect(radToNearestDegree(chart.scales.r.getIndexAngle(i))).toBe(15 + (slice * i));
-               }
-
-               chart.options.startAngle = 0;
-               chart.update();
-
-               for (var x = 0; x < 5; x++) {
-                       expect(radToNearestDegree(chart.scales.r.getIndexAngle(x))).toBe((slice * x));
-               }
-       });
-
-       it('should correctly get the correct label alignment for all points', function() {
-               var chart = window.acquireChart({
-                       type: 'radar',
-                       data: {
-                               datasets: [{
-                                       data: [10, 5, 0, 25, 78]
-                               }],
-                               labels: ['label1', 'label2', 'label3', 'label4', 'label5']
-                       },
-                       options: {
-                               scales: {
-                                       r: {
-                                               pointLabels: {
-                                                       callback: function(value, index) {
-                                                               return index.toString();
-                                                       }
-                                               },
-                                               ticks: {
-                                                       display: false
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var scale = chart.scales.r;
-
-               [{
-                       startAngle: 30,
-                       textAlign: ['right', 'right', 'left', 'left', 'left'],
-                       y: [82, 366, 506, 319, 53]
-               }, {
-                       startAngle: -30,
-                       textAlign: ['right', 'right', 'left', 'left', 'right'],
-                       y: [319, 506, 366, 82, 53]
-               }, {
-                       startAngle: 750,
-                       textAlign: ['right', 'right', 'left', 'left', 'left'],
-                       y: [82, 366, 506, 319, 53]
-               }].forEach(function(expected) {
-                       chart.options.startAngle = expected.startAngle;
-                       chart.update();
-
-                       scale.ctx = window.createMockContext();
-                       chart.draw();
-
-                       scale.ctx.getCalls().filter(function(x) {
-                               return x.name === 'setTextAlign';
-                       }).forEach(function(x, i) {
-                               expect(x.args[0]).withContext('startAngle: ' + expected.startAngle + ', tick: ' + i).toBe(expected.textAlign[i]);
-                       });
-
-                       scale.ctx.getCalls().filter(function(x) {
-                               return x.name === 'fillText';
-                       }).map(function(x, i) {
-                               expect(x.args[2]).toBeCloseToPixel(expected.y[i]);
-                       });
-               });
-       });
+  describe('auto', jasmine.fixture.specs('scale.radialLinear'));
+
+  it('Should register the constructor with the registry', function() {
+    var Constructor = Chart.registry.getScale('radialLinear');
+    expect(Constructor).not.toBe(undefined);
+    expect(typeof Constructor).toBe('function');
+  });
+
+  it('Should have the correct default config', function() {
+    var defaultConfig = Chart.defaults.scales.radialLinear;
+    expect(defaultConfig).toEqual({
+      display: true,
+      animate: true,
+      position: 'chartArea',
+
+      angleLines: {
+        display: true,
+        color: 'rgba(0,0,0,0.1)',
+        lineWidth: 1,
+        borderDash: [],
+        borderDashOffset: 0.0
+      },
+
+      gridLines: {
+        circular: false
+      },
+
+      ticks: {
+        color: Chart.defaults.color,
+        showLabelBackdrop: true,
+        backdropColor: 'rgba(255,255,255,0.75)',
+        backdropPaddingY: 2,
+        backdropPaddingX: 2,
+        callback: defaultConfig.ticks.callback
+      },
+
+      pointLabels: {
+        color: Chart.defaults.color,
+        display: true,
+        font: {
+          size: 10
+        },
+        callback: defaultConfig.pointLabels.callback
+      }
+    });
+
+    // Is this actually a function
+    expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
+    expect(defaultConfig.pointLabels.callback).toEqual(jasmine.any(Function));
+  });
+
+  it('Should correctly determine the max & min data values', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, -5, 78, -100]
+        }, {
+          data: [150]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
+      },
+      options: {
+        scales: {}
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(-100);
+    expect(chart.scales.r.max).toBe(150);
+  });
+
+  it('Should correctly determine the max & min of string data values', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: ['10', '5', '0', '-5', '78', '-100']
+        }, {
+          data: ['150']
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
+      },
+      options: {
+        scales: {}
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(-100);
+    expect(chart.scales.r.max).toBe(150);
+  });
+
+  it('Should correctly determine the max & min data values when there are hidden datasets', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: ['10', '5', '0', '-5', '78', '-100']
+        }, {
+          data: ['150']
+        }, {
+          data: [1000],
+          hidden: true
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
+      },
+      options: {
+        scales: {}
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(-100);
+    expect(chart.scales.r.max).toBe(150);
+  });
+
+  it('Should correctly determine the max & min data values when there is NaN data', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [50, 60, NaN, 70, null, undefined, Infinity, -Infinity]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6', 'label7', 'label8']
+      },
+      options: {
+        scales: {}
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(50);
+    expect(chart.scales.r.max).toBe(70);
+  });
+
+  it('Should ensure that the scale has a max and min that are not equal', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [],
+        labels: []
+      },
+      options: {
+        scales: {
+          rScale: {}
+        }
+      }
+    });
+
+    var scale = chart.scales.rScale;
+
+    expect(scale.min).toBe(-1);
+    expect(scale.max).toBe(1);
+  });
+
+  it('Should use the suggestedMin and suggestedMax options', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
+      },
+      options: {
+        scales: {
+          r: {
+            suggestedMin: -10,
+            suggestedMax: 10
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(-10);
+    expect(chart.scales.r.max).toBe(10);
+  });
+
+  it('Should use the min and max options', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [1, 1, 1, 2, 1, 0]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6']
+      },
+      options: {
+        scales: {
+          r: {
+            min: -1010,
+            max: 1010
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.min).toBe(-1010);
+    expect(chart.scales.r.max).toBe(1010);
+    expect(getLabels(chart.scales.r)).toEqual(['-1,010', '-1,000', '-500', '0', '500', '1,000', '1,010']);
+  });
+
+  it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [20, 30, 40, 50]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      },
+      options: {
+        scales: {
+          r: {
+            beginAtZero: false
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.r)).toEqual(['20', '25', '30', '35', '40', '45', '50']);
+
+    chart.scales.r.options.beginAtZero = true;
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['0', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50']);
+
+    chart.data.datasets[0].data = [-20, -30, -40, -50];
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20', '-15', '-10', '-5', '0']);
+
+    chart.scales.r.options.beginAtZero = false;
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20']);
+  });
+
+  it('Should generate tick marks in the correct order in reversed mode', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            reverse: true
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.r)).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '0']);
+    expect(chart.scales.r.start).toBe(80);
+    expect(chart.scales.r.end).toBe(0);
+  });
+
+  it('Should correctly limit the maximum number of ticks', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        labels: ['label1', 'label2', 'label3'],
+        datasets: [{
+          data: [0.5, 1.5, 2.5]
+        }]
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              display: false
+            }
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.r.ticks.maxTicksLimit = 11;
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.r.ticks.stepSize = 0.01;
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['0.5', '1.0', '1.5', '2.0', '2.5']);
+
+    chart.options.scales.r.min = 0.3;
+    chart.options.scales.r.max = 2.8;
+    chart.update();
+
+    expect(getLabels(chart.scales.r)).toEqual(['0.3', '0.8', '1.3', '1.8', '2.3', '2.8']);
+  });
+
+  it('Should build labels using the user supplied callback', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            ticks: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.r)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']);
+    expect(chart.scales.r.pointLabels).toEqual(['label1', 'label2', 'label3', 'label4', 'label5']);
+  });
+
+  it('Should build point labels using the user supplied callback', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.pointLabels).toEqual(['0', '1', '2', '3', '4']);
+  });
+
+  it('Should build point labels from falsy values', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78, 20]
+        }],
+        labels: [0, '', undefined, null, NaN, false]
+      }
+    });
+
+    expect(chart.scales.r.pointLabels).toEqual([0, '', '', '', '', '']);
+  });
+
+  it('should correctly set the center point', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.drawingArea).toBe(227);
+    expect(chart.scales.r.xCenter).toBe(256);
+    expect(chart.scales.r.yCenter).toBe(284);
+  });
+
+  it('should correctly get the label for a given data index', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+    expect(chart.scales.r.getLabelForValue(5)).toBe('5');
+  });
+
+  it('should get the correct distance from the center point', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.min)).toBe(0);
+    expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.max)).toBe(227);
+
+    var position = chart.scales.r.getPointPositionForValue(1, 5);
+    expect(position.x).toBeCloseToPixel(270);
+    expect(position.y).toBeCloseToPixel(278);
+
+    chart.scales.r.options.reverse = true;
+    chart.update();
+
+    expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.min)).toBe(227);
+    expect(chart.scales.r.getDistanceFromCenterForValue(chart.scales.r.max)).toBe(0);
+  });
+
+  it('should get the correct value for a distance from the center point', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        }
+      }
+    });
+
+    expect(chart.scales.r.getValueForDistanceFromCenter(0)).toBe(chart.scales.r.min);
+    expect(chart.scales.r.getValueForDistanceFromCenter(227)).toBe(chart.scales.r.max);
+
+    var dist = chart.scales.r.getDistanceFromCenterForValue(5);
+    expect(chart.scales.r.getValueForDistanceFromCenter(dist)).toBe(5);
+
+    chart.scales.r.options.reverse = true;
+    chart.update();
+
+    expect(chart.scales.r.getValueForDistanceFromCenter(0)).toBe(chart.scales.r.max);
+    expect(chart.scales.r.getValueForDistanceFromCenter(227)).toBe(chart.scales.r.min);
+  });
+
+  it('should correctly get angles for all points', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            }
+          }
+        },
+        startAngle: 15
+      }
+    });
+
+    var radToNearestDegree = function(rad) {
+      return Math.round((360 * rad) / (2 * Math.PI));
+    };
+
+    var slice = 72; // (360 / 5)
+
+    for (var i = 0; i < 5; i++) {
+      expect(radToNearestDegree(chart.scales.r.getIndexAngle(i))).toBe(15 + (slice * i));
+    }
+
+    chart.options.startAngle = 0;
+    chart.update();
+
+    for (var x = 0; x < 5; x++) {
+      expect(radToNearestDegree(chart.scales.r.getIndexAngle(x))).toBe((slice * x));
+    }
+  });
+
+  it('should correctly get the correct label alignment for all points', function() {
+    var chart = window.acquireChart({
+      type: 'radar',
+      data: {
+        datasets: [{
+          data: [10, 5, 0, 25, 78]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4', 'label5']
+      },
+      options: {
+        scales: {
+          r: {
+            pointLabels: {
+              callback: function(value, index) {
+                return index.toString();
+              }
+            },
+            ticks: {
+              display: false
+            }
+          }
+        }
+      }
+    });
+
+    var scale = chart.scales.r;
+
+    [{
+      startAngle: 30,
+      textAlign: ['right', 'right', 'left', 'left', 'left'],
+      y: [82, 366, 506, 319, 53]
+    }, {
+      startAngle: -30,
+      textAlign: ['right', 'right', 'left', 'left', 'right'],
+      y: [319, 506, 366, 82, 53]
+    }, {
+      startAngle: 750,
+      textAlign: ['right', 'right', 'left', 'left', 'left'],
+      y: [82, 366, 506, 319, 53]
+    }].forEach(function(expected) {
+      chart.options.startAngle = expected.startAngle;
+      chart.update();
+
+      scale.ctx = window.createMockContext();
+      chart.draw();
+
+      scale.ctx.getCalls().filter(function(x) {
+        return x.name === 'setTextAlign';
+      }).forEach(function(x, i) {
+        expect(x.args[0]).withContext('startAngle: ' + expected.startAngle + ', tick: ' + i).toBe(expected.textAlign[i]);
+      });
+
+      scale.ctx.getCalls().filter(function(x) {
+        return x.name === 'fillText';
+      }).map(function(x, i) {
+        expect(x.args[2]).toBeCloseToPixel(expected.y[i]);
+      });
+    });
+  });
 });
index 57add916005b3516d73e6f70dcf0ec3f50ff2f59..40f790ff8a016ecde86dc9bfe89928f89c07823f 100644 (file)
 // Time scale tests
 describe('Time scale tests', function() {
-       describe('auto', jasmine.fixture.specs('scale.time'));
-
-       function createScale(data, options, dimensions) {
-               var width = (dimensions && dimensions.width) || 400;
-               var height = (dimensions && dimensions.height) || 50;
-
-               options = options || {};
-               options.type = 'time';
-               options.id = 'xScale0';
-
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: data,
-                       options: {
-                               scales: {
-                                       x: options
-                               }
-                       }
-               }, {canvas: {width: width, height: height}});
-
-
-               return chart.scales.x;
-       }
-
-       function getLabels(scale) {
-               return scale.ticks.map(t => t.label);
-       }
-
-       beforeEach(function() {
-               // Need a time matcher for getValueFromPixel
-               jasmine.addMatchers({
-                       toBeCloseToTime: function() {
-                               return {
-                                       compare: function(time, expected) {
-                                               var result = false;
-                                               var actual = moment(time);
-                                               var diff = actual.diff(expected.value, expected.unit, true);
-                                               result = Math.abs(diff) < (expected.threshold !== undefined ? expected.threshold : 0.01);
-
-                                               return {
-                                                       pass: result
-                                               };
-                                       }
-                               };
-                       }
-               });
-       });
-
-       it('should load moment.js as a dependency', function() {
-               expect(window.moment).not.toBe(undefined);
-       });
-
-       it('should register the constructor with the registry', function() {
-               var Constructor = Chart.registry.getScale('time');
-               expect(Constructor).not.toBe(undefined);
-               expect(typeof Constructor).toBe('function');
-       });
-
-       it('should have the correct default config', function() {
-               var defaultConfig = Chart.defaults.scales.time;
-               expect(defaultConfig).toEqual({
-                       bounds: 'data',
-                       adapters: {},
-                       time: {
-                               parser: false, // false == a pattern string from or a custom callback that converts its argument to a timestamp
-                               unit: false, // false == automatic or override with week, month, year, etc.
-                               round: false, // none, or override with week, month, year, etc.
-                               isoWeekday: false, // override week start day
-                               minUnit: 'millisecond',
-                               displayFormats: {}
-                       },
-                       ticks: {
-                               source: 'auto',
-                               major: {
-                                       enabled: false
-                               }
-                       }
-               });
-       });
-
-       it('should correctly determine the unit', function() {
-               var date = moment('Jan 01 1990', 'MMM DD YYYY');
-               var data = [];
-               for (var i = 0; i < 60; i++) {
-                       data.push({x: date.valueOf(), y: Math.random()});
-                       date = date.clone().add(1, 'month');
-               }
-
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: data
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               ticks: {
-                                                       source: 'data',
-                                                       autoSkip: true
-                                               }
-                                       },
-                               }
-                       }
-               });
-
-               var scale = chart.scales.x;
-
-               expect(scale._unit).toEqual('month');
-       });
-
-       describe('when specifying limits', function() {
-               var mockData = {
-                       labels: ['2015-01-01T20:00:00', '2015-01-02T20:00:00', '2015-01-03T20:00:00'],
-               };
-
-               var config;
-               beforeEach(function() {
-                       config = Chart.helpers.clone(Chart.defaults.scales.time);
-                       config.ticks.source = 'labels';
-                       config.time.unit = 'day';
-               });
-
-               it('should use the min option when less than first label for building ticks', function() {
-                       config.min = '2014-12-29T04:00:00';
-
-                       var labels = getLabels(createScale(mockData, config));
-                       expect(labels[0]).toEqual('Jan 1');
-               });
-
-               it('should use the min option when greater than first label for building ticks', function() {
-                       config.min = '2015-01-02T04:00:00';
-
-                       var labels = getLabels(createScale(mockData, config));
-                       expect(labels[0]).toEqual('Jan 2');
-               });
-
-               it('should use the max option when greater than last label for building ticks', function() {
-                       config.max = '2015-01-05T06:00:00';
-
-                       var labels = getLabels(createScale(mockData, config));
-                       expect(labels[labels.length - 1]).toEqual('Jan 3');
-               });
-
-               it('should use the max option when less than last label for building ticks', function() {
-                       config.max = '2015-01-02T23:00:00';
-
-                       var labels = getLabels(createScale(mockData, config));
-                       expect(labels[labels.length - 1]).toEqual('Jan 2');
-               });
-       });
-
-       it('should use the isoWeekday option', function() {
-               var mockData = {
-                       labels: [
-                               '2015-01-01T20:00:00', // Thursday
-                               '2015-01-02T20:00:00', // Friday
-                               '2015-01-03T20:00:00' // Saturday
-                       ]
-               };
-
-               var config = Chart.helpers.mergeIf({
-                       bounds: 'ticks',
-                       time: {
-                               unit: 'week',
-                               isoWeekday: 3 // Wednesday
-                       }
-               }, Chart.defaults.scales.time);
-
-               var scale = createScale(mockData, config);
-               var ticks = getLabels(scale);
-
-               expect(ticks).toEqual(['Dec 31, 2014', 'Jan 7, 2015']);
-       });
-
-       describe('when rendering several days', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               xAxisID: 'x',
-                                               data: []
-                                       }],
-                                       labels: [
-                                               '2015-01-01T20:00:00',
-                                               '2015-01-02T21:00:00',
-                                               '2015-01-03T22:00:00',
-                                               '2015-01-05T23:00:00',
-                                               '2015-01-07T03:00',
-                                               '2015-01-08T10:00',
-                                               '2015-01-10T12:00'
-                                       ]
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'time',
-                                                       position: 'bottom'
-                                               },
-                                       }
-                               }
-                       });
-
-                       this.scale = this.chart.scales.x;
-               });
-
-               it('should be bounded by the nearest week beginnings', function() {
-                       var chart = this.chart;
-                       var scale = this.scale;
-                       expect(scale.getValueForPixel(scale.left)).toBeGreaterThan(moment(chart.data.labels[0]).startOf('week'));
-                       expect(scale.getValueForPixel(scale.right)).toBeLessThan(moment(chart.data.labels[chart.data.labels.length - 1]).add(1, 'week').endOf('week'));
-               });
-
-               it('should convert between screen coordinates and times', function() {
-                       var chart = this.chart;
-                       var scale = this.scale;
-                       var timeRange = moment(scale.max).valueOf() - moment(scale.min).valueOf();
-                       var msPerPix = timeRange / scale.width;
-                       var firstPointOffsetMs = moment(chart.config.data.labels[0]).valueOf() - scale.min;
-                       var firstPointPixel = scale.left + firstPointOffsetMs / msPerPix;
-                       var lastPointOffsetMs = moment(chart.config.data.labels[chart.config.data.labels.length - 1]).valueOf() - scale.min;
-                       var lastPointPixel = scale.left + lastPointOffsetMs / msPerPix;
-
-                       expect(scale.getPixelForValue(moment('2015-01-01T20:00:00').valueOf())).toBeCloseToPixel(firstPointPixel);
-                       expect(scale.getPixelForValue(moment(chart.data.labels[0]).valueOf())).toBeCloseToPixel(firstPointPixel);
-                       expect(scale.getValueForPixel(firstPointPixel)).toBeCloseToTime({
-                               value: moment(chart.data.labels[0]),
-                               unit: 'hour',
-                       });
-
-                       expect(scale.getPixelForValue(moment('2015-01-10T12:00').valueOf())).toBeCloseToPixel(lastPointPixel);
-                       expect(scale.getValueForPixel(lastPointPixel)).toBeCloseToTime({
-                               value: moment(chart.data.labels[6]),
-                               unit: 'hour'
-                       });
-               });
-       });
-
-       describe('when rendering several years', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       labels: ['2005-07-04', '2017-01-20'],
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'time',
-                                                       bounds: 'ticks',
-                                                       position: 'bottom'
-                                               },
-                                       }
-                               }
-                       }, {canvas: {width: 800, height: 200}});
-
-                       this.scale = this.chart.scales.x;
-               });
-
-               it('should be bounded by nearest step\'s year start and end', function() {
-                       var scale = this.scale;
-                       var ticks = scale.getTicks();
-                       var step = ticks[1].value - ticks[0].value;
-                       var stepsAmount = Math.floor((scale.max - scale.min) / step);
-
-                       expect(scale.getValueForPixel(scale.left)).toBeCloseToTime({
-                               value: moment(scale.min).startOf('year'),
-                               unit: 'hour',
-                       });
-                       expect(scale.getValueForPixel(scale.right)).toBeCloseToTime({
-                               value: moment(scale.min + step * stepsAmount).endOf('year'),
-                               unit: 'hour',
-                       });
-               });
-
-               it('should build the correct ticks', function() {
-                       expect(getLabels(this.scale)).toEqual(['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018']);
-               });
-
-               it('should have ticks with accurate labels', function() {
-                       var scale = this.scale;
-                       var ticks = scale.getTicks();
-                       // pixelsPerTick is an aproximation which assumes same number of milliseconds per year (not true)
-                       // we use a threshold of 1 day so that we still match these values
-                       var pixelsPerTick = scale.width / (ticks.length - 1);
-
-                       for (var i = 0; i < ticks.length - 1; i++) {
-                               var offset = pixelsPerTick * i;
-                               expect(scale.getValueForPixel(scale.left + offset)).toBeCloseToTime({
-                                       value: moment(ticks[i].label + '-01-01'),
-                                       unit: 'day',
-                                       threshold: 1,
-                               });
-                       }
-               });
-       });
-
-       it('should get the correct label for a data value', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: [null, 10, 3]
-                               }],
-                               labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00', '2015-01-03T22:00:00', '2015-01-05T23:00:00', '2015-01-07T03:00', '2015-01-08T10:00', '2015-01-10T12:00'], // days
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               position: 'bottom',
-                                               ticks: {
-                                                       source: 'labels',
-                                                       autoSkip: false
-                                               }
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               var controller = chart.getDatasetMeta(0).controller;
-               expect(xScale.getLabelForValue(controller.getParsed(0)[xScale.id])).toBeTruthy();
-               expect(xScale.getLabelForValue(controller.getParsed(0)[xScale.id])).toBe('Jan 1, 2015, 8:00:00 pm');
-               expect(xScale.getLabelForValue(xScale.getValueForPixel(xScale.getPixelForTick(6)))).toBe('Jan 10, 2015, 12:00:00 pm');
-       });
-
-       describe('when ticks.callback is specified', function() {
-               beforeEach(function() {
-                       this.chart = window.acquireChart({
-                               type: 'line',
-                               data: {
-                                       datasets: [{
-                                               xAxisID: 'x',
-                                               data: [0, 0]
-                                       }],
-                                       labels: ['2015-01-01T20:00:00', '2015-01-01T20:01:00']
-                               },
-                               options: {
-                                       scales: {
-                                               x: {
-                                                       type: 'time',
-                                                       time: {
-                                                               displayFormats: {
-                                                                       second: 'h:mm:ss'
-                                                               }
-                                                       },
-                                                       ticks: {
-                                                               callback: function(value) {
-                                                                       return '<' + value + '>';
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-                       this.scale = this.chart.scales.x;
-               });
-
-               it('should get the correct labels for ticks', function() {
-                       var labels = getLabels(this.scale);
-
-                       expect(labels.length).toEqual(21);
-                       expect(labels[0]).toEqual('<8:00:00>');
-                       expect(labels[labels.length - 1]).toEqual('<8:01:00>');
-               });
-
-               it('should update ticks.callback correctly', function() {
-                       var chart = this.chart;
-                       chart.options.scales.x.ticks.callback = function(value) {
-                               return '{' + value + '}';
-                       };
-                       chart.update();
-
-                       var labels = getLabels(this.scale);
-                       expect(labels.length).toEqual(21);
-                       expect(labels[0]).toEqual('{8:00:00}');
-                       expect(labels[labels.length - 1]).toEqual('{8:01:00}');
-               });
-       });
-
-       it('should get the correct label when time is specified as a string', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: [{x: '2015-01-01T20:00:00', y: 10}, {x: '2015-01-02T21:00:00', y: 3}]
-                               }],
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               position: 'bottom'
-                                       },
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               var controller = chart.getDatasetMeta(0).controller;
-               var value = controller.getParsed(0)[xScale.id];
-               expect(xScale.getLabelForValue(value)).toBeTruthy();
-               expect(xScale.getLabelForValue(value)).toBe('Jan 1, 2015, 8:00:00 pm');
-       });
-
-       it('should round to isoWeekday', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: [{x: '2020-04-12T20:00:00', y: 1}, {x: '2020-04-13T20:00:00', y: 2}]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               ticks: {
-                                                       source: 'data'
-                                               },
-                                               time: {
-                                                       unit: 'week',
-                                                       round: 'week',
-                                                       isoWeekday: 1,
-                                                       displayFormats: {
-                                                               week: 'WW'
-                                                       }
-                                               }
-                                       },
-                               }
-                       }
-               });
-
-               expect(getLabels(chart.scales.x)).toEqual(['15', '16']);
-       });
-
-       it('should get the correct label for a timestamp', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: [
-                                               {t: +new Date('2018-01-08 05:14:23.234'), y: 10},
-                                               {t: +new Date('2018-01-09 06:17:43.426'), y: 3}
-                                       ]
-                               }],
-                       },
-                       options: {
-                               parsing: {xAxisKey: 't'},
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               position: 'bottom'
-                                       },
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               var controller = chart.getDatasetMeta(0).controller;
-               var label = xScale.getLabelForValue(controller.getParsed(0)[xScale.id]);
-               expect(label).toEqual('Jan 8, 2018, 5:14:23 am');
-       });
-
-       it('should get the correct pixel for only one data in the dataset', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               labels: ['2016-05-27'],
-                               datasets: [{
-                                       xAxisID: 'x',
-                                       data: [5]
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               display: true,
-                                               type: 'time'
-                                       }
-                               }
-                       }
-               });
-
-               var xScale = chart.scales.x;
-               var pixel = xScale.getPixelForValue(moment('2016-05-27').valueOf());
-
-               expect(xScale.getValueForPixel(pixel)).toEqual(moment(chart.data.labels[0]).valueOf());
-       });
-
-       it('does not create a negative width chart when hidden', function() {
-               var chart = window.acquireChart({
-                       type: 'line',
-                       data: {
-                               datasets: [{
-                                       data: []
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'time',
-                                               ticks: {
-                                                       min: moment().subtract(1, 'months'),
-                                                       max: moment(),
-                                               }
-                                       },
-                               },
-                               responsive: true,
-                       },
-               }, {
-                       wrapper: {
-                               style: 'display: none',
-                       },
-               });
-               expect(chart.scales.y.width).toEqual(0);
-               expect(chart.scales.y.maxWidth).toEqual(0);
-               expect(chart.width).toEqual(0);
-       });
-
-       describe('when ticks.source', function() {
-               describe('is "labels"', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               labels: ['2017', '2019', '2020', '2025', '2042'],
-                                               datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time',
-                                                               time: {
-                                                                       parser: 'YYYY'
-                                                               },
-                                                               ticks: {
-                                                                       source: 'labels'
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               });
-                       });
-
-                       it ('should generate ticks from "data.labels"', function() {
-                               var scale = this.chart.scales.x;
-
-                               expect(scale.min).toEqual(+moment('2017', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2042', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2019', '2020', '2025', '2042']);
-                       });
-                       it ('should not add ticks for min and max if they extend the labels range', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.min = '2012';
-                               options.max = '2051';
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment('2012', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2051', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2019', '2020', '2025', '2042']);
-                       });
-                       it ('should not duplicate ticks if min and max are the labels limits', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.min = '2017';
-                               options.max = '2042';
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment('2017', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2042', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2019', '2020', '2025', '2042']);
-                       });
-                       it ('should correctly handle empty `data.labels` using "day" if `time.unit` is undefined`', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-
-                               chart.data.labels = [];
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment().startOf('day'));
-                               expect(scale.max).toEqual(+moment().endOf('day') + 1);
-                               expect(getLabels(scale)).toEqual([]);
-                       });
-                       it ('should correctly handle empty `data.labels` using `time.unit`', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.time.unit = 'year';
-                               chart.data.labels = [];
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment().startOf('year'));
-                               expect(scale.max).toEqual(+moment().endOf('year') + 1);
-                               expect(getLabels(scale)).toEqual([]);
-                       });
-               });
-
-               describe('is "data"', function() {
-                       beforeEach(function() {
-                               this.chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               labels: ['2017', '2019', '2020', '2025', '2042'],
-                                               datasets: [
-                                                       {data: [0, 1, 2, 3, 4, 5]},
-                                                       {data: [
-                                                               {x: '2018', y: 6},
-                                                               {x: '2020', y: 7},
-                                                               {x: '2043', y: 8}
-                                                       ]}
-                                               ]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time',
-                                                               time: {
-                                                                       parser: 'YYYY'
-                                                               },
-                                                               ticks: {
-                                                                       source: 'data'
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               });
-                       });
-
-                       it ('should generate ticks from "datasets.data"', function() {
-                               var scale = this.chart.scales.x;
-
-                               expect(scale.min).toEqual(+moment('2017', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2043', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
-                       });
-                       it ('should not add ticks for min and max if they extend the labels range', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.min = '2012';
-                               options.max = '2051';
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment('2012', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2051', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
-                       });
-                       it ('should not duplicate ticks if min and max are the labels limits', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.min = '2017';
-                               options.max = '2043';
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment('2017', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2043', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
-                       });
-                       it ('should correctly handle empty `data.labels` using "day" if `time.unit` is undefined`', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-
-                               chart.data.labels = [];
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment('2018', 'YYYY'));
-                               expect(scale.max).toEqual(+moment('2043', 'YYYY'));
-                               expect(getLabels(scale)).toEqual([
-                                       '2018', '2020', '2043']);
-                       });
-                       it ('should correctly handle empty `data.labels` and hidden datasets using `time.unit`', function() {
-                               var chart = this.chart;
-                               var scale = chart.scales.x;
-                               var options = chart.options.scales.x;
-
-                               options.time.unit = 'year';
-                               chart.data.labels = [];
-                               var meta = chart.getDatasetMeta(1);
-                               meta.hidden = true;
-                               chart.update();
-
-                               expect(scale.min).toEqual(+moment().startOf('year'));
-                               expect(scale.max).toEqual(+moment().endOf('year') + 1);
-                               expect(getLabels(scale)).toEqual([]);
-                       });
-               });
-       });
-
-       [true, false].forEach(function(normalized) {
-               describe('when normalized is ' + normalized + ' and scale type', function() {
-                       describe('is "timeseries"', function() {
-                               beforeEach(function() {
-                                       this.chart = window.acquireChart({
-                                               type: 'line',
-                                               data: {
-                                                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                                                       datasets: [{data: [0, 1, 2, 3, 4]}]
-                                               },
-                                               options: {
-                                                       normalized,
-                                                       scales: {
-                                                               x: {
-                                                                       type: 'timeseries',
-                                                                       time: {
-                                                                               parser: 'YYYY'
-                                                                       },
-                                                                       ticks: {
-                                                                               source: 'labels'
-                                                                       }
-                                                               },
-                                                               y: {
-                                                                       display: false
-                                                               }
-                                                       }
-                                               }
-                                       });
-                               });
-
-                               it ('should space data out with the same gap, whatever their time values', function() {
-                                       var scale = this.chart.scales.x;
-                                       var start = scale.left;
-                                       var slice = scale.width / 4;
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
-                                       expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice);
-                                       expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * 2);
-                                       expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * 3);
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * 4);
-                               });
-                               it ('should add a step before if scale.min is before the first data', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.min = '2012';
-                                       chart.update();
-
-                                       var start = scale.left;
-                                       var slice = scale.width / 5;
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 1)).toBeCloseToPixel(start + slice);
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 5)).toBeCloseToPixel(start + slice * 5);
-                               });
-                               it ('should add a step after if scale.max is after the last data', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.max = '2050';
-                                       chart.update();
-
-                                       var start = scale.left;
-                                       var slice = scale.width / 5;
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * 4);
-                               });
-                               it ('should add steps before and after if scale.min/max are outside the data range', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.min = '2012';
-                                       options.max = '2050';
-                                       chart.update();
-
-                                       var start = scale.left;
-                                       var slice = scale.width / 6;
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 1)).toBeCloseToPixel(start + slice);
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 5)).toBeCloseToPixel(start + slice * 5);
-                               });
-                       });
-                       describe('is "time"', function() {
-                               beforeEach(function() {
-                                       this.chart = window.acquireChart({
-                                               type: 'line',
-                                               data: {
-                                                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                                                       datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                               },
-                                               options: {
-                                                       scales: {
-                                                               x: {
-                                                                       type: 'time',
-                                                                       time: {
-                                                                               parser: 'YYYY'
-                                                                       },
-                                                                       ticks: {
-                                                                               source: 'labels'
-                                                                       }
-                                                               },
-                                                               y: {
-                                                                       display: false
-                                                               }
-                                                       }
-                                               }
-                                       });
-                               });
-
-                               it ('should space data out with a gap relative to their time values', function() {
-                                       var scale = this.chart.scales.x;
-                                       var start = scale.left;
-                                       var slice = scale.width / (2042 - 2017);
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
-                                       expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice * (2019 - 2017));
-                                       expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * (2020 - 2017));
-                                       expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * (2025 - 2017));
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * (2042 - 2017));
-                               });
-                               it ('should take in account scale min and max if outside the ticks range', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.min = '2012';
-                                       options.max = '2050';
-                                       chart.update();
-
-                                       var start = scale.left;
-                                       var slice = scale.width / (2050 - 2012);
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start + slice * (2017 - 2012));
-                                       expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice * (2019 - 2012));
-                                       expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * (2020 - 2012));
-                                       expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * (2025 - 2012));
-                                       expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * (2042 - 2012));
-                               });
-                       });
-               });
-       });
-
-       describe('when bounds', function() {
-               describe('is "data"', function() {
-                       it ('should preserve the data range', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
-                                               datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time',
-                                                               bounds: 'data',
-                                                               time: {
-                                                                       parser: 'MM/DD HH:mm',
-                                                                       unit: 'day'
-                                                               }
-                                                       },
-                                                       y: {
-                                                               display: false
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.x;
-
-                               expect(scale.min).toEqual(+moment('02/20 08:00', 'MM/DD HH:mm'));
-                               expect(scale.max).toEqual(+moment('02/23 11:00', 'MM/DD HH:mm'));
-                               expect(scale.getPixelForValue(moment('02/20 08:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(scale.left);
-                               expect(scale.getPixelForValue(moment('02/23 11:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(scale.left + scale.width);
-                               expect(getLabels(scale)).toEqual([
-                                       'Feb 21', 'Feb 22', 'Feb 23']);
-                       });
-               });
-
-               describe('is "labels"', function() {
-                       it('should preserve the label range', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {
-                                               labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
-                                               datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                       },
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time',
-                                                               bounds: 'ticks',
-                                                               time: {
-                                                                       parser: 'MM/DD HH:mm',
-                                                                       unit: 'day'
-                                                               }
-                                                       },
-                                                       y: {
-                                                               display: false
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               var scale = chart.scales.x;
-                               var ticks = scale.getTicks();
-
-                               expect(scale.min).toEqual(ticks[0].value);
-                               expect(scale.max).toEqual(ticks[ticks.length - 1].value);
-                               expect(scale.getPixelForValue(moment('02/20 08:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(60);
-                               expect(scale.getPixelForValue(moment('02/23 11:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(426);
-                               expect(getLabels(scale)).toEqual([
-                                       'Feb 20', 'Feb 21', 'Feb 22', 'Feb 23', 'Feb 24']);
-                       });
-               });
-       });
-
-       describe('when min and/or max are defined', function() {
-               ['auto', 'data', 'labels'].forEach(function(source) {
-                       ['data', 'ticks'].forEach(function(bounds) {
-                               describe('and ticks.source is "' + source + '" and bounds "' + bounds + '"', function() {
-                                       beforeEach(function() {
-                                               this.chart = window.acquireChart({
-                                                       type: 'line',
-                                                       data: {
-                                                               labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
-                                                               datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                                       },
-                                                       options: {
-                                                               scales: {
-                                                                       x: {
-                                                                               type: 'time',
-                                                                               bounds: bounds,
-                                                                               time: {
-                                                                                       parser: 'MM/DD HH:mm',
-                                                                                       unit: 'day'
-                                                                               },
-                                                                               ticks: {
-                                                                                       source: source
-                                                                               }
-                                                                       },
-                                                                       y: {
-                                                                               display: false
-                                                                       }
-                                                               }
-                                                       }
-                                               });
-                                       });
-
-                                       it ('should expand scale to the min/max range', function() {
-                                               var chart = this.chart;
-                                               var scale = chart.scales.x;
-                                               var options = chart.options.scales.x;
-                                               var min = '02/19 07:00';
-                                               var max = '02/24 08:00';
-                                               var minMillis = +moment(min, 'MM/DD HH:mm');
-                                               var maxMillis = +moment(max, 'MM/DD HH:mm');
-
-                                               options.min = min;
-                                               options.max = max;
-                                               chart.update();
-
-                                               expect(scale.min).toEqual(minMillis);
-                                               expect(scale.max).toEqual(maxMillis);
-                                               expect(scale.getPixelForValue(minMillis)).toBeCloseToPixel(scale.left);
-                                               expect(scale.getPixelForValue(maxMillis)).toBeCloseToPixel(scale.left + scale.width);
-                                               scale.getTicks().forEach(function(tick) {
-                                                       expect(tick.value >= minMillis).toBeTruthy();
-                                                       expect(tick.value <= maxMillis).toBeTruthy();
-                                               });
-                                       });
-                                       it ('should shrink scale to the min/max range', function() {
-                                               var chart = this.chart;
-                                               var scale = chart.scales.x;
-                                               var options = chart.options.scales.x;
-                                               var min = '02/21 07:00';
-                                               var max = '02/22 20:00';
-                                               var minMillis = +moment(min, 'MM/DD HH:mm');
-                                               var maxMillis = +moment(max, 'MM/DD HH:mm');
-
-                                               options.min = min;
-                                               options.max = max;
-                                               chart.update();
-
-                                               expect(scale.min).toEqual(minMillis);
-                                               expect(scale.max).toEqual(maxMillis);
-                                               expect(scale.getPixelForValue(minMillis)).toBeCloseToPixel(scale.left);
-                                               expect(scale.getPixelForValue(maxMillis)).toBeCloseToPixel(scale.left + scale.width);
-                                               scale.getTicks().forEach(function(tick) {
-                                                       expect(tick.value >= minMillis).toBeTruthy();
-                                                       expect(tick.value <= maxMillis).toBeTruthy();
-                                               });
-                                       });
-                               });
-                       });
-               });
-       });
-
-       ['auto', 'data', 'labels'].forEach(function(source) {
-               ['timeseries', 'time'].forEach(function(type) {
-                       describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() {
-                               beforeEach(function() {
-                                       this.chart = window.acquireChart({
-                                               type: 'line',
-                                               data: {
-                                                       labels: ['2017', '2018', '2019', '2020', '2021'],
-                                                       datasets: [{data: [0, 1, 2, 3, 4]}]
-                                               },
-                                               options: {
-                                                       scales: {
-                                                               x: {
-                                                                       type: type,
-                                                                       time: {
-                                                                               parser: 'YYYY',
-                                                                               unit: 'year'
-                                                                       },
-                                                                       ticks: {
-                                                                               source: source
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       });
-                               });
-
-                               it ('should not add offset from the edges', function() {
-                                       var scale = this.chart.scales.x;
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf())).toBeCloseToPixel(scale.left);
-                                       expect(scale.getPixelForValue(moment('2021').valueOf())).toBeCloseToPixel(scale.left + scale.width);
-                               });
-
-                               it ('should add offset from the edges if offset is true', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.offset = true;
-                                       chart.update();
-
-                                       var numTicks = scale.ticks.length;
-                                       var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
-                                       var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
-
-                                       expect(scale.getPixelForValue(moment('2017').valueOf())).toBeCloseToPixel(scale.left + firstTickInterval / 2);
-                                       expect(scale.getPixelForValue(moment('2021').valueOf())).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
-                               });
-
-                               it ('should not add offset if min and max extend the labels range', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.min = '2012';
-                                       options.max = '2051';
-                                       chart.update();
-
-                                       expect(scale.getPixelForValue(moment('2012').valueOf())).toBeCloseToPixel(scale.left);
-                                       expect(scale.getPixelForValue(moment('2051').valueOf())).toBeCloseToPixel(scale.left + scale.width);
-                               });
-                       });
-               });
-       });
-
-       it ('should handle offset when there are more data points than ticks', function() {
-               const chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [{
-                                       data: [{x: 631180800000, y: '31.84'}, {x: 631267200000, y: '30.89'}, {x: 631353600000, y: '33.00'}, {x: 631440000000, y: '33.52'}, {x: 631526400000, y: '32.24'}, {x: 631785600000, y: '32.74'}, {x: 631872000000, y: '31.45'}, {x: 631958400000, y: '32.60'}, {x: 632044800000, y: '31.77'}, {x: 632131200000, y: '32.45'}, {x: 632390400000, y: '31.13'}, {x: 632476800000, y: '31.82'}, {x: 632563200000, y: '30.81'}, {x: 632649600000, y: '30.07'}, {x: 632736000000, y: '29.31'}, {x: 632995200000, y: '29.82'}, {x: 633081600000, y: '30.20'}, {x: 633168000000, y: '30.78'}, {x: 633254400000, y: '30.72'}, {x: 633340800000, y: '31.62'}, {x: 633600000000, y: '30.64'}, {x: 633686400000, y: '32.36'}, {x: 633772800000, y: '34.66'}, {x: 633859200000, y: '33.96'}, {x: 633945600000, y: '34.20'}, {x: 634204800000, y: '32.20'}, {x: 634291200000, y: '32.44'}, {x: 634377600000, y: '32.72'}, {x: 634464000000, y: '32.95'}, {x: 634550400000, y: '32.95'}, {x: 634809600000, y: '30.88'}, {x: 634896000000, y: '29.44'}, {x: 634982400000, y: '29.36'}, {x: 635068800000, y: '28.84'}, {x: 635155200000, y: '30.85'}, {x: 635414400000, y: '32.00'}, {x: 635500800000, y: '32.74'}, {x: 635587200000, y: '33.16'}, {x: 635673600000, y: '34.73'}, {x: 635760000000, y: '32.89'}, {x: 636019200000, y: '32.41'}, {x: 636105600000, y: '31.15'}, {x: 636192000000, y: '30.63'}, {x: 636278400000, y: '29.60'}, {x: 636364800000, y: '29.31'}, {x: 636624000000, y: '29.83'}, {x: 636710400000, y: '27.97'}, {x: 636796800000, y: '26.18'}, {x: 636883200000, y: '26.06'}, {x: 636969600000, y: '26.34'}, {x: 637228800000, y: '27.75'}, {x: 637315200000, y: '29.05'}, {x: 637401600000, y: '28.82'}, {x: 637488000000, y: '29.43'}, {x: 637574400000, y: '29.53'}, {x: 637833600000, y: '28.50'}, {x: 637920000000, y: '28.87'}, {x: 638006400000, y: '28.11'}, {x: 638092800000, y: '27.79'}, {x: 638179200000, y: '28.18'}, {x: 638438400000, y: '28.27'}, {x: 638524800000, y: '28.29'}, {x: 638611200000, y: '29.63'}, {x: 638697600000, y: '29.13'}, {x: 638784000000, y: '26.57'}, {x: 639039600000, y: '27.19'}, {x: 639126000000, y: '27.48'}, {x: 639212400000, y: '27.79'}, {x: 639298800000, y: '28.48'}, {x: 639385200000, y: '27.88'}, {x: 639644400000, y: '25.63'}, {x: 639730800000, y: '25.02'}, {x: 639817200000, y: '25.26'}, {x: 639903600000, y: '25.00'}, {x: 639990000000, y: '26.23'}, {x: 640249200000, y: '26.22'}, {x: 640335600000, y: '26.36'}, {x: 640422000000, y: '25.45'}, {x: 640508400000, y: '24.62'}, {x: 640594800000, y: '26.65'}, {x: 640854000000, y: '26.28'}, {x: 640940400000, y: '27.25'}, {x: 641026800000, y: '25.93'}],
-                                       backgroundColor: '#ff6666'
-                               }]
-                       },
-                       options: {
-                               scales: {
-                                       x: {
-                                               type: 'timeseries',
-                                               offset: true,
-                                               ticks: {
-                                                       source: 'data',
-                                                       autoSkip: true,
-                                                       maxRotation: 0
-                                               }
-                                       },
-                                       y: {
-                                               type: 'linear',
-                                               gridLines: {
-                                                       drawBorder: false
-                                               }
-                                       }
-                               }
-                       },
-                       plugins: {
-                               legend: false
-                       }
-               });
-               const scale = chart.scales.x;
-               expect(scale.getPixelForDecimal(0)).toBeCloseToPixel(29);
-               expect(scale.getPixelForDecimal(1.0)).toBeCloseToPixel(494);
-       });
-
-       ['data', 'labels'].forEach(function(source) {
-               ['timeseries', 'time'].forEach(function(type) {
-                       describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() {
-                               beforeEach(function() {
-                                       this.chart = window.acquireChart({
-                                               type: 'line',
-                                               data: {
-                                                       labels: ['2017', '2019', '2020', '2025', '2042'],
-                                                       datasets: [{data: [0, 1, 2, 3, 4, 5]}]
-                                               },
-                                               options: {
-                                                       scales: {
-                                                               x: {
-                                                                       id: 'x',
-                                                                       type: type,
-                                                                       time: {
-                                                                               parser: 'YYYY'
-                                                                       },
-                                                                       ticks: {
-                                                                               source: source
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       });
-                               });
-
-                               it ('should add offset if min and max extend the labels range and offset is true', function() {
-                                       var chart = this.chart;
-                                       var scale = chart.scales.x;
-                                       var options = chart.options.scales.x;
-
-                                       options.min = '2012';
-                                       options.max = '2051';
-                                       options.offset = true;
-                                       chart.update();
-
-                                       var numTicks = scale.ticks.length;
-                                       var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
-                                       var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
-                                       expect(scale.getPixelForValue(moment('2012').valueOf())).toBeCloseToPixel(scale.left + firstTickInterval / 2);
-                                       expect(scale.getPixelForValue(moment('2051').valueOf())).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
-                               });
-                       });
-               });
-       });
-
-       describe('Deprecations', function() {
-               describe('options.time.displayFormats', function() {
-                       it('should generate defaults from adapter presets', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {},
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time'
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               // NOTE: built-in adapter uses moment
-                               var expected = {
-                                       datetime: 'MMM D, YYYY, h:mm:ss a',
-                                       millisecond: 'h:mm:ss.SSS a',
-                                       second: 'h:mm:ss a',
-                                       minute: 'h:mm a',
-                                       hour: 'hA',
-                                       day: 'MMM D',
-                                       week: 'll',
-                                       month: 'MMM YYYY',
-                                       quarter: '[Q]Q - YYYY',
-                                       year: 'YYYY'
-                               };
-
-                               expect(chart.scales.x.options.time.displayFormats).toEqual(expected);
-                               expect(chart.options.scales.x.time.displayFormats).toEqual(expected);
-                       });
-
-                       it('should merge user formats with adapter presets', function() {
-                               var chart = window.acquireChart({
-                                       type: 'line',
-                                       data: {},
-                                       options: {
-                                               scales: {
-                                                       x: {
-                                                               type: 'time',
-                                                               time: {
-                                                                       displayFormats: {
-                                                                               millisecond: 'foo',
-                                                                               hour: 'bar',
-                                                                               month: 'bla'
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               });
-
-                               // NOTE: built-in adapter uses moment
-                               var expected = {
-                                       datetime: 'MMM D, YYYY, h:mm:ss a',
-                                       millisecond: 'foo',
-                                       second: 'h:mm:ss a',
-                                       minute: 'h:mm a',
-                                       hour: 'bar',
-                                       day: 'MMM D',
-                                       week: 'll',
-                                       month: 'bla',
-                                       quarter: '[Q]Q - YYYY',
-                                       year: 'YYYY'
-                               };
-
-                               expect(chart.scales.x.options.time.displayFormats).toEqual(expected);
-                               expect(chart.options.scales.x.time.displayFormats).toEqual(expected);
-                       });
-               });
-       });
+  describe('auto', jasmine.fixture.specs('scale.time'));
+
+  function createScale(data, options, dimensions) {
+    var width = (dimensions && dimensions.width) || 400;
+    var height = (dimensions && dimensions.height) || 50;
+
+    options = options || {};
+    options.type = 'time';
+    options.id = 'xScale0';
+
+    var chart = window.acquireChart({
+      type: 'line',
+      data: data,
+      options: {
+        scales: {
+          x: options
+        }
+      }
+    }, {canvas: {width: width, height: height}});
+
+
+    return chart.scales.x;
+  }
+
+  function getLabels(scale) {
+    return scale.ticks.map(t => t.label);
+  }
+
+  beforeEach(function() {
+    // Need a time matcher for getValueFromPixel
+    jasmine.addMatchers({
+      toBeCloseToTime: function() {
+        return {
+          compare: function(time, expected) {
+            var result = false;
+            var actual = moment(time);
+            var diff = actual.diff(expected.value, expected.unit, true);
+            result = Math.abs(diff) < (expected.threshold !== undefined ? expected.threshold : 0.01);
+
+            return {
+              pass: result
+            };
+          }
+        };
+      }
+    });
+  });
+
+  it('should load moment.js as a dependency', function() {
+    expect(window.moment).not.toBe(undefined);
+  });
+
+  it('should register the constructor with the registry', function() {
+    var Constructor = Chart.registry.getScale('time');
+    expect(Constructor).not.toBe(undefined);
+    expect(typeof Constructor).toBe('function');
+  });
+
+  it('should have the correct default config', function() {
+    var defaultConfig = Chart.defaults.scales.time;
+    expect(defaultConfig).toEqual({
+      bounds: 'data',
+      adapters: {},
+      time: {
+        parser: false, // false == a pattern string from or a custom callback that converts its argument to a timestamp
+        unit: false, // false == automatic or override with week, month, year, etc.
+        round: false, // none, or override with week, month, year, etc.
+        isoWeekday: false, // override week start day
+        minUnit: 'millisecond',
+        displayFormats: {}
+      },
+      ticks: {
+        source: 'auto',
+        major: {
+          enabled: false
+        }
+      }
+    });
+  });
+
+  it('should correctly determine the unit', function() {
+    var date = moment('Jan 01 1990', 'MMM DD YYYY');
+    var data = [];
+    for (var i = 0; i < 60; i++) {
+      data.push({x: date.valueOf(), y: Math.random()});
+      date = date.clone().add(1, 'month');
+    }
+
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          data: data
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'time',
+            ticks: {
+              source: 'data',
+              autoSkip: true
+            }
+          },
+        }
+      }
+    });
+
+    var scale = chart.scales.x;
+
+    expect(scale._unit).toEqual('month');
+  });
+
+  describe('when specifying limits', function() {
+    var mockData = {
+      labels: ['2015-01-01T20:00:00', '2015-01-02T20:00:00', '2015-01-03T20:00:00'],
+    };
+
+    var config;
+    beforeEach(function() {
+      config = Chart.helpers.clone(Chart.defaults.scales.time);
+      config.ticks.source = 'labels';
+      config.time.unit = 'day';
+    });
+
+    it('should use the min option when less than first label for building ticks', function() {
+      config.min = '2014-12-29T04:00:00';
+
+      var labels = getLabels(createScale(mockData, config));
+      expect(labels[0]).toEqual('Jan 1');
+    });
+
+    it('should use the min option when greater than first label for building ticks', function() {
+      config.min = '2015-01-02T04:00:00';
+
+      var labels = getLabels(createScale(mockData, config));
+      expect(labels[0]).toEqual('Jan 2');
+    });
+
+    it('should use the max option when greater than last label for building ticks', function() {
+      config.max = '2015-01-05T06:00:00';
+
+      var labels = getLabels(createScale(mockData, config));
+      expect(labels[labels.length - 1]).toEqual('Jan 3');
+    });
+
+    it('should use the max option when less than last label for building ticks', function() {
+      config.max = '2015-01-02T23:00:00';
+
+      var labels = getLabels(createScale(mockData, config));
+      expect(labels[labels.length - 1]).toEqual('Jan 2');
+    });
+  });
+
+  it('should use the isoWeekday option', function() {
+    var mockData = {
+      labels: [
+        '2015-01-01T20:00:00', // Thursday
+        '2015-01-02T20:00:00', // Friday
+        '2015-01-03T20:00:00' // Saturday
+      ]
+    };
+
+    var config = Chart.helpers.mergeIf({
+      bounds: 'ticks',
+      time: {
+        unit: 'week',
+        isoWeekday: 3 // Wednesday
+      }
+    }, Chart.defaults.scales.time);
+
+    var scale = createScale(mockData, config);
+    var ticks = getLabels(scale);
+
+    expect(ticks).toEqual(['Dec 31, 2014', 'Jan 7, 2015']);
+  });
+
+  describe('when rendering several days', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            xAxisID: 'x',
+            data: []
+          }],
+          labels: [
+            '2015-01-01T20:00:00',
+            '2015-01-02T21:00:00',
+            '2015-01-03T22:00:00',
+            '2015-01-05T23:00:00',
+            '2015-01-07T03:00',
+            '2015-01-08T10:00',
+            '2015-01-10T12:00'
+          ]
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'time',
+              position: 'bottom'
+            },
+          }
+        }
+      });
+
+      this.scale = this.chart.scales.x;
+    });
+
+    it('should be bounded by the nearest week beginnings', function() {
+      var chart = this.chart;
+      var scale = this.scale;
+      expect(scale.getValueForPixel(scale.left)).toBeGreaterThan(moment(chart.data.labels[0]).startOf('week'));
+      expect(scale.getValueForPixel(scale.right)).toBeLessThan(moment(chart.data.labels[chart.data.labels.length - 1]).add(1, 'week').endOf('week'));
+    });
+
+    it('should convert between screen coordinates and times', function() {
+      var chart = this.chart;
+      var scale = this.scale;
+      var timeRange = moment(scale.max).valueOf() - moment(scale.min).valueOf();
+      var msPerPix = timeRange / scale.width;
+      var firstPointOffsetMs = moment(chart.config.data.labels[0]).valueOf() - scale.min;
+      var firstPointPixel = scale.left + firstPointOffsetMs / msPerPix;
+      var lastPointOffsetMs = moment(chart.config.data.labels[chart.config.data.labels.length - 1]).valueOf() - scale.min;
+      var lastPointPixel = scale.left + lastPointOffsetMs / msPerPix;
+
+      expect(scale.getPixelForValue(moment('2015-01-01T20:00:00').valueOf())).toBeCloseToPixel(firstPointPixel);
+      expect(scale.getPixelForValue(moment(chart.data.labels[0]).valueOf())).toBeCloseToPixel(firstPointPixel);
+      expect(scale.getValueForPixel(firstPointPixel)).toBeCloseToTime({
+        value: moment(chart.data.labels[0]),
+        unit: 'hour',
+      });
+
+      expect(scale.getPixelForValue(moment('2015-01-10T12:00').valueOf())).toBeCloseToPixel(lastPointPixel);
+      expect(scale.getValueForPixel(lastPointPixel)).toBeCloseToTime({
+        value: moment(chart.data.labels[6]),
+        unit: 'hour'
+      });
+    });
+  });
+
+  describe('when rendering several years', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          labels: ['2005-07-04', '2017-01-20'],
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'time',
+              bounds: 'ticks',
+              position: 'bottom'
+            },
+          }
+        }
+      }, {canvas: {width: 800, height: 200}});
+
+      this.scale = this.chart.scales.x;
+    });
+
+    it('should be bounded by nearest step\'s year start and end', function() {
+      var scale = this.scale;
+      var ticks = scale.getTicks();
+      var step = ticks[1].value - ticks[0].value;
+      var stepsAmount = Math.floor((scale.max - scale.min) / step);
+
+      expect(scale.getValueForPixel(scale.left)).toBeCloseToTime({
+        value: moment(scale.min).startOf('year'),
+        unit: 'hour',
+      });
+      expect(scale.getValueForPixel(scale.right)).toBeCloseToTime({
+        value: moment(scale.min + step * stepsAmount).endOf('year'),
+        unit: 'hour',
+      });
+    });
+
+    it('should build the correct ticks', function() {
+      expect(getLabels(this.scale)).toEqual(['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018']);
+    });
+
+    it('should have ticks with accurate labels', function() {
+      var scale = this.scale;
+      var ticks = scale.getTicks();
+      // pixelsPerTick is an aproximation which assumes same number of milliseconds per year (not true)
+      // we use a threshold of 1 day so that we still match these values
+      var pixelsPerTick = scale.width / (ticks.length - 1);
+
+      for (var i = 0; i < ticks.length - 1; i++) {
+        var offset = pixelsPerTick * i;
+        expect(scale.getValueForPixel(scale.left + offset)).toBeCloseToTime({
+          value: moment(ticks[i].label + '-01-01'),
+          unit: 'day',
+          threshold: 1,
+        });
+      }
+    });
+  });
+
+  it('should get the correct label for a data value', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          data: [null, 10, 3]
+        }],
+        labels: ['2015-01-01T20:00:00', '2015-01-02T21:00:00', '2015-01-03T22:00:00', '2015-01-05T23:00:00', '2015-01-07T03:00', '2015-01-08T10:00', '2015-01-10T12:00'], // days
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'time',
+            position: 'bottom',
+            ticks: {
+              source: 'labels',
+              autoSkip: false
+            }
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    var controller = chart.getDatasetMeta(0).controller;
+    expect(xScale.getLabelForValue(controller.getParsed(0)[xScale.id])).toBeTruthy();
+    expect(xScale.getLabelForValue(controller.getParsed(0)[xScale.id])).toBe('Jan 1, 2015, 8:00:00 pm');
+    expect(xScale.getLabelForValue(xScale.getValueForPixel(xScale.getPixelForTick(6)))).toBe('Jan 10, 2015, 12:00:00 pm');
+  });
+
+  describe('when ticks.callback is specified', function() {
+    beforeEach(function() {
+      this.chart = window.acquireChart({
+        type: 'line',
+        data: {
+          datasets: [{
+            xAxisID: 'x',
+            data: [0, 0]
+          }],
+          labels: ['2015-01-01T20:00:00', '2015-01-01T20:01:00']
+        },
+        options: {
+          scales: {
+            x: {
+              type: 'time',
+              time: {
+                displayFormats: {
+                  second: 'h:mm:ss'
+                }
+              },
+              ticks: {
+                callback: function(value) {
+                  return '<' + value + '>';
+                }
+              }
+            }
+          }
+        }
+      });
+      this.scale = this.chart.scales.x;
+    });
+
+    it('should get the correct labels for ticks', function() {
+      var labels = getLabels(this.scale);
+
+      expect(labels.length).toEqual(21);
+      expect(labels[0]).toEqual('<8:00:00>');
+      expect(labels[labels.length - 1]).toEqual('<8:01:00>');
+    });
+
+    it('should update ticks.callback correctly', function() {
+      var chart = this.chart;
+      chart.options.scales.x.ticks.callback = function(value) {
+        return '{' + value + '}';
+      };
+      chart.update();
+
+      var labels = getLabels(this.scale);
+      expect(labels.length).toEqual(21);
+      expect(labels[0]).toEqual('{8:00:00}');
+      expect(labels[labels.length - 1]).toEqual('{8:01:00}');
+    });
+  });
+
+  it('should get the correct label when time is specified as a string', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          data: [{x: '2015-01-01T20:00:00', y: 10}, {x: '2015-01-02T21:00:00', y: 3}]
+        }],
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'time',
+            position: 'bottom'
+          },
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    var controller = chart.getDatasetMeta(0).controller;
+    var value = controller.getParsed(0)[xScale.id];
+    expect(xScale.getLabelForValue(value)).toBeTruthy();
+    expect(xScale.getLabelForValue(value)).toBe('Jan 1, 2015, 8:00:00 pm');
+  });
+
+  it('should round to isoWeekday', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [{x: '2020-04-12T20:00:00', y: 1}, {x: '2020-04-13T20:00:00', y: 2}]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'time',
+            ticks: {
+              source: 'data'
+            },
+            time: {
+              unit: 'week',
+              round: 'week',
+              isoWeekday: 1,
+              displayFormats: {
+                week: 'WW'
+              }
+            }
+          },
+        }
+      }
+    });
+
+    expect(getLabels(chart.scales.x)).toEqual(['15', '16']);
+  });
+
+  it('should get the correct label for a timestamp', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          xAxisID: 'x',
+          data: [
+            {t: +new Date('2018-01-08 05:14:23.234'), y: 10},
+            {t: +new Date('2018-01-09 06:17:43.426'), y: 3}
+          ]
+        }],
+      },
+      options: {
+        parsing: {xAxisKey: 't'},
+        scales: {
+          x: {
+            type: 'time',
+            position: 'bottom'
+          },
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    var controller = chart.getDatasetMeta(0).controller;
+    var label = xScale.getLabelForValue(controller.getParsed(0)[xScale.id]);
+    expect(label).toEqual('Jan 8, 2018, 5:14:23 am');
+  });
+
+  it('should get the correct pixel for only one data in the dataset', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        labels: ['2016-05-27'],
+        datasets: [{
+          xAxisID: 'x',
+          data: [5]
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            display: true,
+            type: 'time'
+          }
+        }
+      }
+    });
+
+    var xScale = chart.scales.x;
+    var pixel = xScale.getPixelForValue(moment('2016-05-27').valueOf());
+
+    expect(xScale.getValueForPixel(pixel)).toEqual(moment(chart.data.labels[0]).valueOf());
+  });
+
+  it('does not create a negative width chart when hidden', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: []
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'time',
+            ticks: {
+              min: moment().subtract(1, 'months'),
+              max: moment(),
+            }
+          },
+        },
+        responsive: true,
+      },
+    }, {
+      wrapper: {
+        style: 'display: none',
+      },
+    });
+    expect(chart.scales.y.width).toEqual(0);
+    expect(chart.scales.y.maxWidth).toEqual(0);
+    expect(chart.width).toEqual(0);
+  });
+
+  describe('when ticks.source', function() {
+    describe('is "labels"', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            labels: ['2017', '2019', '2020', '2025', '2042'],
+            datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+          },
+          options: {
+            scales: {
+              x: {
+                type: 'time',
+                time: {
+                  parser: 'YYYY'
+                },
+                ticks: {
+                  source: 'labels'
+                }
+              }
+            }
+          }
+        });
+      });
+
+      it ('should generate ticks from "data.labels"', function() {
+        var scale = this.chart.scales.x;
+
+        expect(scale.min).toEqual(+moment('2017', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2042', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2019', '2020', '2025', '2042']);
+      });
+      it ('should not add ticks for min and max if they extend the labels range', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.min = '2012';
+        options.max = '2051';
+        chart.update();
+
+        expect(scale.min).toEqual(+moment('2012', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2051', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2019', '2020', '2025', '2042']);
+      });
+      it ('should not duplicate ticks if min and max are the labels limits', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.min = '2017';
+        options.max = '2042';
+        chart.update();
+
+        expect(scale.min).toEqual(+moment('2017', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2042', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2019', '2020', '2025', '2042']);
+      });
+      it ('should correctly handle empty `data.labels` using "day" if `time.unit` is undefined`', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+
+        chart.data.labels = [];
+        chart.update();
+
+        expect(scale.min).toEqual(+moment().startOf('day'));
+        expect(scale.max).toEqual(+moment().endOf('day') + 1);
+        expect(getLabels(scale)).toEqual([]);
+      });
+      it ('should correctly handle empty `data.labels` using `time.unit`', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.time.unit = 'year';
+        chart.data.labels = [];
+        chart.update();
+
+        expect(scale.min).toEqual(+moment().startOf('year'));
+        expect(scale.max).toEqual(+moment().endOf('year') + 1);
+        expect(getLabels(scale)).toEqual([]);
+      });
+    });
+
+    describe('is "data"', function() {
+      beforeEach(function() {
+        this.chart = window.acquireChart({
+          type: 'line',
+          data: {
+            labels: ['2017', '2019', '2020', '2025', '2042'],
+            datasets: [
+              {data: [0, 1, 2, 3, 4, 5]},
+              {data: [
+                {x: '2018', y: 6},
+                {x: '2020', y: 7},
+                {x: '2043', y: 8}
+              ]}
+            ]
+          },
+          options: {
+            scales: {
+              x: {
+                type: 'time',
+                time: {
+                  parser: 'YYYY'
+                },
+                ticks: {
+                  source: 'data'
+                }
+              }
+            }
+          }
+        });
+      });
+
+      it ('should generate ticks from "datasets.data"', function() {
+        var scale = this.chart.scales.x;
+
+        expect(scale.min).toEqual(+moment('2017', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2043', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
+      });
+      it ('should not add ticks for min and max if they extend the labels range', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.min = '2012';
+        options.max = '2051';
+        chart.update();
+
+        expect(scale.min).toEqual(+moment('2012', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2051', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
+      });
+      it ('should not duplicate ticks if min and max are the labels limits', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.min = '2017';
+        options.max = '2043';
+        chart.update();
+
+        expect(scale.min).toEqual(+moment('2017', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2043', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2017', '2018', '2019', '2020', '2025', '2042', '2043']);
+      });
+      it ('should correctly handle empty `data.labels` using "day" if `time.unit` is undefined`', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+
+        chart.data.labels = [];
+        chart.update();
+
+        expect(scale.min).toEqual(+moment('2018', 'YYYY'));
+        expect(scale.max).toEqual(+moment('2043', 'YYYY'));
+        expect(getLabels(scale)).toEqual([
+          '2018', '2020', '2043']);
+      });
+      it ('should correctly handle empty `data.labels` and hidden datasets using `time.unit`', function() {
+        var chart = this.chart;
+        var scale = chart.scales.x;
+        var options = chart.options.scales.x;
+
+        options.time.unit = 'year';
+        chart.data.labels = [];
+        var meta = chart.getDatasetMeta(1);
+        meta.hidden = true;
+        chart.update();
+
+        expect(scale.min).toEqual(+moment().startOf('year'));
+        expect(scale.max).toEqual(+moment().endOf('year') + 1);
+        expect(getLabels(scale)).toEqual([]);
+      });
+    });
+  });
+
+  [true, false].forEach(function(normalized) {
+    describe('when normalized is ' + normalized + ' and scale type', function() {
+      describe('is "timeseries"', function() {
+        beforeEach(function() {
+          this.chart = window.acquireChart({
+            type: 'line',
+            data: {
+              labels: ['2017', '2019', '2020', '2025', '2042'],
+              datasets: [{data: [0, 1, 2, 3, 4]}]
+            },
+            options: {
+              normalized,
+              scales: {
+                x: {
+                  type: 'timeseries',
+                  time: {
+                    parser: 'YYYY'
+                  },
+                  ticks: {
+                    source: 'labels'
+                  }
+                },
+                y: {
+                  display: false
+                }
+              }
+            }
+          });
+        });
+
+        it ('should space data out with the same gap, whatever their time values', function() {
+          var scale = this.chart.scales.x;
+          var start = scale.left;
+          var slice = scale.width / 4;
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
+          expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice);
+          expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * 2);
+          expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * 3);
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * 4);
+        });
+        it ('should add a step before if scale.min is before the first data', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.min = '2012';
+          chart.update();
+
+          var start = scale.left;
+          var slice = scale.width / 5;
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 1)).toBeCloseToPixel(start + slice);
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 5)).toBeCloseToPixel(start + slice * 5);
+        });
+        it ('should add a step after if scale.max is after the last data', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.max = '2050';
+          chart.update();
+
+          var start = scale.left;
+          var slice = scale.width / 5;
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * 4);
+        });
+        it ('should add steps before and after if scale.min/max are outside the data range', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.min = '2012';
+          options.max = '2050';
+          chart.update();
+
+          var start = scale.left;
+          var slice = scale.width / 6;
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 1)).toBeCloseToPixel(start + slice);
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 5)).toBeCloseToPixel(start + slice * 5);
+        });
+      });
+      describe('is "time"', function() {
+        beforeEach(function() {
+          this.chart = window.acquireChart({
+            type: 'line',
+            data: {
+              labels: ['2017', '2019', '2020', '2025', '2042'],
+              datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+            },
+            options: {
+              scales: {
+                x: {
+                  type: 'time',
+                  time: {
+                    parser: 'YYYY'
+                  },
+                  ticks: {
+                    source: 'labels'
+                  }
+                },
+                y: {
+                  display: false
+                }
+              }
+            }
+          });
+        });
+
+        it ('should space data out with a gap relative to their time values', function() {
+          var scale = this.chart.scales.x;
+          var start = scale.left;
+          var slice = scale.width / (2042 - 2017);
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start);
+          expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice * (2019 - 2017));
+          expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * (2020 - 2017));
+          expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * (2025 - 2017));
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * (2042 - 2017));
+        });
+        it ('should take in account scale min and max if outside the ticks range', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.min = '2012';
+          options.max = '2050';
+          chart.update();
+
+          var start = scale.left;
+          var slice = scale.width / (2050 - 2012);
+
+          expect(scale.getPixelForValue(moment('2017').valueOf(), 0)).toBeCloseToPixel(start + slice * (2017 - 2012));
+          expect(scale.getPixelForValue(moment('2019').valueOf(), 1)).toBeCloseToPixel(start + slice * (2019 - 2012));
+          expect(scale.getPixelForValue(moment('2020').valueOf(), 2)).toBeCloseToPixel(start + slice * (2020 - 2012));
+          expect(scale.getPixelForValue(moment('2025').valueOf(), 3)).toBeCloseToPixel(start + slice * (2025 - 2012));
+          expect(scale.getPixelForValue(moment('2042').valueOf(), 4)).toBeCloseToPixel(start + slice * (2042 - 2012));
+        });
+      });
+    });
+  });
+
+  describe('when bounds', function() {
+    describe('is "data"', function() {
+      it ('should preserve the data range', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
+            datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+          },
+          options: {
+            scales: {
+              x: {
+                type: 'time',
+                bounds: 'data',
+                time: {
+                  parser: 'MM/DD HH:mm',
+                  unit: 'day'
+                }
+              },
+              y: {
+                display: false
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.x;
+
+        expect(scale.min).toEqual(+moment('02/20 08:00', 'MM/DD HH:mm'));
+        expect(scale.max).toEqual(+moment('02/23 11:00', 'MM/DD HH:mm'));
+        expect(scale.getPixelForValue(moment('02/20 08:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(scale.left);
+        expect(scale.getPixelForValue(moment('02/23 11:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(scale.left + scale.width);
+        expect(getLabels(scale)).toEqual([
+          'Feb 21', 'Feb 22', 'Feb 23']);
+      });
+    });
+
+    describe('is "labels"', function() {
+      it('should preserve the label range', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {
+            labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
+            datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+          },
+          options: {
+            scales: {
+              x: {
+                type: 'time',
+                bounds: 'ticks',
+                time: {
+                  parser: 'MM/DD HH:mm',
+                  unit: 'day'
+                }
+              },
+              y: {
+                display: false
+              }
+            }
+          }
+        });
+
+        var scale = chart.scales.x;
+        var ticks = scale.getTicks();
+
+        expect(scale.min).toEqual(ticks[0].value);
+        expect(scale.max).toEqual(ticks[ticks.length - 1].value);
+        expect(scale.getPixelForValue(moment('02/20 08:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(60);
+        expect(scale.getPixelForValue(moment('02/23 11:00', 'MM/DD HH:mm').valueOf())).toBeCloseToPixel(426);
+        expect(getLabels(scale)).toEqual([
+          'Feb 20', 'Feb 21', 'Feb 22', 'Feb 23', 'Feb 24']);
+      });
+    });
+  });
+
+  describe('when min and/or max are defined', function() {
+    ['auto', 'data', 'labels'].forEach(function(source) {
+      ['data', 'ticks'].forEach(function(bounds) {
+        describe('and ticks.source is "' + source + '" and bounds "' + bounds + '"', function() {
+          beforeEach(function() {
+            this.chart = window.acquireChart({
+              type: 'line',
+              data: {
+                labels: ['02/20 08:00', '02/21 09:00', '02/22 10:00', '02/23 11:00'],
+                datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+              },
+              options: {
+                scales: {
+                  x: {
+                    type: 'time',
+                    bounds: bounds,
+                    time: {
+                      parser: 'MM/DD HH:mm',
+                      unit: 'day'
+                    },
+                    ticks: {
+                      source: source
+                    }
+                  },
+                  y: {
+                    display: false
+                  }
+                }
+              }
+            });
+          });
+
+          it ('should expand scale to the min/max range', function() {
+            var chart = this.chart;
+            var scale = chart.scales.x;
+            var options = chart.options.scales.x;
+            var min = '02/19 07:00';
+            var max = '02/24 08:00';
+            var minMillis = +moment(min, 'MM/DD HH:mm');
+            var maxMillis = +moment(max, 'MM/DD HH:mm');
+
+            options.min = min;
+            options.max = max;
+            chart.update();
+
+            expect(scale.min).toEqual(minMillis);
+            expect(scale.max).toEqual(maxMillis);
+            expect(scale.getPixelForValue(minMillis)).toBeCloseToPixel(scale.left);
+            expect(scale.getPixelForValue(maxMillis)).toBeCloseToPixel(scale.left + scale.width);
+            scale.getTicks().forEach(function(tick) {
+              expect(tick.value >= minMillis).toBeTruthy();
+              expect(tick.value <= maxMillis).toBeTruthy();
+            });
+          });
+          it ('should shrink scale to the min/max range', function() {
+            var chart = this.chart;
+            var scale = chart.scales.x;
+            var options = chart.options.scales.x;
+            var min = '02/21 07:00';
+            var max = '02/22 20:00';
+            var minMillis = +moment(min, 'MM/DD HH:mm');
+            var maxMillis = +moment(max, 'MM/DD HH:mm');
+
+            options.min = min;
+            options.max = max;
+            chart.update();
+
+            expect(scale.min).toEqual(minMillis);
+            expect(scale.max).toEqual(maxMillis);
+            expect(scale.getPixelForValue(minMillis)).toBeCloseToPixel(scale.left);
+            expect(scale.getPixelForValue(maxMillis)).toBeCloseToPixel(scale.left + scale.width);
+            scale.getTicks().forEach(function(tick) {
+              expect(tick.value >= minMillis).toBeTruthy();
+              expect(tick.value <= maxMillis).toBeTruthy();
+            });
+          });
+        });
+      });
+    });
+  });
+
+  ['auto', 'data', 'labels'].forEach(function(source) {
+    ['timeseries', 'time'].forEach(function(type) {
+      describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() {
+        beforeEach(function() {
+          this.chart = window.acquireChart({
+            type: 'line',
+            data: {
+              labels: ['2017', '2018', '2019', '2020', '2021'],
+              datasets: [{data: [0, 1, 2, 3, 4]}]
+            },
+            options: {
+              scales: {
+                x: {
+                  type: type,
+                  time: {
+                    parser: 'YYYY',
+                    unit: 'year'
+                  },
+                  ticks: {
+                    source: source
+                  }
+                }
+              }
+            }
+          });
+        });
+
+        it ('should not add offset from the edges', function() {
+          var scale = this.chart.scales.x;
+
+          expect(scale.getPixelForValue(moment('2017').valueOf())).toBeCloseToPixel(scale.left);
+          expect(scale.getPixelForValue(moment('2021').valueOf())).toBeCloseToPixel(scale.left + scale.width);
+        });
+
+        it ('should add offset from the edges if offset is true', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.offset = true;
+          chart.update();
+
+          var numTicks = scale.ticks.length;
+          var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
+          var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
+
+          expect(scale.getPixelForValue(moment('2017').valueOf())).toBeCloseToPixel(scale.left + firstTickInterval / 2);
+          expect(scale.getPixelForValue(moment('2021').valueOf())).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
+        });
+
+        it ('should not add offset if min and max extend the labels range', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.min = '2012';
+          options.max = '2051';
+          chart.update();
+
+          expect(scale.getPixelForValue(moment('2012').valueOf())).toBeCloseToPixel(scale.left);
+          expect(scale.getPixelForValue(moment('2051').valueOf())).toBeCloseToPixel(scale.left + scale.width);
+        });
+      });
+    });
+  });
+
+  it ('should handle offset when there are more data points than ticks', function() {
+    const chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [{x: 631180800000, y: '31.84'}, {x: 631267200000, y: '30.89'}, {x: 631353600000, y: '33.00'}, {x: 631440000000, y: '33.52'}, {x: 631526400000, y: '32.24'}, {x: 631785600000, y: '32.74'}, {x: 631872000000, y: '31.45'}, {x: 631958400000, y: '32.60'}, {x: 632044800000, y: '31.77'}, {x: 632131200000, y: '32.45'}, {x: 632390400000, y: '31.13'}, {x: 632476800000, y: '31.82'}, {x: 632563200000, y: '30.81'}, {x: 632649600000, y: '30.07'}, {x: 632736000000, y: '29.31'}, {x: 632995200000, y: '29.82'}, {x: 633081600000, y: '30.20'}, {x: 633168000000, y: '30.78'}, {x: 633254400000, y: '30.72'}, {x: 633340800000, y: '31.62'}, {x: 633600000000, y: '30.64'}, {x: 633686400000, y: '32.36'}, {x: 633772800000, y: '34.66'}, {x: 633859200000, y: '33.96'}, {x: 633945600000, y: '34.20'}, {x: 634204800000, y: '32.20'}, {x: 634291200000, y: '32.44'}, {x: 634377600000, y: '32.72'}, {x: 634464000000, y: '32.95'}, {x: 634550400000, y: '32.95'}, {x: 634809600000, y: '30.88'}, {x: 634896000000, y: '29.44'}, {x: 634982400000, y: '29.36'}, {x: 635068800000, y: '28.84'}, {x: 635155200000, y: '30.85'}, {x: 635414400000, y: '32.00'}, {x: 635500800000, y: '32.74'}, {x: 635587200000, y: '33.16'}, {x: 635673600000, y: '34.73'}, {x: 635760000000, y: '32.89'}, {x: 636019200000, y: '32.41'}, {x: 636105600000, y: '31.15'}, {x: 636192000000, y: '30.63'}, {x: 636278400000, y: '29.60'}, {x: 636364800000, y: '29.31'}, {x: 636624000000, y: '29.83'}, {x: 636710400000, y: '27.97'}, {x: 636796800000, y: '26.18'}, {x: 636883200000, y: '26.06'}, {x: 636969600000, y: '26.34'}, {x: 637228800000, y: '27.75'}, {x: 637315200000, y: '29.05'}, {x: 637401600000, y: '28.82'}, {x: 637488000000, y: '29.43'}, {x: 637574400000, y: '29.53'}, {x: 637833600000, y: '28.50'}, {x: 637920000000, y: '28.87'}, {x: 638006400000, y: '28.11'}, {x: 638092800000, y: '27.79'}, {x: 638179200000, y: '28.18'}, {x: 638438400000, y: '28.27'}, {x: 638524800000, y: '28.29'}, {x: 638611200000, y: '29.63'}, {x: 638697600000, y: '29.13'}, {x: 638784000000, y: '26.57'}, {x: 639039600000, y: '27.19'}, {x: 639126000000, y: '27.48'}, {x: 639212400000, y: '27.79'}, {x: 639298800000, y: '28.48'}, {x: 639385200000, y: '27.88'}, {x: 639644400000, y: '25.63'}, {x: 639730800000, y: '25.02'}, {x: 639817200000, y: '25.26'}, {x: 639903600000, y: '25.00'}, {x: 639990000000, y: '26.23'}, {x: 640249200000, y: '26.22'}, {x: 640335600000, y: '26.36'}, {x: 640422000000, y: '25.45'}, {x: 640508400000, y: '24.62'}, {x: 640594800000, y: '26.65'}, {x: 640854000000, y: '26.28'}, {x: 640940400000, y: '27.25'}, {x: 641026800000, y: '25.93'}],
+          backgroundColor: '#ff6666'
+        }]
+      },
+      options: {
+        scales: {
+          x: {
+            type: 'timeseries',
+            offset: true,
+            ticks: {
+              source: 'data',
+              autoSkip: true,
+              maxRotation: 0
+            }
+          },
+          y: {
+            type: 'linear',
+            gridLines: {
+              drawBorder: false
+            }
+          }
+        }
+      },
+      plugins: {
+        legend: false
+      }
+    });
+    const scale = chart.scales.x;
+    expect(scale.getPixelForDecimal(0)).toBeCloseToPixel(29);
+    expect(scale.getPixelForDecimal(1.0)).toBeCloseToPixel(494);
+  });
+
+  ['data', 'labels'].forEach(function(source) {
+    ['timeseries', 'time'].forEach(function(type) {
+      describe('when ticks.source is "' + source + '" and scale type is "' + type + '"', function() {
+        beforeEach(function() {
+          this.chart = window.acquireChart({
+            type: 'line',
+            data: {
+              labels: ['2017', '2019', '2020', '2025', '2042'],
+              datasets: [{data: [0, 1, 2, 3, 4, 5]}]
+            },
+            options: {
+              scales: {
+                x: {
+                  id: 'x',
+                  type: type,
+                  time: {
+                    parser: 'YYYY'
+                  },
+                  ticks: {
+                    source: source
+                  }
+                }
+              }
+            }
+          });
+        });
+
+        it ('should add offset if min and max extend the labels range and offset is true', function() {
+          var chart = this.chart;
+          var scale = chart.scales.x;
+          var options = chart.options.scales.x;
+
+          options.min = '2012';
+          options.max = '2051';
+          options.offset = true;
+          chart.update();
+
+          var numTicks = scale.ticks.length;
+          var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
+          var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
+          expect(scale.getPixelForValue(moment('2012').valueOf())).toBeCloseToPixel(scale.left + firstTickInterval / 2);
+          expect(scale.getPixelForValue(moment('2051').valueOf())).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
+        });
+      });
+    });
+  });
+
+  describe('Deprecations', function() {
+    describe('options.time.displayFormats', function() {
+      it('should generate defaults from adapter presets', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {},
+          options: {
+            scales: {
+              x: {
+                type: 'time'
+              }
+            }
+          }
+        });
+
+        // NOTE: built-in adapter uses moment
+        var expected = {
+          datetime: 'MMM D, YYYY, h:mm:ss a',
+          millisecond: 'h:mm:ss.SSS a',
+          second: 'h:mm:ss a',
+          minute: 'h:mm a',
+          hour: 'hA',
+          day: 'MMM D',
+          week: 'll',
+          month: 'MMM YYYY',
+          quarter: '[Q]Q - YYYY',
+          year: 'YYYY'
+        };
+
+        expect(chart.scales.x.options.time.displayFormats).toEqual(expected);
+        expect(chart.options.scales.x.time.displayFormats).toEqual(expected);
+      });
+
+      it('should merge user formats with adapter presets', function() {
+        var chart = window.acquireChart({
+          type: 'line',
+          data: {},
+          options: {
+            scales: {
+              x: {
+                type: 'time',
+                time: {
+                  displayFormats: {
+                    millisecond: 'foo',
+                    hour: 'bar',
+                    month: 'bla'
+                  }
+                }
+              }
+            }
+          }
+        });
+
+        // NOTE: built-in adapter uses moment
+        var expected = {
+          datetime: 'MMM D, YYYY, h:mm:ss a',
+          millisecond: 'foo',
+          second: 'h:mm:ss a',
+          minute: 'h:mm a',
+          hour: 'bar',
+          day: 'MMM D',
+          week: 'll',
+          month: 'bla',
+          quarter: '[Q]Q - YYYY',
+          year: 'YYYY'
+        };
+
+        expect(chart.scales.x.options.time.displayFormats).toEqual(expected);
+        expect(chart.options.scales.x.time.displayFormats).toEqual(expected);
+      });
+    });
+  });
 });
index 9f78e06c9c1230c08bfd38976316bdc9fa27bfdb..8eff8baac43feb2927c352e74edf42ac3572063c 100644 (file)
@@ -2,11 +2,11 @@ import { Chart } from './index.esm';
 import { AnyObject } from './basic';
 
 export class Animation {
-       constructor(cfg: AnyObject, target: AnyObject, prop: string, to?: unknown);
-       active(): boolean;
-       update(cfg: AnyObject, to: unknown, date: number): void;
-       cancel(): void;
-       tick(date: number): void;
+  constructor(cfg: AnyObject, target: AnyObject, prop: string, to?: unknown);
+  active(): boolean;
+  update(cfg: AnyObject, to: unknown, date: number): void;
+  cancel(): void;
+  tick(date: number): void;
 }
 
 export interface AnimationEvent {
@@ -16,17 +16,17 @@ export interface AnimationEvent {
 }
 
 export class Animator {
-       listen(chart: Chart, event: 'complete' | 'progress', cb: (event: AnimationEvent) => void): void;
-       add(chart: Chart, items: readonly Animation[]): void;
-       has(chart: Chart): boolean;
-       start(chart: Chart): void;
-       running(chart: Chart): boolean;
-       stop(chart: Chart): void;
-       remove(chart: Chart): boolean;
+  listen(chart: Chart, event: 'complete' | 'progress', cb: (event: AnimationEvent) => void): void;
+  add(chart: Chart, items: readonly Animation[]): void;
+  has(chart: Chart): boolean;
+  start(chart: Chart): void;
+  running(chart: Chart): boolean;
+  stop(chart: Chart): void;
+  remove(chart: Chart): boolean;
 }
 
 export class Animations {
-       constructor(chart: Chart, animations: AnyObject);
-       configure(animations: AnyObject): void;
-       update(target: AnyObject, values: AnyObject): undefined | boolean;
+  constructor(chart: Chart, animations: AnyObject);
+  configure(animations: AnyObject): void;
+  update(target: AnyObject, values: AnyObject): undefined | boolean;
 }
index b6827e7591f2c334c33e429ed4a837883e4ee6de..799be04f8383fb8b9ec31240cf855cb6c44b6384 100644 (file)
@@ -20,9 +20,9 @@ import { Element } from './element';
 import { ChartArea, Point } from './geometric';
 import { LayoutItem, LayoutPosition } from './layout';
 import {
-       Scriptable,
-       ScriptableOptions,
-       ScriptableAndArrayOptions
+  Scriptable,
+  ScriptableOptions,
+  ScriptableAndArrayOptions
 } from './scriptable';
 
 export { DateAdapter, TimeUnit, _adapters } from './adapters';
@@ -32,10 +32,10 @@ export { Element } from './element';
 export { ChartArea, Point } from './geometric';
 export { LayoutItem, LayoutPosition } from './layout';
 export {
-       Scriptable,
-       ScriptableOptions,
-       ScriptableAndArray,
-       ScriptableAndArrayOptions
+  Scriptable,
+  ScriptableOptions,
+  ScriptableAndArray,
+  ScriptableAndArrayOptions
 } from './scriptable';
 
 export interface ScriptableContext {
@@ -519,7 +519,7 @@ export declare enum UpdateModeEnum {
 export type UpdateMode = keyof typeof UpdateModeEnum;
 
 export class DatasetController<TElement extends Element = Element, TDatasetElement extends Element = Element> {
-       constructor(chart: Chart, datasetIndex: number);
+  constructor(chart: Chart, datasetIndex: number);
 
        readonly chart: Chart;
        readonly index: number;
@@ -1863,13 +1863,13 @@ export interface ElementChartOptions {
 }
 
 export class BasePlatform {
-       /**
+  /**
         * Called at chart construction time, returns a context2d instance implementing
         * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
         * @param {HTMLCanvasElement} canvas - The canvas from which to acquire context (platform specific)
         * @param options - The chart options
         */
-       acquireContext(
+  acquireContext(
                canvas: HTMLCanvasElement,
                options?: CanvasRenderingContext2DSettings
        ): CanvasRenderingContext2D | null;
@@ -1879,39 +1879,39 @@ export class BasePlatform {
         * @param {CanvasRenderingContext2D} context - The context2d instance
         * @returns {boolean} true if the method succeeded, else false
         */
-       releaseContext(context: CanvasRenderingContext2D): boolean;
-       /**
+  releaseContext(context: CanvasRenderingContext2D): boolean;
+  /**
         * Registers the specified listener on the given chart.
         * @param {Chart} chart - Chart from which to listen for event
         * @param {string} type - The ({@link ChartEvent}) type to listen for
         * @param listener - Receives a notification (an object that implements
         * the {@link ChartEvent} interface) when an event of the specified type occurs.
         */
-       addEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void;
-       /**
+  addEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void;
+  /**
         * Removes the specified listener previously registered with addEventListener.
         * @param {Chart} chart - Chart from which to remove the listener
         * @param {string} type - The ({@link ChartEvent}) type to remove
         * @param listener - The listener function to remove from the event target.
         */
-       removeEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void;
-       /**
+  removeEventListener(chart: Chart, type: string, listener: (e: ChartEvent) => void): void;
+  /**
         * @returns {number} the current devicePixelRatio of the device this platform is connected to.
         */
-       getDevicePixelRatio(): number;
-       /**
+  getDevicePixelRatio(): number;
+  /**
         * @param {HTMLCanvasElement} canvas - The canvas for which to calculate the maximum size
         * @param {number} [width] - Parent element's content width
         * @param {number} [height] - Parent element's content height
         * @param {number} [aspectRatio] - The aspect ratio to maintain
         * @returns { width: number, height: number } the maximum size available.
         */
-       getMaximumSize(canvas: HTMLCanvasElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number };
-       /**
+  getMaximumSize(canvas: HTMLCanvasElement, width?: number, height?: number, aspectRatio?: number): { width: number, height: number };
+  /**
         * @param {HTMLCanvasElement} canvas
         * @returns {boolean} true if the canvas is attached to the platform, false if not.
         */
-       isAttached(canvas: HTMLCanvasElement): boolean;
+  isAttached(canvas: HTMLCanvasElement): boolean;
 }
 
 export class BasicPlatform extends BasePlatform {}