## Default Options
-It is common to want to apply a configuration setting to all created bar charts. The global bar chart settings are stored in `Chart.defaults.controllers.bar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+It is common to want to apply a configuration setting to all created bar charts. The global bar chart settings are stored in `Chart.overrides.bar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
## barPercentage vs categoryPercentage
## Default Options
-We can also change the default values for the Bubble chart type. Doing so will give all bubble charts created after this point the new defaults. The default configuration for the bubble chart can be accessed at `Chart.defaults.controllers.bubble`.
+We can also change the default values for the Bubble chart type. Doing so will give all bubble charts created after this point the new defaults. The default configuration for the bubble chart can be accessed at `Chart.overrides.bubble`.
## Data Structure
## Default Options
-We can also change these default values for each Doughnut type that is created, this object is available at `Chart.defaults.controllers.doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.controllers.pie`, with the only difference being `cutout` being set to 0.
+We can also change these default values for each Doughnut type that is created, this object is available at `Chart.overrides.doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.overrides.pie`, with the only difference being `cutout` being set to 0.
## Data Structure
## Default Options
-It is common to want to apply a configuration setting to all created line charts. The global line chart settings are stored in `Chart.defaults.controllers.line`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+It is common to want to apply a configuration setting to all created line charts. The global line chart settings are stored in `Chart.overrides.line`. Changing the global options only affects charts created after the change. Existing charts are not changed.
For example, to configure all line charts with `spanGaps = true` you would do:
```javascript
-Chart.defaults.controllers.line.spanGaps = true;
+Chart.overrides.line.spanGaps = true;
```
## Data Structure
## Default Options
-We can also change these default values for each PolarArea type that is created, this object is available at `Chart.defaults.controllers.polarArea`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+We can also change these default values for each PolarArea type that is created, this object is available at `Chart.overrides.polarArea`. Changing the global options only affects charts created after the change. Existing charts are not changed.
For example, to configure all new polar area charts with `animateScale = false` you would do:
```javascript
-Chart.defaults.controllers.polarArea.animation.animateScale = false;
+Chart.overrides.polarArea.animation.animateScale = false;
```
## Data Structure
## Default Options
-It is common to want to apply a configuration setting to all created radar charts. The global radar chart settings are stored in `Chart.defaults.controllers.radar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
+It is common to want to apply a configuration setting to all created radar charts. The global radar chart settings are stored in `Chart.overrides.radar`. Changing the global options only affects charts created after the change. Existing charts are not changed.
## Data Structure
y: {
from: 0
}
- }
+ }
},
hide: {
animations: {
These keys can be configured in following paths:
* `` - chart options
-* `controllers[type]` - controller type options
-* `controllers[type].datasets` - dataset type options
* `datasets[type]` - dataset type options
+* `overrides[type]` - chart type options
These paths are valid under `defaults` for global confuguration and `options` for instance configuration.
```javascript
// Do not show lines for all datasets by default
-Chart.defaults.controllers.line.showLine = false;
+Chart.defaults.datasets.line.showLine = false;
// This chart would show a line only for the third dataset
var chart = new Chart(ctx, {
### Chart level options
* options
-* defaults.controllers[`config.type`]
+* overrides[`config.type`]
* defaults
### Dataset level options
* dataset
* options.datasets[`dataset.type`]
-* options.controllers[`dataset.type`].datasets
* options
+* overrides[`config.type`].datasets[`dataset.type`]
* defaults.datasets[`dataset.type`]
-* defaults.controllers[`dataset.type`].datasets
* defaults
### Dataset animation options
* dataset.animation
-* options.controllers[`dataset.type`].datasets.animation
+* options.datasets[`dataset.type`].animation
* options.animation
-* defaults.controllers[`dataset.type`].datasets.animation
+* overrides[`config.type`].datasets[`dataset.type`].animation
+* defaults.datasets[`dataset.type`].animation
* defaults.animation
### Dataset element level options
* dataset
* options.datasets[`dataset.type`]
-* options.controllers[`dataset.type`].datasets
-* options.controllers[`dataset.type`].elements[`elementType`]
+* options.datasets[`dataset.type`].elements[`elementType`]
* options.elements[`elementType`]
* options
+* overrides[`config.type`].datasets[`dataset.type`]
+* overrides[`config.type`].datasets[`dataset.type`].elements[`elementType`]
* defaults.datasets[`dataset.type`]
-* defaults.controllers[`dataset.type`].datasets
-* defaults.controllers[`dataset.type`].elements[`elementType`]
+* defaults.datasets[`dataset.type`].elements[`elementType`]
* defaults.elements[`elementType`]
* defaults
### Scale options
* options.scales
-* defaults.controllers[`config.type`].scales
-* defaults.controllers[`dataset.type`].scales
+* overrides[`config.type`].scales
* defaults.scales
+* defaults.scale
### Plugin options
A plugin can provide `additionalOptionScopes` array of paths to additionally look for its options in. For root scope, use empty string: `''`. Most core plugins also take options from root scope.
* options.plugins[`plugin.id`]
-* options.controllers[`config.type`].plugins[`plugin.id`]
* (options.[`...plugin.additionalOptionScopes`])
-* defaults.controllers[`config.type`].plugins[`plugin.id`]
+* overrides[`config.type`].plugins[`plugin.id`]
* defaults.plugins[`plugin.id`]
* (defaults.[`...plugin.additionalOptionScopes`])
#### Defaults
* `global` namespace was removed from `defaults`. So `Chart.defaults.global` is now `Chart.defaults`
-* Dataset controller defaults were relocate to `controllers`. For example `Chart.defaults.line` is now `Chart.defaults.controllers.line`
+* Dataset controller defaults were relocate to `overrides`. For example `Chart.defaults.line` is now `Chart.overrides.line`
* `default` prefix was removed from defaults. For example `Chart.defaults.global.defaultColor` is now `Chart.defaults.color`
* `defaultColor` was split to `color`, `borderColor` and `backgroundColor`
* `defaultFontColor` was renamed to `color`
// Call bubble controller method to draw all the points
super.draw(arguments);
- // Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
+ // Now we can do some custom drawing for this dataset. Here we'll draw a box around the first point in each dataset, using `boxStrokeStyle` dataset option for color
var meta = this.getMeta();
var pt0 = meta.data[0];
var ctx = this.chart.ctx;
ctx.save();
- ctx.strokeStyle = 'red';
+ ctx.strokeStyle = this.options.boxStrokeStyle;
ctx.lineWidth = 1;
ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
}
Custom.id = 'derivedBubble';
- Custom.defaults = Chart.controllers.bubble.defaults;
+ Custom.defaults = {
+ // Custom defaults. Bubble defaults are inherited.
+ boxStrokeStyle: 'red'
+ };
+ // Overrides are only inherited, but not merged if defined
+ // Custom.overrides = Chart.overrides.bubble;
// Stores the controller so that the chart initialization routine can look it up
Chart.register(Custom);
labels: {
generateLabels: function(chart) {
// Get the default label list
- var original = Chart.defaults.controllers.pie.plugins.legend.labels.generateLabels;
+ var original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
var labels = original.call(this, chart);
// Build an array of colors used in the datasets of the chart
datasetElementType: false,
dataElementType: 'bar',
+ categoryPercentage: 0.8,
+ barPercentage: 0.9,
+
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['x', 'y', 'base', 'width', 'height']
+ }
+ }
+};
+
+/**
+ * @type {any}
+ */
+BarController.overrides = {
interaction: {
mode: 'index'
},
hover: {},
- datasets: {
- categoryPercentage: 0.8,
- barPercentage: 0.9,
- animations: {
- numbers: {
- type: 'number',
- properties: ['x', 'y', 'base', 'width', 'height']
- }
- }
- },
-
scales: {
_index_: {
type: 'category',
BubbleController.defaults = {
datasetElementType: false,
dataElementType: 'point',
+
animations: {
numbers: {
type: 'number',
properties: ['x', 'y', 'borderWidth', 'radius']
}
- },
+ }
+};
+
+/**
+ * @type {any}
+ */
+BubbleController.overrides = {
scales: {
x: {
type: 'linear'
properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth']
},
},
- aspectRatio: 1,
-
- datasets: {
- // The percentage of the chart that we cut out of the middle.
- cutout: '50%',
+ // The percentage of the chart that we cut out of the middle.
+ cutout: '50%',
- // The rotation of the chart, where the first data arc begins.
- rotation: 0,
+ // The rotation of the chart, where the first data arc begins.
+ rotation: 0,
- // The total circumference of the chart.
- circumference: 360,
+ // The total circumference of the chart.
+ circumference: 360,
- // The outr radius of the chart
- radius: '100%'
- },
+ // The outr radius of the chart
+ radius: '100%',
indexAxis: 'r',
+};
+
+/**
+ * @type {any}
+ */
+DoughnutController.overrides = {
+ aspectRatio: 1,
// Need to override these to give a nice default
plugins: {
datasetElementType: 'line',
dataElementType: 'point',
- datasets: {
- showLine: true,
- spanGaps: false,
- },
+ showLine: true,
+ spanGaps: false,
+};
+/**
+ * @type {any}
+ */
+LineController.overrides = {
interaction: {
mode: 'index'
},
* @type {any}
*/
PieController.defaults = {
- datasets: {
- // The percentage of the chart that we cut out of the middle.
- cutout: 0,
+ // The percentage of the chart that we cut out of the middle.
+ cutout: 0,
- // The rotation of the chart, where the first data arc begins.
- rotation: 0,
+ // The rotation of the chart, where the first data arc begins.
+ rotation: 0,
- // The total circumference of the chart.
- circumference: 360,
+ // The total circumference of the chart.
+ circumference: 360,
- // The outr radius of the chart
- radius: '100%'
- }
+ // The outr radius of the chart
+ radius: '100%'
};
properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
},
},
- aspectRatio: 1,
indexAxis: 'r',
- scales: {
- r: {
- type: 'radialLinear',
- angleLines: {
- display: false
- },
- beginAtZero: true,
- gridLines: {
- circular: true
- },
- pointLabels: {
- display: false
- }
- }
- },
-
startAngle: 0,
+};
+
+/**
+ * @type {any}
+ */
+PolarAreaController.overrides = {
+ aspectRatio: 1,
+
plugins: {
legend: {
labels: {
}
}
}
- }
+ },
+ scales: {
+ r: {
+ type: 'radialLinear',
+ angleLines: {
+ display: false
+ },
+ beginAtZero: true,
+ gridLines: {
+ circular: true
+ },
+ pointLabels: {
+ display: false
+ }
+ }
+ }
};
RadarController.defaults = {
datasetElementType: 'line',
dataElementType: 'point',
- aspectRatio: 1,
- datasets: {
- showLine: true,
- },
+ indexAxis: 'r',
+ showLine: true,
elements: {
line: {
fill: 'start'
}
},
- indexAxis: 'r',
+};
+
+/**
+ * @type {any}
+ */
+RadarController.overrides = {
+ aspectRatio: 1,
+
scales: {
r: {
type: 'radialLinear',
* @type {any}
*/
ScatterController.defaults = {
- scales: {
- x: {
- type: 'linear'
- },
- y: {
- type: 'linear'
- }
- },
+ showLine: false,
+ fill: false
+};
- datasets: {
- showLine: false,
- fill: false
- },
+/**
+ * @type {any}
+ */
+ScatterController.overrides = {
interaction: {
mode: 'point'
}
}
}
+ },
+
+ scales: {
+ x: {
+ type: 'linear'
+ },
+ y: {
+ type: 'linear'
+ }
}
};
-import defaults from './core.defaults';
+import defaults, {overrides, descriptors} from './core.defaults';
import {mergeIf, resolveObjectKey, isArray, isFunction, valueOrDefault, isObject} from '../helpers/helpers.core';
import {_attachContext, _createResolver, _descriptors} from '../helpers/helpers.config';
export function getIndexAxis(type, options) {
- const typeDefaults = defaults.controllers[type] || {};
- const datasetDefaults = typeDefaults.datasets || {};
- const datasetOptions = options.datasets || {};
- const typeOptions = datasetOptions[type] || {};
- return typeOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
+ const datasetDefaults = defaults.datasets[type] || {};
+ const datasetOptions = (options.datasets || {})[type] || {};
+ return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
}
function getAxisFromDefaultScaleID(id, indexAxis) {
}
function mergeScaleConfig(config, options) {
- const chartDefaults = defaults.controllers[config.type] || {scales: {}};
+ const chartDefaults = overrides[config.type] || {scales: {}};
const configScales = options.scales || {};
const chartIndexAxis = getIndexAxis(config.type, options);
const firstIDs = Object.create(null);
config.data.datasets.forEach(dataset => {
const type = dataset.type || config.type;
const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
- const datasetDefaults = defaults.controllers[type] || {};
+ const datasetDefaults = overrides[type] || {};
const defaultScaleOptions = datasetDefaults.scales || {};
Object.keys(defaultScaleOptions).forEach(defaultID => {
const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
return cachedKeys(datasetType,
() => [
`datasets.${datasetType}`,
- `controllers.${datasetType}`,
- `controllers.${datasetType}.datasets`,
''
]);
}
return cachedKeys(`${datasetType}.transition.${transition}`,
() => [
`datasets.${datasetType}.transitions.${transition}`,
- `controllers.${datasetType}.transitions.${transition}`,
- `controllers.${datasetType}.datasets.transitions.${transition}`,
`transitions.${transition}`,
+ // The following are used for looking up the `animations` and `animation` keys
`datasets.${datasetType}`,
- `controllers.${datasetType}`,
- `controllers.${datasetType}.datasets`,
''
]);
}
datasetElementScopeKeys(datasetType, elementType) {
return cachedKeys(`${datasetType}-${elementType}`,
() => [
+ `datasets.${datasetType}.elements.${elementType}`,
`datasets.${datasetType}`,
- `controllers.${datasetType}.datasets`,
- `controllers.${datasetType}.elements.${elementType}`,
`elements.${elementType}`,
''
]);
const type = this.type;
return cachedKeys(`${type}-plugin-${id}`,
() => [
- `controllers.${type}.plugins.${id}`,
`plugins.${id}`,
...plugin.additionalOptionScopes || [],
]);
* @param {boolean} [resetCache] - reset the cache for this mainScope
*/
getOptionScopes(mainScope, scopeKeys, resetCache) {
- let cache = this._scopeCache.get(mainScope);
+ const {_scopeCache, options, type} = this;
+ let cache = _scopeCache.get(mainScope);
if (!cache || resetCache) {
cache = new Map();
- this._scopeCache.set(mainScope, cache);
+ _scopeCache.set(mainScope, cache);
}
const cached = cache.get(scopeKeys);
if (cached) {
scopes.add(mainScope);
scopeKeys.forEach(key => addIfFound(scopes, mainScope, key));
}
- scopeKeys.forEach(key => addIfFound(scopes, this.options, key));
+ scopeKeys.forEach(key => addIfFound(scopes, options, key));
+ scopeKeys.forEach(key => addIfFound(scopes, overrides[type] || {}, key));
scopeKeys.forEach(key => addIfFound(scopes, defaults, key));
- scopeKeys.forEach(key => addIfFound(scopes, defaults.descriptors, key));
+ scopeKeys.forEach(key => addIfFound(scopes, descriptors, key));
const array = [...scopes];
if (keysCached.has(scopeKeys)) {
* @return {object[]}
*/
chartOptionScopes() {
- const controllerDefaults = defaults.controllers[this.type] || {};
+ const {options, type} = this;
+
return [
- this.options,
- controllerDefaults,
- controllerDefaults.datasets || {},
- {type: this.type},
+ options,
+ overrides[type] || {},
+ defaults.datasets[type] || {}, // https://github.com/chartjs/Chart.js/issues/8531
+ {type},
defaults,
- defaults.descriptors
+ descriptors
];
}
import animator from './core.animator';
-import defaults from './core.defaults';
+import defaults, {overrides} from './core.defaults';
import Interaction from './core.interaction';
import layouts from './core.layouts';
import {BasicPlatform, DomPlatform} from '../platform';
meta.controller.updateIndex(i);
meta.controller.linkScales();
} else {
- const controllerDefaults = defaults.controllers[type];
const ControllerClass = registry.getController(type);
+ const {datasetElementType, dataElementType} = defaults.datasets[type];
Object.assign(ControllerClass.prototype, {
- dataElementType: registry.getElement(controllerDefaults.dataElementType),
- datasetElementType: controllerDefaults.datasetElementType && registry.getElement(controllerDefaults.datasetElementType)
+ dataElementType: registry.getElement(dataElementType),
+ datasetElementType: datasetElementType && registry.getElement(datasetElementType)
});
meta.controller = new ControllerClass(me, i);
newControllers.push(meta.controller);
enumerable,
value: instances
},
+ overrides: {
+ enumerable,
+ value: overrides
+ },
registry: {
enumerable,
value: registry
import {getHoverColor} from '../helpers/helpers.color';
import {isObject, merge, valueOrDefault} from '../helpers/helpers.core';
-const privateSymbol = Symbol('private');
+export const overrides = Object.create(null);
+export const descriptors = Object.create(null);
/**
* @param {object} node
return node;
}
+function set(root, scope, values) {
+ if (typeof scope === 'string') {
+ return merge(getScope(root, scope), values);
+ }
+ return merge(getScope(root, ''), scope);
+}
+
/**
* Please use the module's default export which provides a singleton instance
* Note: class is exported for typedoc
*/
export class Defaults {
- constructor(descriptors) {
+ constructor(_descriptors) {
this.animation = undefined;
this.backgroundColor = 'rgba(0,0,0,0.1)';
this.borderColor = 'rgba(0,0,0,0.1)';
this.color = '#666';
- this.controllers = {};
+ this.datasets = {};
this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio();
this.elements = {};
this.events = [
this.scales = {};
this.showLine = true;
- Object.defineProperty(this, privateSymbol, {
- value: Object.create(null),
- writable: false
- });
-
- this.describe(descriptors);
+ this.describe(_descriptors);
}
/**
* @param {object} [values]
*/
set(scope, values) {
- if (typeof scope === 'string') {
- return merge(getScope(this, scope), values);
- }
- return merge(getScope(this, ''), scope);
+ return set(this, scope, values);
}
/**
* @param {object} [values]
*/
describe(scope, values) {
- const root = this[privateSymbol];
- if (typeof scope === 'string') {
- return merge(getScope(root, scope), values);
- }
- return merge(getScope(root, ''), scope);
+ return set(descriptors, scope, values);
}
- get descriptors() {
- return this[privateSymbol];
+ override(scope, values) {
+ return set(overrides, scope, values);
}
/**
*/
export class Registry {
constructor() {
- this.controllers = new TypedRegistry(DatasetController, 'controllers');
+ this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
this.elements = new TypedRegistry(Element, 'elements');
this.plugins = new TypedRegistry(Object, 'plugins');
this.scales = new TypedRegistry(Scale, 'scales');
-import defaults from './core.defaults';
+import {merge} from '../helpers';
+import defaults, {overrides} from './core.defaults';
/**
- * @typedef {{id: string, defaults: any, defaultRoutes: any}} IChartComponent
+ * @typedef {{id: string, defaults: any, overrides?: any, defaultRoutes: any}} IChartComponent
*/
export default class TypedRegistry {
- constructor(type, scope) {
+ constructor(type, scope, override) {
this.type = type;
this.scope = scope;
+ this.override = override;
this.items = Object.create(null);
}
* @returns {string} The scope where items defaults were registered to.
*/
register(item) {
+ const me = this;
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);
+ parentScope = me.register(proto);
}
- const items = this.items;
+ const items = me.items;
const id = item.id;
- const baseScope = this.scope;
- const scope = baseScope ? baseScope + '.' + id : id;
+ const scope = me.scope + '.' + id;
if (!id) {
throw new Error('class does not have id: ' + item);
items[id] = item;
registerDefaults(item, scope, parentScope);
+ if (me.override) {
+ defaults.override(item.id, item.overrides);
+ }
return scope;
}
if (scope && id in defaults[scope]) {
delete defaults[scope][id];
+ if (this.override) {
+ delete overrides[id];
+ }
}
}
}
function registerDefaults(item, scope, parentScope) {
// Inherit the parent's defaults and keep existing defaults
- const itemDefaults = Object.assign(
- Object.create(null),
- parentScope && defaults.get(parentScope),
- item.defaults,
- defaults.get(scope)
- );
+ const itemDefaults = merge(Object.create(null), [
+ parentScope ? defaults.get(parentScope) : {},
+ defaults.get(scope),
+ item.defaults
+ ]);
defaults.set(scope, itemDefaults);
var chart = window.acquireChart(this.config);
var meta = chart.getDatasetMeta(0);
var xScale = chart.scales[meta.xAxisID];
- var options = Chart.defaults.controllers.bar.datasets;
+ var options = Chart.defaults.datasets.bar;
var categoryPercentage = options.categoryPercentage;
var barPercentage = options.barPercentage;
expected = barThickness;
} else {
var scale = chart.scales.x;
- var options = Chart.defaults.controllers.bar.datasets;
+ var options = Chart.defaults.datasets.bar;
var categoryPercentage = options.categoryPercentage;
var barPercentage = options.barPercentage;
var tickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
describe('dataset global defaults', function() {
beforeEach(function() {
- this._defaults = Chart.helpers.clone(Chart.defaults.controllers.line.datasets);
+ this._defaults = Chart.helpers.clone(Chart.defaults.datasets.line);
});
afterEach(function() {
- Chart.defaults.controllers.line.datasets = this._defaults;
+ Chart.defaults.datasets.line = this._defaults;
delete this._defaults;
});
it('should utilize the dataset global default options', function() {
- Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
-
- Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
+ Chart.helpers.merge(Chart.defaults.datasets.line, {
spanGaps: true,
tension: 0.231,
backgroundColor: '#add',
});
it('should be overriden by user-supplied values', function() {
- Chart.defaults.controllers.line.datasets = Chart.defaults.controllers.line.datasets || {};
-
- Chart.helpers.merge(Chart.defaults.controllers.line.datasets, {
+ Chart.helpers.merge(Chart.defaults.datasets.line, {
spanGaps: true,
tension: 0.231
});
describe('Chart', function() {
+ const overrides = Chart.overrides;
+
// https://github.com/chartjs/Chart.js/issues/2481
// See global.deprecations.tests.js for backward compatibility
it('should be defined and prototype of chart instances', function() {
it('should initialize config with default interaction options', function() {
var callback = function() {};
var defaults = Chart.defaults;
- var defaultMode = defaults.controllers.line.interaction.mode;
+ var defaultMode = overrides.line.interaction.mode;
defaults.hover.onHover = callback;
- defaults.controllers.line.spanGaps = true;
- defaults.controllers.line.interaction.mode = 'test';
+ overrides.line.interaction.mode = 'test';
var chart = acquireChart({
type: 'line'
var options = chart.options;
expect(options.font.size).toBe(defaults.font.size);
- expect(options.showLine).toBe(defaults.controllers.line.datasets.showLine);
- expect(options.spanGaps).toBe(true);
expect(options.hover.onHover).toBe(callback);
expect(options.hover.mode).toBe('test');
defaults.hover.onHover = null;
- defaults.controllers.line.spanGaps = false;
- defaults.controllers.line.interaction.mode = defaultMode;
+ overrides.line.interaction.mode = defaultMode;
});
it('should initialize config with default hover options', function() {
var defaults = Chart.defaults;
defaults.hover.onHover = callback;
- defaults.controllers.line.spanGaps = true;
- defaults.controllers.line.hover.mode = 'test';
+ overrides.line.hover.mode = 'test';
var chart = acquireChart({
type: 'line'
var options = chart.options;
expect(options.font.size).toBe(defaults.font.size);
- expect(options.showLine).toBe(defaults.controllers.line.datasets.showLine);
- expect(options.spanGaps).toBe(true);
expect(options.hover.onHover).toBe(callback);
expect(options.hover.mode).toBe('test');
defaults.hover.onHover = null;
- defaults.controllers.line.spanGaps = false;
- delete defaults.controllers.line.hover.mode;
+ delete overrides.line.hover.mode;
});
it('should override default options', function() {
var callback = function() {};
var defaults = Chart.defaults;
+ var defaultSpanGaps = defaults.datasets.line.spanGaps;
defaults.hover.onHover = callback;
- defaults.controllers.line.hover.mode = 'x-axis';
- defaults.controllers.line.spanGaps = true;
+ overrides.line.hover.mode = 'x-axis';
+ defaults.datasets.line.spanGaps = true;
var chart = acquireChart({
type: 'line',
expect(options.plugins.title.position).toBe('bottom');
defaults.hover.onHover = null;
- delete defaults.controllers.line.hover.mode;
- defaults.controllers.line.spanGaps = false;
+ delete overrides.line.hover.mode;
+ defaults.datasets.line.spanGaps = defaultSpanGaps;
});
it('should initialize config with default dataset options', function() {
- var defaults = Chart.defaults.controllers.pie.datasets;
+ var defaults = Chart.defaults.datasets.pie;
var chart = acquireChart({
type: 'pie'
expect(chart.scales.x.options._jasmineCheck).toBeDefined();
expect(chart.scales.y.options._jasmineCheck).toBeDefined();
- expect(Chart.defaults.controllers.line._jasmineCheck).not.toBeDefined();
+ expect(Chart.overrides.line._jasmineCheck).not.toBeDefined();
expect(Chart.defaults._jasmineCheck).not.toBeDefined();
expect(Chart.defaults.scales.linear._jasmineCheck).not.toBeDefined();
expect(Chart.defaults.scales.category._jasmineCheck).not.toBeDefined();
CustomController.defaults = {
foo: 'bar'
};
+ CustomController.overrides = {
+ bar: 'foo'
+ };
Chart.register(CustomController);
expect(Chart.registry.getController('custom')).toEqual(CustomController);
- expect(Chart.defaults.controllers.custom).toEqual(CustomController.defaults);
+ expect(Chart.defaults.datasets.custom).toEqual(CustomController.defaults);
+ expect(Chart.overrides.custom).toEqual(CustomController.overrides);
Chart.unregister(CustomController);
expect(function() {
Chart.registry.getController('custom');
}).toThrow(new Error('"custom" is not a registered controller.'));
- expect(Chart.defaults.controllers.custom).not.toBeDefined();
+ expect(Chart.overrides.custom).not.toBeDefined();
+ expect(Chart.defaults.datasets.custom).not.toBeDefined();
});
it('should handle an ES6 scale extension', function() {
expect(function() {
Chart.registry.getScale('es6Scale');
}).toThrow(new Error('"es6Scale" is not a registered scale.'));
- expect(Chart.defaults.controllers.custom).not.toBeDefined();
+ expect(Chart.defaults.scales.es6Scale).not.toBeDefined();
});
it('should handle an ES6 element extension', function() {
Chart.registry.addControllers(customExtension);
expect(Chart.registry.getController('custom')).toEqual(customExtension);
- expect(Chart.defaults.controllers.custom).toEqual(customExtension.defaults);
+ expect(Chart.defaults.datasets.custom).toEqual(customExtension.defaults);
Chart.registry.removeControllers(customExtension);
expect(function() {
Chart.registry.getController('custom');
}).toThrow(new Error('"custom" is not a registered controller.'));
- expect(Chart.defaults.controllers.custom).not.toBeDefined();
+ expect(Chart.defaults.datasets.custom).not.toBeDefined();
});
it('as scale', function() {
});
it('should preserve existing defaults', function() {
- Chart.defaults.controllers.test = {test1: true};
+ Chart.defaults.datasets.test = {test1: true, test3: false};
+ Chart.overrides.test = {testA: true, testC: false};
class testController extends Chart.DatasetController {}
testController.id = 'test';
testController.defaults = {test1: false, test2: true};
+ testController.overrides = {testA: false, testB: true};
Chart.register(testController);
- expect(Chart.defaults.controllers.test).toEqual({test1: true, test2: true});
+ expect(Chart.defaults.datasets.test).toEqual({test1: false, test2: true, test3: false});
+ expect(Chart.overrides.test).toEqual({testA: false, testB: true, testC: false});
Chart.unregister(testController);
- expect(Chart.defaults.controllers.test).not.toBeDefined();
+ expect(Chart.defaults.datasets.test).not.toBeDefined();
+ expect(Chart.overrides.test).not.toBeDefined();
});
describe('should handle multiple items', function() {
describe('Default Configs', function() {
describe('Bubble Chart', function() {
it('should return correct tooltip strings', function() {
- var config = Chart.defaults.controllers.bubble;
var chart = window.acquireChart({
type: 'bubble',
data: {
}]
}]
},
- options: config
});
// fake out the tooltip hover and force the tooltip to update
describe('Doughnut Chart', function() {
it('should return correct tooltip strings', function() {
- var config = Chart.defaults.controllers.doughnut;
var chart = window.acquireChart({
type: 'doughnut',
data: {
data: [10, 20, 30],
}]
},
- options: config
});
// fake out the tooltip hover and force the tooltip to update
});
it('should return correct tooltip string for a multiline label', function() {
- var config = Chart.defaults.controllers.doughnut;
var chart = window.acquireChart({
type: 'doughnut',
data: {
data: [10, 20, 30],
}]
},
- options: config
});
// fake out the tooltip hover and force the tooltip to update
});
it('should return correct legend label objects', function() {
- var config = Chart.defaults.controllers.doughnut;
var chart = window.acquireChart({
type: 'doughnut',
data: {
borderColor: '#000'
}]
},
- options: config
});
var expected = [{
});
it('should hide the correct arc when a legend item is clicked', function() {
- var config = Chart.defaults.controllers.doughnut;
+ var config = Chart.overrides.doughnut;
var chart = window.acquireChart({
type: 'doughnut',
data: {
borderColor: '#000'
}]
},
- options: config
});
spyOn(chart, 'update').and.callThrough();
describe('Polar Area Chart', function() {
it('should return correct tooltip strings', function() {
- var config = Chart.defaults.controllers.polarArea;
var chart = window.acquireChart({
type: 'polarArea',
data: {
data: [10, 20, 30],
}]
},
- options: config
});
// fake out the tooltip hover and force the tooltip to update
});
it('should return correct legend label objects', function() {
- var config = Chart.defaults.controllers.polarArea;
var chart = window.acquireChart({
type: 'polarArea',
data: {
borderColor: '#000'
}]
},
- options: config
});
var expected = [{
});
it('should hide the correct arc when a legend item is clicked', function() {
- var config = Chart.defaults.controllers.polarArea;
+ var config = Chart.overrides.polarArea;
var chart = window.acquireChart({
type: 'polarArea',
data: {
borderColor: '#000'
}]
},
- options: config
});
spyOn(chart, 'update').and.callThrough();
});
it('should use default "chart" aspect ratio for render and display sizes', function() {
- var ratio = Chart.defaults.controllers.doughnut.aspectRatio;
- Chart.defaults.controllers.doughnut.aspectRatio = 1;
+ var ratio = Chart.overrides.doughnut.aspectRatio;
+ Chart.overrides.doughnut.aspectRatio = 1;
var chart = acquireChart({
type: 'doughnut',
}
});
- Chart.defaults.controllers.doughnut.aspectRatio = ratio;
+ Chart.overrides.doughnut.aspectRatio = ratio;
expect(chart).toBeChartOfSize({
dw: 425, dh: 425,
export interface BarControllerDatasetOptions
extends ControllerDatasetOptions,
ScriptableAndArrayOptions<BarOptions, ScriptableContext<'bar'>>,
- ScriptableAndArrayOptions<CommonHoverOptions, ScriptableContext<'bar'>> {
+ ScriptableAndArrayOptions<CommonHoverOptions, ScriptableContext<'bar'>>,
+ AnimationOptions<'bar'> {
/**
* The ID of the x axis to plot this dataset on.
*/
ScriptableAndArrayOptions<PointPrefixedOptions, ScriptableContext<'line'>>,
ScriptableAndArrayOptions<PointPrefixedHoverOptions, ScriptableContext<'line'>>,
ScriptableOptions<LineOptions, ScriptableContext<'line'>>,
- ScriptableOptions<LineHoverOptions, ScriptableContext<'line'>> {
+ ScriptableOptions<LineHoverOptions, ScriptableContext<'line'>>,
+ AnimationOptions<'line'> {
/**
* The ID of the x axis to plot this dataset on.
*/
export interface DoughnutControllerDatasetOptions
extends ControllerDatasetOptions,
ScriptableAndArrayOptions<ArcOptions, ScriptableContext<'doughnut'>>,
- ScriptableAndArrayOptions<ArcHoverOptions, ScriptableContext<'doughnut'>> {
+ ScriptableAndArrayOptions<ArcHoverOptions, ScriptableContext<'doughnut'>>,
+ AnimationOptions<'doughnut'> {
/**
* Sweep to allow arcs to cover.
ScriptableOptions<PointPrefixedOptions, ScriptableContext<'radar'>>,
ScriptableOptions<PointPrefixedHoverOptions, ScriptableContext<'radar'>>,
ScriptableOptions<LineOptions, ScriptableContext<'radar'>>,
- ScriptableOptions<LineHoverOptions, ScriptableContext<'radar'>> {
- /**
+ ScriptableOptions<LineHoverOptions, ScriptableContext<'radar'>>,
+ AnimationOptions<'radar'> {
+ /**
* The ID of the x axis to plot this dataset on.
*/
xAxisID: string;
notifyPlugins(hook: string, args?: AnyObject): boolean | void;
static readonly defaults: Defaults;
+ static readonly overrides: Overrides;
static readonly version: string;
static readonly instances: { [key: string]: Chart };
static readonly registry: Registry;
}
export interface Defaults extends CoreChartOptions<ChartType>, ElementChartOptions, PluginChartOptions<ChartType> {
- controllers: {
- [key in ChartType]: DeepPartial<
- CoreChartOptions<key> &
- ElementChartOptions &
- PluginChartOptions<key> &
- DatasetChartOptions<key>[key] &
- ScaleChartOptions<key> &
- ChartTypeRegistry[key]['chartOptions']
- >;
- };
scale: ScaleOptionsByType;
scales: {
route(scope: string, name: string, targetScope: string, targetName: string): void;
}
+export type Overrides = {
+ [key in ChartType]: DeepPartial<
+ CoreChartOptions<key> &
+ ElementChartOptions &
+ PluginChartOptions<key> &
+ DatasetChartOptions<ChartType> &
+ ScaleChartOptions<key> &
+ ChartTypeRegistry[key]['chartOptions']
+ >;
+}
+
export const defaults: Defaults;
export interface InteractionOptions {
axis?: string;
export interface CoreChartOptions<TType extends ChartType> extends ParsingOptions, AnimationOptions<TType> {
- datasets: AnimationOptions<TType>;
+ datasets: {
+ [key in ChartType]: ChartTypeRegistry[key]['datasetOptions']
+ }
/**
* The base axis of the chart. 'x' for vertical charts and 'y' for horizontal charts.
* The number of milliseconds an animation takes.
* @default 1000
*/
- duration: Scriptable<number, ScriptableContext<TType>>;
+ duration?: Scriptable<number, ScriptableContext<TType>>;
/**
* Easing function to use
* @default 'easeOutQuart'
*/
- easing: Scriptable<EasingFunction, ScriptableContext<TType>>;
-
- /**
- * Running animation count + FPS display in upper left corner of the chart.
- * @default false
- */
- debug: Scriptable<boolean, ScriptableContext<TType>>;
+ easing?: Scriptable<EasingFunction, ScriptableContext<TType>>;
/**
* Delay before starting the animations.
* @default 0
*/
- delay: Scriptable<number, ScriptableContext<TType>>;
+ delay?: Scriptable<number, ScriptableContext<TType>>;
/**
* If set to true, the animations loop endlessly.
* @default false
*/
- loop: Scriptable<boolean, ScriptableContext<TType>>;
+ loop?: Scriptable<boolean, ScriptableContext<TType>>;
}
export type AnimationsSpec<TType extends ChartType> = {
/**
* Callback called on each step of an animation.
*/
- onProgress: (this: Chart, event: AnimationEvent) => void;
+ onProgress?: (this: Chart, event: AnimationEvent) => void;
/**
* Callback called when all animations are completed.
*/
- onComplete: (this: Chart, event: AnimationEvent) => void;
+ onComplete?: (this: Chart, event: AnimationEvent) => void;
};
animations: AnimationsSpec<TType>;
transitions: TransitionsSpec<TType>;
--- /dev/null
+import { Chart } from '../index.esm';
+
+Chart.defaults.scales.time.time.minUnit = 'day';
+
+Chart.defaults.plugins.title.display = false;
+
+Chart.defaults.datasets.bar.backgroundColor = 'red';
+
+Chart.defaults.animation = { duration: 500 };
--- /dev/null
+import { Chart } from '../index.esm';
+
+export const chart = new Chart('test', {
+ type: 'bar',
+ data: {
+ labels: ['a'],
+ datasets: [{
+ data: [1],
+ }, {
+ type: 'line',
+ data: [{ x: 1, y: 1 }]
+ }]
+ },
+ options: {
+ animation: {
+ duration: 500
+ },
+ backgroundColor: 'red',
+ datasets: {
+ line: {
+ animation: {
+ duration: 600
+ },
+ backgroundColor: 'blue',
+ }
+ },
+ elements: {
+ point: {
+ backgroundColor: 'red'
+ }
+ }
+ }
+});
--- /dev/null
+import { Chart } from '../index.esm';
+
+Chart.overrides.bar.scales.x.type = 'time';
+
+Chart.overrides.bar.plugins.title.display = false;
+
+Chart.overrides.line.datasets.bar.backgroundColor = 'red';
+
+Chart.overrides.line.animation = false;
+Chart.overrides.line.datasets.bar.animation = { duration: 100 };
import { Chart } from '../../../index.esm';
-Chart.defaults.controllers.bubble.plugins.tooltip.callbacks.label = (item) => {
+Chart.overrides.bubble.plugins.tooltip.callbacks.label = (item) => {
const { x, y, _custom: r } = item.parsed;
return `${item.label}: (${x}, ${y}, ${r})`;
};