| Name | Type | Default | Description
| ---- | ---- | ------- | -----------
| `radius` | `number` | `3` | Point radius.
-| [`pointStyle`](#point-styles) | <code>string|Image</code> | `'circle'` | Point style.
+| [`pointStyle`](#point-styles) | `string`\|`Image` | `'circle'` | Point style.
| `rotation` | `number` | `0` | Point rotation (in degrees).
-| `backgroundColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Point fill color.
+| `backgroundColor` | `Color` | `Chart.defaults.color` | Point fill color.
| `borderWidth` | `number` | `1` | Point stroke width.
-| `borderColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Point stroke color.
+| `borderColor` | `Color` | `Chart.defaults.color` | Point stroke color.
| `hitRadius` | `number` | `1` | Extra radius added to point radius for hit detection.
| `hoverRadius` | `number` | `4` | Point radius when hovered.
| `hoverBorderWidth` | `number` | `1` | Stroke width when hovered.
| Name | Type | Default | Description
| ---- | ---- | ------- | -----------
| `tension` | `number` | `0.4` | Bézier curve tension (`0` for no Bézier curves).
-| `backgroundColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Line fill color.
+| `backgroundColor` | `Color` | `Chart.defaults.color` | Line fill color.
| `borderWidth` | `number` | `3` | Line stroke width.
-| `borderColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Line stroke color.
+| `borderColor` | `Color` | `Chart.defaults.color` | Line stroke color.
| `borderCapStyle` | `string` | `'butt'` | Line cap style. See [MDN](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap).
| `borderDash` | `number[]` | `[]` | Line dash. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash).
| `borderDashOffset` | `number` | `0.0` | Line dash offset. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset).
| `borderJoinStyle` | `string` | `'miter'` | Line join style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin).
| `capBezierPoints` | `boolean` | `true` | `true` to keep Bézier control inside the chart, `false` for no restriction.
| `cubicInterpolationMode` | `string` | `'default'` | Interpolation mode to apply. [See more...](../charts/line.md#cubicinterpolationmode)
-| `fill` | <code>boolean|string</code> | `true` | How to fill the area under the line. See [area charts](../charts/area.md#filling-modes).
+| `fill` | `boolean`\|`string` | `true` | How to fill the area under the line. See [area charts](../charts/area.md#filling-modes).
| `stepped` | `boolean` | `false` | `true` to show the line as a stepped line (`tension` will be ignored).
## Rectangle Configuration
| Name | Type | Default | Description
| ---- | ---- | ------- | -----------
-| `backgroundColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Bar fill color.
+| `backgroundColor` | `Color` | `Chart.defaults.color` | Bar fill color.
| `borderWidth` | `number` | `0` | Bar stroke width.
-| `borderColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Bar stroke color.
+| `borderColor` | `Color` | `Chart.defaults.color` | Bar stroke color.
| `borderSkipped` | `string` | `'bottom'` | Skipped (excluded) border: `'bottom'`, `'left'`, `'top'` or `'right'`.
## Arc Configuration
| Name | Type | Default | Description
| ---- | ---- | ------- | -----------
| `angle` - for polar only | `number` | `circumference / (arc count)` | Arc angle to cover.
-| `backgroundColor` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Arc fill color.
+| `backgroundColor` | `Color` | `Chart.defaults.color` | Arc fill color.
| `borderAlign` | `string` | `'center'` | Arc stroke alignment.
| `borderColor` | `Color` | `'#fff'` | Arc stroke color.
| `borderWidth`| `number` | `2` | Arc stroke width.
-import {merge} from '../helpers/helpers.core';
+import {merge, isArray, valueOrDefault} from '../helpers/helpers.core';
+
+/**
+ * @param {object} node
+ * @param {string} key
+ * @return {object}
+ */
+function getScope(node, key) {
+ if (!key) {
+ return node;
+ }
+ const keys = key.split('.');
+ for (let i = 0, n = keys.length; i < n; ++i) {
+ const k = keys[i];
+ node = node[k] || (node[k] = {});
+ }
+ return node;
+}
/**
* Please use the module's default export which provides a singleton instance
+ * Note: class is exported for typedoc
*/
export class Defaults {
constructor() {
this.title = undefined;
this.tooltips = undefined;
this.doughnut = undefined;
+ this._routes = {};
}
/**
* @param {string} scope
* @param {*} values
*/
set(scope, values) {
- return merge(this[scope] || (this[scope] = {}), values);
+ return merge(getScope(this, scope), values);
+ }
+
+ /**
+ * 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:
+ *
+ * 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.
+ */
+ route(scope, names, targetScope, targetNames) {
+ 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
+ },
+ // 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;
+ }
+ }
+ });
+ });
}
}
import {_angleBetween, getAngleFromPoint} from '../helpers/helpers.math';
const TAU = Math.PI * 2;
-defaults.set('elements', {
- arc: {
- backgroundColor: defaults.color,
- borderAlign: 'center',
- borderColor: '#fff',
- borderWidth: 2
- }
+const scope = 'elements.arc';
+defaults.set(scope, {
+ borderAlign: 'center',
+ borderColor: '#fff',
+ borderWidth: 2
});
+defaults.route(scope, ['backgroundColor'], '', ['color']);
+
function clipArc(ctx, model) {
const {startAngle, endAngle, pixelMargin, x, y} = model;
let angleMargin = pixelMargin / model.outerRadius;
* @typedef { import("./element.point").default } Point
*/
-const defaultColor = defaults.color;
-
-defaults.set('elements', {
- line: {
- backgroundColor: defaultColor,
- borderCapStyle: 'butt',
- borderColor: defaultColor,
- borderDash: [],
- borderDashOffset: 0,
- borderJoinStyle: 'miter',
- borderWidth: 3,
- capBezierPoints: true,
- fill: true,
- tension: 0.4
- }
+const scope = 'elements.line';
+defaults.set(scope, {
+ borderCapStyle: 'butt',
+ borderDash: [],
+ borderDashOffset: 0,
+ borderJoinStyle: 'miter',
+ borderWidth: 3,
+ capBezierPoints: true,
+ fill: true,
+ tension: 0.4
});
+defaults.route(scope, ['backgroundColor', 'borderColor'], '', 'color');
+
function setStyle(ctx, vm) {
ctx.lineCap = vm.borderCapStyle;
ctx.setLineDash(vm.borderDash);
import Element from '../core/core.element';
import {_isPointInArea, drawPoint} from '../helpers/helpers.canvas';
-const defaultColor = defaults.color;
-
-defaults.set('elements', {
- point: {
- backgroundColor: defaultColor,
- borderColor: defaultColor,
- borderWidth: 1,
- hitRadius: 1,
- hoverBorderWidth: 1,
- hoverRadius: 4,
- pointStyle: 'circle',
- radius: 3
- }
+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 {
constructor(cfg) {
import Element from '../core/core.element';
import {isObject} from '../helpers/helpers.core';
-const defaultColor = defaults.color;
-
-defaults.set('elements', {
- rectangle: {
- backgroundColor: defaultColor,
- borderColor: defaultColor,
- borderSkipped: 'bottom',
- borderWidth: 0
- }
+const scope = 'elements.rectangle';
+defaults.set(scope, {
+ borderSkipped: 'bottom',
+ 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
expect(data1[hook]).toBe(Array.prototype[hook]);
});
});
+
+ it('should resolve data element options to the default color', function() {
+ var data0 = [0, 1, 2, 3, 4, 5];
+ var oldColor = Chart.defaults.color;
+ Chart.defaults.color = 'red';
+ var chart = acquireChart({
+ type: 'line',
+ data: {
+ datasets: [{
+ data: data0
+ }]
+ }
+ });
+
+ var meta = chart.getDatasetMeta(0);
+ expect(meta.dataset.options.borderColor).toBe('red');
+ expect(meta.data[0].options.borderColor).toBe('red');
+
+ // Reset old shared state
+ Chart.defaults.color = oldColor;
+ });
});