]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Generic registry for controllers, scales, elements and plugins (#7435)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Mon, 6 Jul 2020 21:38:04 +0000 (00:38 +0300)
committerGitHub <noreply@github.com>
Mon, 6 Jul 2020 21:38:04 +0000 (17:38 -0400)
* Generic registry for controllers, scales, elements and plugins
* Remove references to scale service

41 files changed:
docs/docs/axes/index.md
docs/docs/developers/axes.md
docs/docs/developers/charts.md
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/controllers/index.js
src/core/core.controller.js
src/core/core.datasetController.js
src/core/core.defaults.js
src/core/core.element.js
src/core/core.registry.js [new file with mode: 0644]
src/core/core.scaleService.js [deleted file]
src/core/core.typedRegistry.js [new file with mode: 0644]
src/core/index.js
src/elements/element.arc.js
src/elements/element.line.js
src/elements/element.point.js
src/elements/element.rectangle.js
src/index.js
src/scales/scale.category.js
src/scales/scale.linear.js
src/scales/scale.logarithmic.js
src/scales/scale.radialLinear.js
src/scales/scale.time.js
src/scales/scale.timeseries.js
test/specs/controller.doughnut.tests.js
test/specs/core.controller.tests.js
test/specs/core.scale.tests.js
test/specs/core.scaleService.tests.js [deleted file]
test/specs/global.namespace.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

index 6466d327ad44b845ad4727ebb664f7a0e16c6450..d9f830ce7b859e0cd9545c1a86344e597b13ca2d 100644 (file)
@@ -45,14 +45,12 @@ There are a number of config callbacks that can be used to change parameters in
 
 ### Updating Axis Defaults
 
-The default configuration for a scale can be easily changed using the scale service. All you need to do is to pass in a partial configuration that will be merged with the current scale default configuration to form the new default.
+The default configuration for a scale can be easily changed. All you need to do is set the new options to `Chart.defaults.scales[type]`.
 
 For example, to set the minimum value of 0 for all linear scales, you would do the following. Any linear scales created after this time would now have a minimum of 0.
 
 ```javascript
-Chart.scaleService.updateScaleDefaults('linear', {
-    min: 0
-});
+Chart.defaults.scales.linear.min = 0;
 ```
 
 ## Creating New Axes
index d6adadbe4a1ef4cc3fdf2bf5408afa910e4a1adb..e4cd873c108463dd7bcd4880ecd07f8e372e9e44 100644 (file)
@@ -17,7 +17,7 @@ MyScale.defaults = defaultConfigObject;
 Once you have created your scale class, you need to register it with the global chart object so that it can be used. A default config for the scale may be provided when registering the constructor. The first parameter to the register function is a string key that is used later to identify which scale type to use for a chart.
 
 ```javascript
-Chart.scaleService.registerScale(MyScale);
+Chart.register(MyScale);
 ```
 
 To use the new scale, simply pass in the string key to the config when creating a chart.
index f68bebe477a06e303c3f3a9cf325aaab9fb00748..14c0cf1c8b2d827bd6727c7293f2cd65d06c35f0 100644 (file)
@@ -49,6 +49,7 @@ Dataset controllers must implement the following interface.
 ```
 
 The following methods may optionally be overridden by derived dataset controllers.
+
 ```javascript
 {
     // Initializes the controller
@@ -79,12 +80,6 @@ The built in controller types are:
 For example, to derive a new chart type that extends from a bubble chart, you would do the following.
 
 ```javascript
-// Sets the default config for 'derivedBubble' to be the same as the bubble defaults.
-// We look for the defaults by doing Chart.defaults[chartType]
-// It looks like a bug exists when the defaults don't exist
-Chart.defaults.derivedBubble = Chart.defaults.bubble;
-
-// I think the recommend using Chart.controllers.bubble.extend({ extensions here });
 class Custom extends Chart.controllers.bubble {
     draw() {
         // Call super method first
@@ -103,10 +98,11 @@ class Custom extends Chart.controllers.bubble {
         ctx.restore();
     }
 });
+Custom.id = 'derivedBubble';
+Custom.defaults = Chart.defaults.bubble;
 
-// Stores the controller so that the chart initialization routine can look it up with
-// Chart.controllers[type]
-Chart.controllers.derivedBubble = Custom;
+// Stores the controller so that the chart initialization routine can look it up
+Chart.register(Custom);
 
 // Now we can create and use our new chart type
 new Chart(ctx, {
index 5afb5b4ed7b9ea4a385e993d138c9ca889127a98..3608120294d568848f342d9c420b9ae7588a80f6 100644 (file)
@@ -1,41 +1,8 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Rectangle} from '../elements/index';
 import {clipArea, unclipArea} from '../helpers/helpers.canvas';
 import {isArray, isNullOrUndef, valueOrDefault, resolveObjectKey} from '../helpers/helpers.core';
 import {_limitValue, sign} from '../helpers/helpers.math';
 
-defaults.set('bar', {
-       hover: {
-               mode: 'index'
-       },
-
-       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,
-               }
-       }
-});
-
 /**
  * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
  * @private
@@ -507,16 +474,51 @@ export default class BarController extends DatasetController {
 
 }
 
-BarController.prototype.dataElementType = Rectangle;
-
-BarController.prototype.dataElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderSkipped',
-       'borderWidth',
-       'barPercentage',
-       'barThickness',
-       'categoryPercentage',
-       'maxBarThickness',
-       'minBarLength'
-];
+BarController.id = 'bar';
+
+/**
+ * @type {any}
+ */
+BarController.defaults = {
+       datasetElementType: false,
+       dataElementType: 'rectangle',
+       dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderSkipped',
+               'borderWidth',
+               'barPercentage',
+               'barThickness',
+               'categoryPercentage',
+               'maxBarThickness',
+               'minBarLength'
+       ],
+       hover: {
+               mode: 'index'
+       },
+
+       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 0fd32fec388e3126b1b78750b5b72800c21e1e66..3dd89e9f187b378e45c5f731aaa7b3068b297a12 100644 (file)
@@ -1,34 +1,7 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Point} from '../elements/index';
 import {resolve} from '../helpers/helpers.options';
 import {resolveObjectKey} from '../helpers/helpers.core';
 
-defaults.set('bubble', {
-       animation: {
-               numbers: {
-                       properties: ['x', 'y', 'borderWidth', 'radius']
-               }
-       },
-       scales: {
-               x: {
-                       type: 'linear'
-               },
-               y: {
-                       type: 'linear'
-               }
-       },
-
-       tooltips: {
-               callbacks: {
-                       title() {
-                               // Title doesn't make sense for scatter since we format the data as a point
-                               return '';
-                       }
-               }
-       }
-});
-
 export default class BubbleController extends DatasetController {
 
        /**
@@ -165,14 +138,42 @@ export default class BubbleController extends DatasetController {
        }
 }
 
-BubbleController.prototype.dataElementType = Point;
-
-BubbleController.prototype.dataElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderWidth',
-       'hitRadius',
-       'radius',
-       'pointStyle',
-       'rotation'
-];
+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'
+               }
+       },
+       tooltips: {
+               callbacks: {
+                       title() {
+                               // Title doesn't make sense for scatter since we format the data as a point
+                               return '';
+                       }
+               }
+       }
+};
index a7c13124d2de04a61e9b4d061cbbfdc4329b12c0..892c9ae3e70b59247e1b03bd215ccd70bc2cc0ef 100644 (file)
@@ -1,6 +1,4 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Arc} from '../elements/index';
 import {isArray, valueOrDefault} from '../helpers/helpers.core';
 
 /**
@@ -11,83 +9,6 @@ const PI = Math.PI;
 const DOUBLE_PI = PI * 2;
 const HALF_PI = PI / 2;
 
-defaults.set('doughnut', {
-       animation: {
-               numbers: {
-                       type: 'number',
-                       properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y']
-               },
-               // 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,
-       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();
-               }
-       },
-
-       // 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: -HALF_PI,
-
-       // The total circumference of the chart.
-       circumference: DOUBLE_PI,
-
-       // Need to override these to give a nice default
-       tooltips: {
-               callbacks: {
-                       title() {
-                               return '';
-                       },
-                       label(tooltipItem, data) {
-                               let dataLabel = data.labels[tooltipItem.index];
-                               const value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
-
-                               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;
-                       }
-               }
-       }
-});
-
 function getRatioAndOffset(rotation, circumference, cutout) {
        let ratioX = 1;
        let ratioY = 1;
@@ -330,14 +251,95 @@ export default class DoughnutController extends DatasetController {
        }
 }
 
-DoughnutController.prototype.dataElementType = Arc;
-
-DoughnutController.prototype.dataElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderWidth',
-       'borderAlign',
-       'hoverBackgroundColor',
-       'hoverBorderColor',
-       'hoverBorderWidth',
-];
+DoughnutController.id = 'doughnut';
+
+/**
+ * @type {any}
+ */
+DoughnutController.defaults = {
+       datasetElementType: false,
+       dataElementType: 'arc',
+       dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+       animation: {
+               numbers: {
+                       type: 'number',
+                       properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y']
+               },
+               // 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,
+       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();
+               }
+       },
+
+       // 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: -HALF_PI,
+
+       // The total circumference of the chart.
+       circumference: DOUBLE_PI,
+
+       // Need to override these to give a nice default
+       tooltips: {
+               callbacks: {
+                       title() {
+                               return '';
+                       },
+                       label(tooltipItem, data) {
+                               let dataLabel = data.labels[tooltipItem.index];
+                               const value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
+
+                               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 e9d31189ddf00496199f14572a2e5be2e09e99af..873dc281fe4700a336bf43aaeca4c2f2536e3024 100644 (file)
@@ -1,28 +1,8 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Line, Point} from '../elements/index';
 import {valueOrDefault} from '../helpers/helpers.core';
 import {isNumber} from '../helpers/helpers.math';
 import {resolve} from '../helpers/helpers.options';
 
-defaults.set('line', {
-       showLines: true,
-       spanGaps: false,
-
-       hover: {
-               mode: 'index'
-       },
-
-       scales: {
-               _index_: {
-                       type: 'category',
-               },
-               _value_: {
-                       type: 'linear',
-               },
-       }
-});
-
 export default class LineController extends DatasetController {
 
        constructor(chart, datasetIndex) {
@@ -158,34 +138,55 @@ export default class LineController extends DatasetController {
        }
 }
 
-LineController.prototype.datasetElementType = Line;
-
-LineController.prototype.dataElementType = Point;
-
-LineController.prototype.datasetElementOptions = [
-       'backgroundColor',
-       'borderCapStyle',
-       'borderColor',
-       'borderDash',
-       'borderDashOffset',
-       'borderJoinStyle',
-       'borderWidth',
-       'capBezierPoints',
-       'cubicInterpolationMode',
-       'fill'
-];
-
-LineController.prototype.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'
+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'
+       },
+
+       showLines: true,
+       spanGaps: false,
+
+       hover: {
+               mode: 'index'
+       },
+
+       scales: {
+               _index_: {
+                       type: 'category',
+               },
+               _value_: {
+                       type: 'linear',
+               },
+       }
 };
index 09acd50b5da5c79bccfca3baf81a4a935670fd3a..de95a69ef5d4a71a65b5fb9620a1a0726d03bbdd 100644 (file)
@@ -1,11 +1,15 @@
 import DoughnutController from './controller.doughnut';
-import defaults from '../core/core.defaults';
-import {clone} from '../helpers/helpers.core';
-
-defaults.set('pie', clone(defaults.doughnut));
-defaults.set('pie', {
-       cutoutPercentage: 0
-});
 
 // Pie charts are Doughnut chart with different defaults
-export default DoughnutController;
+export default class PieController extends DoughnutController {
+
+}
+
+PieController.id = 'pie';
+
+/**
+ * @type {any}
+ */
+PieController.defaults = {
+       cutoutPercentage: 0
+};
index 2a2cda9946e2460926ab956e0c4cd53443f4a084..5006eaef3939795526b3be18b8ead624d7a62d8e 100644 (file)
@@ -1,83 +1,7 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Arc} from '../elements/index';
 import {toRadians} from '../helpers/helpers.math';
 import {resolve} from '../helpers/helpers.options';
 
-defaults.set('polarArea', {
-       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,
-       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
-       tooltips: {
-               callbacks: {
-                       title() {
-                               return '';
-                       },
-                       label(item, data) {
-                               return data.labels[item.index] + ': ' + item.value;
-                       }
-               }
-       }
-});
-
 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.
@@ -211,14 +135,92 @@ export default class PolarAreaController extends DatasetController {
        }
 }
 
-PolarAreaController.prototype.dataElementType = Arc;
-
-PolarAreaController.prototype.dataElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderWidth',
-       'borderAlign',
-       'hoverBackgroundColor',
-       'hoverBorderColor',
-       'hoverBorderWidth'
-];
+PolarAreaController.id = 'polarArea';
+
+/**
+ * @type {any}
+ */
+PolarAreaController.defaults = {
+       dataElementType: 'arc',
+       dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth'
+       ],
+
+       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,
+       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
+       tooltips: {
+               callbacks: {
+                       title() {
+                               return '';
+                       },
+                       label(item, data) {
+                               return data.labels[item.index] + ': ' + item.value;
+                       }
+               }
+       }
+};
index 185b14db3debc498081bf34eea6bf3bc0a17127a..b7dca8f6a3feaea4277e419bada95528ba51354b 100644 (file)
@@ -1,27 +1,6 @@
 import DatasetController from '../core/core.datasetController';
-import defaults from '../core/core.defaults';
-import {Line, Point} from '../elements/index';
 import {valueOrDefault} from '../helpers/helpers.core';
 
-defaults.set('radar', {
-       aspectRatio: 1,
-       spanGaps: false,
-       scales: {
-               r: {
-                       type: 'radialLinear',
-               }
-       },
-       datasets: {
-               indexAxis: 'r'
-       },
-       elements: {
-               line: {
-                       fill: 'start',
-                       tension: 0 // no bezier in radar
-               }
-       }
-});
-
 export default class RadarController extends DatasetController {
 
        /**
@@ -104,31 +83,53 @@ export default class RadarController extends DatasetController {
        }
 }
 
-RadarController.prototype.datasetElementType = Line;
-
-RadarController.prototype.dataElementType = Point;
-
-RadarController.prototype.datasetElementOptions = [
-       'backgroundColor',
-       'borderColor',
-       'borderCapStyle',
-       'borderDash',
-       'borderDashOffset',
-       'borderJoinStyle',
-       'borderWidth',
-       'fill'
-];
-
-RadarController.prototype.dataElementOptions = {
-       backgroundColor: 'pointBackgroundColor',
-       borderColor: 'pointBorderColor',
-       borderWidth: 'pointBorderWidth',
-       hitRadius: 'pointHitRadius',
-       hoverBackgroundColor: 'pointHoverBackgroundColor',
-       hoverBorderColor: 'pointHoverBorderColor',
-       hoverBorderWidth: 'pointHoverBorderWidth',
-       hoverRadius: 'pointHoverRadius',
-       pointStyle: 'pointStyle',
-       radius: 'pointRadius',
-       rotation: 'pointRotation'
+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
+               }
+       }
 };
index 8acbac025b1996f0e848abacd7c653fa84b8b39d..75165a9d4e5acb96d38a70c153e286ffb6dc4ea7 100644 (file)
@@ -1,7 +1,15 @@
 import LineController from './controller.line';
-import defaults from '../core/core.defaults';
 
-defaults.set('scatter', {
+export default class ScatterController extends LineController {
+
+}
+
+ScatterController.id = 'scatter';
+
+/**
+ * @type {any}
+ */
+ScatterController.defaults = {
        scales: {
                x: {
                        type: 'linear'
@@ -25,7 +33,4 @@ defaults.set('scatter', {
                        }
                }
        }
-});
-
-// Scatter charts use line controllers
-export default LineController;
+};
index b853df6967b39e83bd7455cbcb7dbd9d29908e6a..8c0129b368741d6bcfb8b2f1feeb06a854e47f92 100644 (file)
@@ -1,8 +1,8 @@
-export {default as bar} from './controller.bar';
-export {default as bubble} from './controller.bubble';
-export {default as doughnut} from './controller.doughnut';
-export {default as line} from './controller.line';
-export {default as polarArea} from './controller.polarArea';
-export {default as pie} from './controller.pie';
-export {default as radar} from './controller.radar';
-export {default as scatter} from './controller.scatter';
+export {default as BarController} from './controller.bar';
+export {default as BubbleController} from './controller.bubble';
+export {default as DoughnutController} from './controller.doughnut';
+export {default as LineController} from './controller.line';
+export {default as PolarAreaController} from './controller.polarArea';
+export {default as PieController} from './controller.pie';
+export {default as RadarController} from './controller.radar';
+export {default as ScatterController} from './controller.scatter';
index f35ae23f2d27a0cfd72af0382218b04ca2fe198d..e36a514a451e03f373f6ae64c8ffc48adebe047a 100644 (file)
@@ -1,12 +1,11 @@
 /* eslint-disable import/no-namespace, import/namespace */
 import animator from './core.animator';
-import * as controllers from '../controllers';
 import defaults from './core.defaults';
 import Interaction from './core.interaction';
 import layouts from './core.layouts';
 import {BasicPlatform, DomPlatform} from '../platform';
 import plugins from './core.plugins';
-import scaleService from './core.scaleService';
+import registry from './core.registry';
 import {getMaximumWidth, getMaximumHeight, retinaScale} from '../helpers/helpers.dom';
 import {mergeIf, merge, _merger, each, callback as callCallback, uid, valueOrDefault, _elementsEqual} from '../helpers/helpers.core';
 import {clear as canvasClear, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas';
@@ -80,7 +79,7 @@ function mergeScaleConfig(config, options) {
        // apply scale defaults, if not overridden by dataset defaults
        Object.keys(scales).forEach(key => {
                const scale = scales[key];
-               mergeIf(scale, scaleService.getScaleDefaults(scale.type));
+               mergeIf(scale, [defaults.scales[scale.type], defaults.scale]);
        });
 
        return scales;
@@ -442,10 +441,7 @@ class Chart {
                        if (id in scales && scales[id].type === scaleType) {
                                scale = scales[id];
                        } else {
-                               const scaleClass = scaleService.getScaleConstructor(scaleType);
-                               if (!scaleClass) {
-                                       return;
-                               }
+                               const scaleClass = registry.getScale(scaleType);
                                scale = new scaleClass({
                                        id,
                                        type: scaleType,
@@ -473,7 +469,13 @@ class Chart {
 
                me.scales = scales;
 
-               scaleService.addScalesToLayout(this);
+               each(scales, (scale) => {
+                       // Set ILayoutItem parameters for backwards compatibility
+                       scale.fullWidth = scale.options.fullWidth;
+                       scale.position = scale.options.position;
+                       scale.weight = scale.options.weight;
+                       layouts.addBox(me, scale);
+               });
        }
 
        /**
@@ -537,11 +539,14 @@ class Chart {
                                meta.controller.updateIndex(i);
                                meta.controller.linkScales();
                        } else {
-                               const ControllerClass = controllers[meta.type];
-                               if (ControllerClass === undefined) {
-                                       throw new Error('"' + meta.type + '" is not a chart type.');
-                               }
-
+                               const controllerDefaults = defaults[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);
                        }
@@ -1171,4 +1176,6 @@ Chart.version = version;
  */
 Chart.instances = {};
 
+Chart.registry = registry;
+
 export default Chart;
index 255f54cb3899cb1e6a5ebb2da5a082a00b6a4ce2..57c431e6a3c95cd6a59f576709e69eb43ac81983 100644 (file)
@@ -686,7 +686,6 @@ export default class DatasetController {
                        datasetIndex: this.index,
                        active
                };
-
        }
 
        /**
@@ -696,7 +695,7 @@ export default class DatasetController {
        resolveDatasetElementOptions(active) {
                return this._resolveOptions(this.datasetElementOptions, {
                        active,
-                       type: this.datasetElementType._type
+                       type: this.datasetElementType.id
                });
        }
 
@@ -718,7 +717,7 @@ export default class DatasetController {
                        index,
                        active,
                        info,
-                       type: me.dataElementType._type
+                       type: me.dataElementType.id
                });
 
                if (info.cacheable) {
@@ -975,6 +974,11 @@ export default class DatasetController {
        }
 }
 
+/**
+ * @type {any}
+ */
+DatasetController.defaults = {};
+
 /**
  * Element type used to generate a meta dataset (e.g. Chart.element.Line).
  */
index 652ee34c55531d7093e4e4268beaec774bdb58c6..9cd435a762fe1df6bc6ceed4f25ea7fda89d45d9 100644 (file)
@@ -1,4 +1,4 @@
-import {merge, isArray, valueOrDefault} from '../helpers/helpers.core';
+import {merge, valueOrDefault} from '../helpers/helpers.core';
 
 /**
  * @param {object} node
@@ -58,6 +58,8 @@ export class Defaults {
                this.tooltips = undefined;
                this.doughnut = undefined;
                this._routes = {};
+               this.scales = undefined;
+               this.controllers = undefined;
        }
        /**
         * @param {string} scope
@@ -67,52 +69,48 @@ export class Defaults {
                return merge(getScope(this, scope), values);
        }
 
+       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
         * fallback is evaluated at each access, so its always up to date.
         *
-        * Examples:
+        * Example:
         *
         *      defaults.route('elements.arc', 'backgroundColor', '', 'color')
         *   - reads the backgroundColor from defaults.color when undefined locally
         *
-        *      defaults.route('elements.line', ['backgroundColor', 'borderColor'], '', 'color')
-        *   - reads the backgroundColor and borderColor from defaults.color when undefined locally
-        *
-        *      defaults.route('elements.customLine', ['borderWidth', 'tension'], 'elements.line', ['borderWidth', 'tension'])
-        *   - reads the borderWidth and tension from elements.line when those are not defined in elements.customLine
-        *
         * @param {string} scope Scope this route applies to.
-        * @param {string[]} names Names of the properties that should be routed to different namespace when not defined here.
-        * @param {string} targetScope The namespace where those properties should be routed to. Empty string ('') is the root of defaults.
-        * @param {string|string[]} targetNames The target name/names in the target scope the properties should be routed to.
+        * @param {string} name Property name that should be routed to different namespace when not defined here.
+        * @param {string} targetScope The namespace where those properties should be routed to.
+        * 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, names, targetScope, targetNames) {
+       route(scope, name, targetScope, targetName) {
                const scopeObject = getScope(this, scope);
                const targetScopeObject = getScope(this, targetScope);
-               const targetNamesIsArray = isArray(targetNames);
-               names.forEach((name, index) => {
-                       const privateName = '_' + name;
-                       const targetName = targetNamesIsArray ? targetNames[index] : targetNames;
-                       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]: {
-                                       writable: true
+               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]: {
+                               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() {
+                                       // @ts-ignore
+                                       return valueOrDefault(this[privateName], targetScopeObject[targetName]);
                                },
-                               // The actual property is defined as getter/setter so we can do the routing when value is not locally set.
-                               [name]: {
-                                       enumerable: true,
-                                       get() {
-                                               // @ts-ignore
-                                               return valueOrDefault(this[privateName], targetScopeObject[targetName]);
-                                       },
-                                       set(value) {
-                                               this[privateName] = value;
-                                       }
+                               set(value) {
+                                       this[privateName] = value;
                                }
-                       });
+                       }
                });
        }
 }
index 039ef657b41dbb933938f421fa395f15a06f9693..b0927ce994b923c380eaa0995c433c773d6fc8bb 100644 (file)
@@ -42,3 +42,13 @@ export default class Element {
                return ret;
        }
 }
+
+/**
+ * @type any
+ */
+Element.defaults = {};
+
+/**
+ * @type any
+ */
+Element.defaultRoutes = undefined;
diff --git a/src/core/core.registry.js b/src/core/core.registry.js
new file mode 100644 (file)
index 0000000..9b685bc
--- /dev/null
@@ -0,0 +1,154 @@
+import DatasetController from './core.datasetController';
+import Element from './core.element';
+import Scale from './core.scale';
+import TypedRegistry from './core.typedRegistry';
+import {each, callback as call} from '../helpers/helpers.core';
+
+/**
+ * Please use the module's default export which provides a singleton instance
+ * Note: class is exported for typedoc
+ */
+export class Registry {
+       constructor() {
+               this.controllers = new TypedRegistry(DatasetController, '');
+               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._registerEach(args);
+       }
+
+       /**
+        * @param  {...typeof DatasetController} args
+        */
+       addControllers(...args) {
+               this._registerEach(args, this.controllers);
+       }
+
+       /**
+        * @param  {...typeof Element} args
+        */
+       addElements(...args) {
+               this._registerEach(args, this.elements);
+       }
+
+       /**
+        * @param  {...any} args
+        */
+       addPlugins(...args) {
+               this._registerEach(args, this.plugins);
+       }
+
+       /**
+        * @param  {...typeof Scale} args
+        */
+       addScales(...args) {
+               this._registerEach(args, this.scales);
+       }
+
+       /**
+        * @param {string} id
+        * @returns {typeof DatasetController}
+        */
+       getController(id) {
+               return this._get(id, this.controllers, 'controller');
+       }
+
+       /**
+        * @param {string} id
+        * @returns {typeof Element}
+        */
+       getElement(id) {
+               return this._get(id, this.elements, 'element');
+       }
+
+       /**
+        * @param {string} id
+        * @returns {object}
+        */
+       getPlugin(id) {
+               return this._get(id, this.plugins, 'plugin');
+       }
+
+       /**
+        * @param {string} id
+        * @returns {typeof Scale}
+        */
+       getScale(id) {
+               return this._get(id, this.scales, 'scale');
+       }
+
+       /**
+        * @private
+        */
+       _registerEach(args, typedRegistry) {
+               const me = this;
+               [...args].forEach(arg => {
+                       const reg = typedRegistry || me._getRegistryForType(arg);
+                       if (reg.isForType(arg)) {
+                               me._registerComponent(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._registerComponent(itemReg, item);
+                               });
+                       }
+               });
+       }
+
+       /**
+        * @private
+        */
+       _registerComponent(registry, component) {
+               call(component.beforeRegister, [], component);
+               registry.register(component);
+               call(component.afterRegister, [], 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;
+       }
+
+       /**
+        * @private
+        */
+       _get(id, typedRegistry, type) {
+               const item = typedRegistry.get(id);
+               if (item === undefined) {
+                       throw new Error('"' + id + '" is not a registered ' + type + '.');
+               }
+               return item;
+       }
+
+}
+
+// singleton instance
+export default new Registry();
diff --git a/src/core/core.scaleService.js b/src/core/core.scaleService.js
deleted file mode 100644 (file)
index 00308da..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-import defaults from './core.defaults';
-import {clone, each, merge} from '../helpers/helpers.core';
-import layouts from './core.layouts';
-
-export default {
-       // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
-       // use the new chart options to grab the correct scale
-       constructors: {},
-       // Use a registration function so that we can move to an ES6 map when we no longer need to support
-       // old browsers
-
-       // Scale config defaults
-       defaults: {},
-       registerScale(scaleConstructor) {
-               const me = this;
-               const type = scaleConstructor.id;
-               me.constructors[type] = scaleConstructor;
-               me.defaults[type] = clone(scaleConstructor.defaults);
-       },
-       getScaleConstructor(type) {
-               return Object.prototype.hasOwnProperty.call(this.constructors, type) ? this.constructors[type] : undefined;
-       },
-       getScaleDefaults(type) {
-               // Return the scale defaults merged with the global settings so that we always use the latest ones
-               return Object.prototype.hasOwnProperty.call(this.defaults, type) ? merge({}, [defaults.scale, this.defaults[type]]) : {};
-       },
-       updateScaleDefaults(type, additions) {
-               const me = this;
-               if (Object.prototype.hasOwnProperty.call(me.defaults, type)) {
-                       me.defaults[type] = Object.assign(me.defaults[type], additions);
-               }
-       },
-       addScalesToLayout(chart) {
-               // Adds each scale to the chart.boxes array to be sized accordingly
-               each(chart.scales, (scale) => {
-                       // Set ILayoutItem parameters for backwards compatibility
-                       scale.fullWidth = scale.options.fullWidth;
-                       scale.position = scale.options.position;
-                       scale.weight = scale.options.weight;
-                       layouts.addBox(chart, scale);
-               });
-       }
-};
diff --git a/src/core/core.typedRegistry.js b/src/core/core.typedRegistry.js
new file mode 100644 (file)
index 0000000..e84126b
--- /dev/null
@@ -0,0 +1,104 @@
+import defaults from './core.defaults';
+import {valueOrDefault} from '../helpers/helpers.core';
+
+/**
+ * @typedef {{id: string, defaults: any, defaultRoutes: any}} IChartComponent
+ */
+
+export default class TypedRegistry {
+       constructor(type, scope) {
+               this.type = type;
+               this.scope = scope;
+               this.items = Object.create(null);
+       }
+
+       isForType(type) {
+               return Object.prototype.isPrototypeOf.call(this.type, type);
+       }
+
+       /**
+        * @param {IChartComponent} item
+        * @param {string} [scopeOverride]
+        * @returns {string} The scope where items defaults were registered to.
+        */
+       register(item, scopeOverride) {
+               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);
+               }
+
+               const items = this.items;
+               const id = item.id;
+               const baseScope = valueOrDefault(scopeOverride, this.scope);
+               const scope = baseScope ? baseScope + '.' + id : id;
+
+               if (!id) {
+                       throw new Error('class does not have id: ' + Object.getPrototypeOf(item));
+               }
+
+               if (id in items) {
+                       // already registered
+                       return scope;
+               }
+
+               items[id] = item;
+               registerDefaults(item, scope, parentScope);
+
+               return scope;
+       }
+
+       /**
+        * @param {string} id
+        * @returns {object?}
+        */
+       get(id) {
+               return this.items[id];
+       }
+
+       /**
+        * @param {IChartComponent} item
+        */
+       unregister(item) {
+               const items = this.items;
+               const id = item.id;
+
+               if (id in items) {
+                       delete items[id];
+               }
+
+               if (id in defaults[this.scope]) {
+                       delete defaults[this.scope][id];
+               } else if (id in defaults) {
+                       delete defaults[id];
+               }
+       }
+}
+
+function registerDefaults(item, scope, parentScope) {
+       // Inherit the parent's defaults
+       const itemDefaults = parentScope
+               ? Object.assign({}, defaults.get(parentScope), item.defaults)
+               : item.defaults;
+
+       defaults.set(scope, itemDefaults);
+
+       if (item.defaultRoutes) {
+               routeDefaults(scope, item.defaultRoutes);
+       }
+}
+
+function routeDefaults(scope, routes) {
+       Object.keys(routes).forEach(property => {
+               const parts = routes[property].split('.');
+               const targetName = parts.pop();
+               const targetScope = parts.join('.');
+               defaults.route(scope, property, targetScope, targetName);
+       });
+}
+
+function isIChartComponent(proto) {
+       return 'id' in proto && 'defaults' in proto;
+}
index 6f91d53e83126bbbc5fcfec10097dfef1a2d5d81..af0b30963fcad44aab1ec7c94218790d3e5fe4db 100644 (file)
@@ -9,6 +9,6 @@ export {default as Element} from './core.element';
 export {default as Interaction} from './core.interaction';
 export {default as layouts} from './core.layouts';
 export {default as plugins} from './core.plugins';
+export {default as registry} from './core.registry';
 export {default as Scale} from './core.scale';
-export {default as ScaleService} from './core.scaleService';
 export {default as Ticks} from './core.ticks';
index 243524468989043a5532b2a0c97eef164186203c..a69415a03bc34d87f18103451af76350ee232ca3 100644 (file)
@@ -1,16 +1,7 @@
-import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import {_angleBetween, getAngleFromPoint} from '../helpers/helpers.math';
-const TAU = Math.PI * 2;
-
-const scope = 'elements.arc';
-defaults.set(scope, {
-       borderAlign: 'center',
-       borderColor: '#fff',
-       borderWidth: 2
-});
 
-defaults.route(scope, ['backgroundColor'], '', ['color']);
+const TAU = Math.PI * 2;
 
 function clipArc(ctx, model) {
        const {startAngle, endAngle, pixelMargin, x, y} = model;
@@ -108,7 +99,7 @@ function drawBorder(ctx, element, model) {
        ctx.stroke();
 }
 
-class Arc extends Element {
+export default class Arc extends Element {
 
        constructor(cfg) {
                super();
@@ -207,6 +198,20 @@ class Arc extends Element {
        }
 }
 
-Arc._type = 'arc';
+Arc.id = 'arc';
 
-export default Arc;
+/**
+ * @type {any}
+ */
+Arc.defaults = {
+       borderAlign: 'center',
+       borderColor: '#fff',
+       borderWidth: 2
+};
+
+/**
+ * @type {any}
+ */
+Arc.defaultRoutes = {
+       backgroundColor: 'color'
+};
index db1cae385e53ba7539fd19167e7d60986a1d15a9..46b5ae6e8b0ee4562697a7e28b451c8e856ed862 100644 (file)
@@ -1,4 +1,3 @@
-import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import {_bezierInterpolation, _pointInLine, _steppedInterpolation} from '../helpers/helpers.interpolation';
 import {_computeSegments, _boundSegments} from '../helpers/helpers.segment';
@@ -9,20 +8,6 @@ import {_updateBezierControlPoints} from '../helpers/helpers.curve';
  * @typedef { import("./element.point").default } Point
  */
 
-const scope = 'elements.line';
-defaults.set(scope, {
-       borderCapStyle: 'butt',
-       borderDash: [],
-       borderDashOffset: 0,
-       borderJoinStyle: 'miter',
-       borderWidth: 3,
-       capBezierPoints: true,
-       fill: true,
-       tension: 0
-});
-
-defaults.route(scope, ['backgroundColor', 'borderColor'], '', 'color');
-
 function setStyle(ctx, vm) {
        ctx.lineCap = vm.borderCapStyle;
        ctx.setLineDash(vm.borderDash);
@@ -199,7 +184,7 @@ function _getInterpolationMethod(options) {
        return _pointInLine;
 }
 
-class Line extends Element {
+export default class Line extends Element {
 
        constructor(cfg) {
                super();
@@ -359,6 +344,26 @@ class Line extends Element {
        }
 }
 
-Line._type = 'line';
+Line.id = 'line';
 
-export default Line;
+/**
+ * @type {any}
+ */
+Line.defaults = {
+       borderCapStyle: 'butt',
+       borderDash: [],
+       borderDashOffset: 0,
+       borderJoinStyle: 'miter',
+       borderWidth: 3,
+       capBezierPoints: true,
+       fill: true,
+       tension: 0
+};
+
+/**
+ * @type {any}
+ */
+Line.defaultRoutes = {
+       backgroundColor: 'color',
+       borderColor: 'color'
+};
index 93e4948bbc52a18d831c0ba00168167c6bdb474b..52b38645fb63aac5409ddc9be3d33f7c3f12081a 100644 (file)
@@ -1,20 +1,7 @@
-import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import {_isPointInArea, drawPoint} from '../helpers/helpers.canvas';
 
-const scope = 'elements.point';
-defaults.set(scope, {
-       borderWidth: 1,
-       hitRadius: 1,
-       hoverBorderWidth: 1,
-       hoverRadius: 4,
-       pointStyle: 'circle',
-       radius: 3
-});
-
-defaults.route(scope, ['backgroundColor', 'borderColor'], '', 'color');
-
-class Point extends Element {
+export default class Point extends Element {
 
        constructor(cfg) {
                super();
@@ -82,6 +69,24 @@ class Point extends Element {
        }
 }
 
-Point._type = 'point';
+Point.id = 'point';
 
-export default Point;
+/**
+ * @type {any}
+ */
+Point.defaults = {
+       borderWidth: 1,
+       hitRadius: 1,
+       hoverBorderWidth: 1,
+       hoverRadius: 4,
+       pointStyle: 'circle',
+       radius: 3
+};
+
+/**
+ * @type {any}
+ */
+Point.defaultRoutes = {
+       backgroundColor: 'color',
+       borderColor: 'color'
+};
index 8dfa2833d1c4736601badb79d925e4734c2a276d..2363a87ffdeda811d439e8a0081173cfe070b1ad 100644 (file)
@@ -1,15 +1,6 @@
-import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import {isObject} from '../helpers/helpers.core';
 
-const scope = 'elements.rectangle';
-defaults.set(scope, {
-       borderSkipped: 'start',
-       borderWidth: 0
-});
-
-defaults.route(scope, ['backgroundColor', 'borderColor'], '', 'color');
-
 /**
  * Helper function to get the bounds of the bar regardless of the orientation
  * @param {Rectangle} bar the bar
@@ -131,7 +122,7 @@ function inRange(bar, x, y, useFinalPosition) {
                && (skipY || y >= bounds.top && y <= bounds.bottom);
 }
 
-class Rectangle extends Element {
+export default class Rectangle extends Element {
 
        constructor(cfg) {
                super();
@@ -193,6 +184,20 @@ class Rectangle extends Element {
        }
 }
 
-Rectangle._type = 'rectangle';
+Rectangle.id = 'rectangle';
 
-export default Rectangle;
+/**
+ * @type {any}
+ */
+Rectangle.defaults = {
+       borderSkipped: 'start',
+       borderWidth: 0
+};
+
+/**
+ * @type {any}
+ */
+Rectangle.defaultRoutes = {
+       backgroundColor: 'color',
+       borderColor: 'color'
+};
index 4ee572ae77738ae512e570217067ac0dd2026738..3b2cd389cebdcd3a989ddf5b76a0af15053b7352 100644 (file)
@@ -17,18 +17,25 @@ import Element from './core/core.element';
 import * as elements from './elements/index';
 import Interaction from './core/core.interaction';
 import layouts from './core/core.layouts';
-import * as platforms from './platform';
+import * as platforms from './platform/index';
+import * as plugins from './plugins';
 import pluginsCore from './core/core.plugins';
+import registry from './core/core.registry';
 import Scale from './core/core.scale';
-import scaleService from './core/core.scaleService';
+import * as scales from './scales';
 import Ticks from './core/core.ticks';
 
+Chart.register = (...items) => registry.add(...items);
+
+// Register built-ins
+Chart.register(controllers, scales, elements, plugins);
+
 Chart.helpers = helpers;
 Chart._adapters = _adapters;
 Chart.Animation = Animation;
 Chart.animator = animator;
 Chart.animationService = animationService;
-Chart.controllers = controllers;
+Chart.controllers = registry.controllers.items;
 Chart.DatasetController = DatasetController;
 Chart.defaults = defaults;
 Chart.Element = Element;
@@ -37,16 +44,10 @@ Chart.Interaction = Interaction;
 Chart.layouts = layouts;
 Chart.platforms = platforms;
 Chart.plugins = pluginsCore;
+Chart.registry = registry;
 Chart.Scale = Scale;
-Chart.scaleService = scaleService;
 Chart.Ticks = Ticks;
 
-// Register built-in scales
-import * as scales from './scales';
-Object.keys(scales).forEach(key => Chart.scaleService.registerScale(scales[key]));
-
-// Loading built-in plugins
-import * as plugins from './plugins';
 for (const k in plugins) {
        if (Object.prototype.hasOwnProperty.call(plugins, k)) {
                Chart.plugins.register(plugins[k]);
index 3386aa1e08afc8412c95de4786bd7be7d53235ab..988bcc0cdca2657b78714a741ea292e1c0e9c7ab 100644 (file)
@@ -1,9 +1,6 @@
 import Scale from '../core/core.scale';
 
-const defaultConfig = {
-};
-
-class CategoryScale extends Scale {
+export default class CategoryScale extends Scale {
 
        constructor(cfg) {
                super(cfg);
@@ -108,7 +105,7 @@ class CategoryScale extends Scale {
 
 CategoryScale.id = 'category';
 
-// INTERNAL: default options, registered in src/index.js
-CategoryScale.defaults = defaultConfig;
-
-export default CategoryScale;
+/**
+ * @type {any}
+ */
+CategoryScale.defaults = {};
index c7f8e88ec7d6c5595f1ee892fe8086c81bbd0740..bd3fc5af6985e1431a78ac0847134805aaa89a82 100644 (file)
@@ -2,13 +2,7 @@ import {isFinite, valueOrDefault} from '../helpers/helpers.core';
 import LinearScaleBase from './scale.linearbase';
 import Ticks from '../core/core.ticks';
 
-const defaultConfig = {
-       ticks: {
-               callback: Ticks.formatters.numeric
-       }
-};
-
-class LinearScale extends LinearScaleBase {
+export default class LinearScale extends LinearScaleBase {
 
        determineDataLimits() {
                const me = this;
@@ -54,7 +48,11 @@ class LinearScale extends LinearScaleBase {
 
 LinearScale.id = 'linear';
 
-// INTERNAL: default options, registered in src/index.js
-LinearScale.defaults = defaultConfig;
-
-export default LinearScale;
+/**
+ * @type {any}
+ */
+LinearScale.defaults = {
+       ticks: {
+               callback: Ticks.formatters.numeric
+       }
+};
index e0cce4182a626e7adea49e680ccc684c467605cc..98942f9b60e93befe7d56acd4aaab22a8dd41acb 100644 (file)
@@ -47,17 +47,7 @@ function generateTicks(generationOptions, dataRange) {
        return ticks;
 }
 
-const defaultConfig = {
-       // label settings
-       ticks: {
-               callback: Ticks.formatters.logarithmic,
-               major: {
-                       enabled: true
-               }
-       }
-};
-
-class LogarithmicScale extends Scale {
+export default class LogarithmicScale extends Scale {
 
        constructor(cfg) {
                super(cfg);
@@ -184,7 +174,14 @@ class LogarithmicScale extends Scale {
 
 LogarithmicScale.id = 'logarithmic';
 
-// INTERNAL: default options, registered in src/index.js
-LogarithmicScale.defaults = defaultConfig;
-
-export default LogarithmicScale;
+/**
+ * @type {any}
+ */
+LogarithmicScale.defaults = {
+       ticks: {
+               callback: Ticks.formatters.logarithmic,
+               major: {
+                       enabled: true
+               }
+       }
+};
index 888c5c570149ae73637451ae8b10611c46ec9d7b..fa1f7caa4671a0a74b131c9efa0f44c0ff168f77 100644 (file)
@@ -6,59 +6,6 @@ import Ticks from '../core/core.ticks';
 import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
 import {toFont, resolve} from '../helpers/helpers.options';
 
-
-const defaultConfig = {
-       display: true,
-
-       // Boolean - Whether to animate scaling the chart from the centre
-       animate: true,
-       position: 'chartArea',
-
-       angleLines: {
-               display: true,
-               color: 'rgba(0,0,0,0.1)',
-               lineWidth: 1,
-               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;
-               }
-       }
-};
-
 function getTickBackdropHeight(opts) {
        const tickOpts = opts.ticks;
 
@@ -306,7 +253,7 @@ function numberOrZero(param) {
        return isNumber(param) ? param : 0;
 }
 
-class RadialLinearScale extends LinearScaleBase {
+export default class RadialLinearScale extends LinearScaleBase {
 
        constructor(cfg) {
                super(cfg);
@@ -593,7 +540,57 @@ class RadialLinearScale extends LinearScaleBase {
 
 RadialLinearScale.id = 'radialLinear';
 
-// INTERNAL: default options, registered in src/index.js
-RadialLinearScale.defaults = defaultConfig;
+/**
+ * @type {any}
+ */
+RadialLinearScale.defaults = {
+       display: true,
+
+       // Boolean - Whether to animate scaling the chart from the centre
+       animate: true,
+       position: 'chartArea',
+
+       angleLines: {
+               display: true,
+               color: 'rgba(0,0,0,0.1)',
+               lineWidth: 1,
+               borderDash: [],
+               borderDashOffset: 0.0
+       },
 
-export default RadialLinearScale;
+       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;
+               }
+       }
+};
index 61e2491b707248126b1aae407d2bfbad323167b0..888f424c58d8057bf92a049285cee0c4b6dd505f 100644 (file)
@@ -198,44 +198,7 @@ function ticksFromTimestamps(scale, values, majorUnit) {
        return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
 }
 
-const defaultConfig = {
-
-       /**
-        * 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: {
-               /**
-                * 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).
-                * - 'labels': generates ticks from user given `data.labels` values ONLY.
-                * @see https://github.com/chartjs/Chart.js/pull/4507
-                * @since 2.7.0
-                */
-               source: 'auto',
-
-               major: {
-                       enabled: false
-               }
-       }
-};
-
-class TimeScale extends Scale {
+export default class TimeScale extends Scale {
 
        /**
         * @param {object} props
@@ -644,7 +607,41 @@ class TimeScale extends Scale {
 
 TimeScale.id = 'time';
 
-// INTERNAL: default options, registered in src/index.js
-TimeScale.defaults = defaultConfig;
+/**
+ * @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',
 
-export default TimeScale;
+       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).
+                * - 'labels': generates ticks from user given `data.labels` values ONLY.
+                * @see https://github.com/chartjs/Chart.js/pull/4507
+                * @since 2.7.0
+                */
+               source: 'auto',
+
+               major: {
+                       enabled: false
+               }
+       }
+};
index 1476040eb9944738fa654db18a0feb38c55c6431..a1cce266f29b041ed2b18ee79879fa1c24882c65 100644 (file)
@@ -191,7 +191,9 @@ class TimeSeriesScale extends TimeScale {
 
 TimeSeriesScale.id = 'timeseries';
 
-// INTERNAL: default options, registered in src/index.js
+/**
+ * @type {any}
+ */
 TimeSeriesScale.defaults = TimeScale.defaults;
 
 export default TimeSeriesScale;
index dbf9f0ce34e1906438b6bc4cfdedeb45ecf28e45..32c992dcd012ba75749333675dfdb224eec20752 100644 (file)
@@ -3,7 +3,7 @@ describe('Chart.controllers.doughnut', function() {
 
        it('should be registered as dataset controller', function() {
                expect(typeof Chart.controllers.doughnut).toBe('function');
-               expect(Chart.controllers.doughnut).toBe(Chart.controllers.pie);
+               expect(typeof Chart.controllers.pie).toBe('function');
        });
 
        it('should be constructed', function() {
index ed94068a7a45afbae589ea97d0506d0959186501..e733d6a6bd3d52c1762caa825968030af5cfb2bd 100644 (file)
@@ -163,7 +163,7 @@ describe('Chart', function() {
                                        }
                                });
                        }
-                       expect(createChart).toThrow(new Error('"area" is not a chart type.'));
+                       expect(createChart).toThrow(new Error('"area" is not a registered controller.'));
                });
        });
 
@@ -175,7 +175,7 @@ describe('Chart', function() {
                                _jasmineCheckC: 'c0'
                        });
 
-                       Chart.helpers.merge(Chart.scaleService.defaults.logarithmic, {
+                       Chart.helpers.merge(Chart.defaults.scales.logarithmic, {
                                _jasmineCheckB: 'b1',
                                _jasmineCheckC: 'c1',
                        });
@@ -185,8 +185,8 @@ describe('Chart', function() {
                        delete Chart.defaults.scale._jasmineCheckA;
                        delete Chart.defaults.scale._jasmineCheckB;
                        delete Chart.defaults.scale._jasmineCheckC;
-                       delete Chart.scaleService.defaults.logarithmic._jasmineCheckB;
-                       delete Chart.scaleService.defaults.logarithmic._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() {
@@ -298,8 +298,8 @@ describe('Chart', function() {
 
                        expect(Chart.defaults.line._jasmineCheck).not.toBeDefined();
                        expect(Chart.defaults._jasmineCheck).not.toBeDefined();
-                       expect(Chart.scaleService.defaults.linear._jasmineCheck).not.toBeDefined();
-                       expect(Chart.scaleService.defaults.category._jasmineCheck).not.toBeDefined();
+                       expect(Chart.defaults.scales.linear._jasmineCheck).not.toBeDefined();
+                       expect(Chart.defaults.scales.category._jasmineCheck).not.toBeDefined();
                });
        });
 
index 556fea585a2132fd3f1cb0482b882e3952d73f51..2062eacee07e11b4ff2c03cfd02cefb7c79f4dfe 100644 (file)
@@ -462,7 +462,7 @@ describe('Core.scale', function() {
                        }
                        CustomScale.id = 'customScale';
                        CustomScale.defaults = {};
-                       Chart.scaleService.registerScale(CustomScale);
+                       Chart.register(CustomScale);
 
                        var chart = window.acquireChart({
                                type: 'line',
diff --git a/test/specs/core.scaleService.tests.js b/test/specs/core.scaleService.tests.js
deleted file mode 100644 (file)
index ecf5b21..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// Tests of the scale service
-describe('Test the scale service', function() {
-
-       it('should update scale defaults', function() {
-               var type = 'my_test_type';
-               var Constructor = function() {
-                       this.initialized = true;
-               };
-               Constructor.id = type;
-               Constructor.defaults = {
-                       testProp: true
-               };
-               Chart.scaleService.registerScale(Constructor);
-
-               // Should equal defaults but not be an identical object
-               expect(Chart.scaleService.getScaleDefaults(type)).toEqual(jasmine.objectContaining({
-                       testProp: true
-               }));
-
-               Chart.scaleService.updateScaleDefaults(type, {
-                       testProp: 'red',
-                       newProp: 42
-               });
-
-               expect(Chart.scaleService.getScaleDefaults(type)).toEqual(jasmine.objectContaining({
-                       testProp: 'red',
-                       newProp: 42
-               }));
-       });
-});
index cb4675fc6d209ba733593c728da257b220a91b51..8e39d5574f4d3435a14543cbeae1b4a0f8c413fe 100644 (file)
@@ -17,8 +17,8 @@ describe('Chart namespace', function() {
                        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.scaleService instanceof Object).toBeTruthy();
                        expect(Chart.Ticks instanceof Object).toBeTruthy();
                });
        });
index 0e17194bac3129934ff55f423b12bcd96af3dbb3..5c998dc4f590a103194cc37ef1ee3c46c71a974c 100644 (file)
@@ -11,52 +11,15 @@ function getValues(scale) {
 describe('Category scale tests', function() {
        describe('auto', jasmine.fixture.specs('scale.category'));
 
-       it('Should register the constructor with the scale service', function() {
-               var Constructor = Chart.scaleService.getScaleConstructor('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.scaleService.getScaleDefaults('category');
-               expect(defaultConfig).toEqual({
-                       display: true,
-                       reverse: false,
-                       beginAtZero: false,
-
-                       gridLines: {
-                               color: 'rgba(0,0,0,0.1)',
-                               drawBorder: true,
-                               drawOnChartArea: true,
-                               drawTicks: true, // draw ticks extending towards the label
-                               tickMarkLength: 10,
-                               lineWidth: 1,
-                               offsetGridLines: false,
-                               display: true,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-                       offset: false,
-                       scaleLabel: Chart.defaults.scale.scaleLabel,
-                       ticks: {
-                               minRotation: 0,
-                               maxRotation: 50,
-                               mirror: false,
-                               padding: 0,
-                               display: true,
-                               callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
-                               autoSkip: true,
-                               autoSkipPadding: 0,
-                               labelOffset: 0,
-                               minor: {},
-                               major: {},
-                               lineWidth: 0,
-                               strokeStyle: '',
-                       }
-               });
-
-               // Is this actually a function
-               expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
+               var defaultConfig = Chart.defaults.scales.category;
+               expect(defaultConfig).toEqual({});
        });
 
 
@@ -71,9 +34,9 @@ describe('Category scale tests', function() {
                        xLabels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
                };
 
-               var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+               var config = Chart.helpers.clone(Chart.defaults.scales.category);
                config.position = 'bottom';
-               var Constructor = Chart.scaleService.getScaleConstructor('category');
+               var Constructor = Chart.registry.getScale('category');
                var scale = new Constructor({
                        ctx: {},
                        chart: {
@@ -99,9 +62,9 @@ describe('Category scale tests', function() {
                        yLabels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
                };
 
-               var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
+               var config = Chart.helpers.clone(Chart.defaults.scales.category);
                config.position = 'left'; // y axis
-               var Constructor = Chart.scaleService.getScaleConstructor('category');
+               var Constructor = Chart.registry.getScale('category');
                var scale = new Constructor({
                        ctx: {},
                        chart: {
index 0d1eec7cd208ca1a2b2f484f83630d9cd8f93e13..36014eabf2b0a4d4a3cedaa5e9501963e6d78a6c 100644 (file)
@@ -5,48 +5,14 @@ function getLabels(scale) {
 describe('Linear Scale', function() {
        describe('auto', jasmine.fixture.specs('scale.linear'));
 
-       it('Should register the constructor with the scale service', function() {
-               var Constructor = Chart.scaleService.getScaleConstructor('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.scaleService.getScaleDefaults('linear');
-               expect(defaultConfig).toEqual({
-                       display: true,
-                       gridLines: {
-                               color: 'rgba(0,0,0,0.1)',
-                               drawBorder: true,
-                               drawOnChartArea: true,
-                               drawTicks: true, // draw ticks extending towards the label
-                               tickMarkLength: 10,
-                               lineWidth: 1,
-                               offsetGridLines: false,
-                               display: true,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-                       offset: false,
-                       reverse: false,
-                       beginAtZero: false,
-                       scaleLabel: Chart.defaults.scale.scaleLabel,
-                       ticks: {
-                               minRotation: 0,
-                               maxRotation: 50,
-                               mirror: false,
-                               padding: 0,
-                               display: true,
-                               callback: defaultConfig.ticks.callback, // make this work nicer, then check below
-                               autoSkip: true,
-                               autoSkipPadding: 0,
-                               labelOffset: 0,
-                               minor: {},
-                               major: {},
-                               lineWidth: 0,
-                               strokeStyle: '',
-                       }
-               });
+               var defaultConfig = Chart.defaults.scales.linear;
 
                expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
        });
index c1c98d819852dba5494595b9449e0be9e926524e..19a616ab2765c7eac8b6887ed872c553f683a91e 100644 (file)
@@ -3,49 +3,21 @@ function getLabels(scale) {
 }
 
 describe('Logarithmic Scale tests', function() {
-       it('should register the constructor with the scale service', function() {
-               var Constructor = Chart.scaleService.getScaleConstructor('logarithmic');
+       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.scaleService.getScaleDefaults('logarithmic');
+               var defaultConfig = Chart.defaults.scales.logarithmic;
                expect(defaultConfig).toEqual({
-                       display: true,
-                       gridLines: {
-                               color: 'rgba(0,0,0,0.1)',
-                               drawBorder: true,
-                               drawOnChartArea: true,
-                               drawTicks: true,
-                               tickMarkLength: 10,
-                               lineWidth: 1,
-                               offsetGridLines: false,
-                               display: true,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-                       offset: false,
-                       reverse: false,
-                       beginAtZero: false,
-                       scaleLabel: Chart.defaults.scale.scaleLabel,
                        ticks: {
-                               minRotation: 0,
-                               maxRotation: 50,
-                               mirror: false,
-                               padding: 0,
-                               display: true,
-                               callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
-                               autoSkip: true,
-                               autoSkipPadding: 0,
-                               labelOffset: 0,
-                               minor: {},
-                               lineWidth: 0,
-                               strokeStyle: '',
+                               callback: Chart.Ticks.formatters.logarithmic,
                                major: {
                                        enabled: true
-                               },
-                       },
+                               }
+                       }
                });
 
                // Is this actually a function
index 1e2268652ddc7794ce79de3cae091a56470dc070..dd0846d71789bd8d1dd4a831b7b48673fcdd0e2b 100644 (file)
@@ -6,15 +6,19 @@ function getLabels(scale) {
 describe('Test the radial linear scale', function() {
        describe('auto', jasmine.fixture.specs('scale.radialLinear'));
 
-       it('Should register the constructor with the scale service', function() {
-               var Constructor = Chart.scaleService.getScaleConstructor('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.scaleService.getScaleDefaults('radialLinear');
+               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)',
@@ -22,52 +26,26 @@ describe('Test the radial linear scale', function() {
                                borderDash: [],
                                borderDashOffset: 0.0
                        },
-                       animate: true,
-                       display: true,
+
                        gridLines: {
-                               circular: false,
-                               color: 'rgba(0,0,0,0.1)',
-                               drawBorder: true,
-                               drawOnChartArea: true,
-                               drawTicks: true,
-                               tickMarkLength: 10,
-                               lineWidth: 1,
-                               offsetGridLines: false,
-                               display: true,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-                       pointLabels: {
-                               display: true,
-                               font: {
-                                       size: 10,
-                               },
-                               callback: defaultConfig.pointLabels.callback, // make this nicer, then check explicitly below
+                               circular: false
                        },
-                       position: 'chartArea',
-                       offset: false,
-                       reverse: false,
-                       beginAtZero: false,
-                       scaleLabel: Chart.defaults.scale.scaleLabel,
+
                        ticks: {
+                               showLabelBackdrop: true,
                                backdropColor: 'rgba(255,255,255,0.75)',
                                backdropPaddingY: 2,
                                backdropPaddingX: 2,
-                               minRotation: 0,
-                               maxRotation: 50,
-                               mirror: false,
-                               padding: 0,
-                               showLabelBackdrop: true,
-                               display: true,
-                               callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
-                               autoSkip: true,
-                               autoSkipPadding: 0,
-                               labelOffset: 0,
-                               minor: {},
-                               major: {},
-                               lineWidth: 0,
-                               strokeStyle: '',
+                               callback: defaultConfig.ticks.callback
                        },
+
+                       pointLabels: {
+                               display: true,
+                               font: {
+                                       size: 10
+                               },
+                               callback: defaultConfig.pointLabels.callback
+                       }
                });
 
                // Is this actually a function
index 3300c19fa34b82727afecfb4634a54e1aafdf506..db7fb9c3948cd5398178dfc3f31a481413e31a5d 100644 (file)
@@ -52,64 +52,32 @@ describe('Time scale tests', function() {
                expect(window.moment).not.toBe(undefined);
        });
 
-       it('should register the constructor with the scale service', function() {
-               var Constructor = Chart.scaleService.getScaleConstructor('time');
+       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.scaleService.getScaleDefaults('time');
+               var defaultConfig = Chart.defaults.scales.time;
                expect(defaultConfig).toEqual({
-                       display: true,
-                       gridLines: {
-                               color: 'rgba(0,0,0,0.1)',
-                               drawBorder: true,
-                               drawOnChartArea: true,
-                               drawTicks: true,
-                               tickMarkLength: 10,
-                               lineWidth: 1,
-                               offsetGridLines: false,
-                               display: true,
-                               borderDash: [],
-                               borderDashOffset: 0.0
-                       },
-                       offset: false,
-                       reverse: false,
-                       beginAtZero: false,
-                       scaleLabel: Chart.defaults.scale.scaleLabel,
                        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: {
-                               minRotation: 0,
-                               maxRotation: 50,
-                               mirror: false,
                                source: 'auto',
-                               padding: 0,
-                               display: true,
-                               callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below,
-                               autoSkip: true,
-                               autoSkipPadding: 0,
-                               labelOffset: 0,
-                               minor: {},
                                major: {
                                        enabled: false
-                               },
-                               lineWidth: 0,
-                               strokeStyle: '',
-                       },
-                       time: {
-                               parser: false,
-                               unit: false,
-                               round: false,
-                               isoWeekday: false,
-                               minUnit: 'millisecond',
-                               displayFormats: {}
+                               }
                        }
                });
-
-               // Is this actually a function
-               expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
        });
 
        it('should correctly determine the unit', function() {
@@ -153,7 +121,7 @@ describe('Time scale tests', function() {
 
                var config;
                beforeEach(function() {
-                       config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
+                       config = Chart.helpers.clone(Chart.defaults.scales.time);
                        config.ticks.source = 'labels';
                        config.time.unit = 'day';
                });
@@ -202,7 +170,7 @@ describe('Time scale tests', function() {
                                unit: 'week',
                                isoWeekday: 3 // Wednesday
                        }
-               }, Chart.scaleService.getScaleDefaults('time'));
+               }, Chart.defaults.scales.time);
 
                var scale = createScale(mockData, config);
                var ticks = getLabels(scale);