The following options are provided by the linear radial scale. They are all located in the `ticks` sub options. The [common tick configuration](../styling.md#tick-configuration) options are supported by this axis.
-| Name | Type | Default | Description
-| ---- | ---- | ------- | -----------
-| `backdropColor` | `Color` | `'rgba(255, 255, 255, 0.75)'` | Color of label backdrops.
-| `backdropPaddingX` | `number` | `2` | Horizontal padding of label backdrop.
-| `backdropPaddingY` | `number` | `2` | Vertical padding of label backdrop.
-| `format` | `object` | | The [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) options used by the default label formatter
-| `maxTicksLimit` | `number` | `11` | Maximum number of ticks and gridlines to show.
-| `precision` | `number` | | if defined and `stepSize` is not specified, the step size will be rounded to this many decimal places.
-| `stepSize` | `number` | | User defined fixed step size for the scale. [more...](#step-size)
-| `showLabelBackdrop` | `boolean` | `true` | If true, draw a background behind the tick labels.
+| Name | Type | Scriptable | Default | Description
+| ---- | ---- | ------- | ------- | -----------
+| `backdropColor` | `Color` | Yes | `'rgba(255, 255, 255, 0.75)'` | Color of label backdrops.
+| `backdropPaddingX` | `number` | | `2` | Horizontal padding of label backdrop.
+| `backdropPaddingY` | `number` | | `2` | Vertical padding of label backdrop.
+| `format` | `object` | | | The [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) options used by the default label formatter
+| `maxTicksLimit` | `number` | | `11` | Maximum number of ticks and gridlines to show.
+| `precision` | `number` | | | if defined and `stepSize` is not specified, the step size will be rounded to this many decimal places.
+| `stepSize` | `number` | | | User defined fixed step size for the scale. [more...](#step-size)
+| `showLabelBackdrop` | `boolean` | Yes | `true` | If true, draw a background behind the tick labels.
+
+The scriptable context has the following form:
+
+```javascript
+{
+ chart,
+ scale,
+ index,
+ tick
+}
+```
## Axis Range Settings
The following options are used to configure angled lines that radiate from the center of the chart to the point labels. They can be found in the `angleLines` sub options.
-| Name | Type | Default | Description
-| ---- | ---- | ------- | -----------
-| `display` | `boolean` | `true` | if true, angle lines are shown.
-| `color` | `Color` | `'rgba(0, 0, 0, 0.1)'` | Color of angled lines.
-| `lineWidth` | `number` | `1` | Width of angled lines.
-| `borderDash` | `number[]` | `[]` | Length and spacing of dashes on angled lines. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash).
-| `borderDashOffset` | `number` | `0.0` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset).
+| Name | Type | Scriptable | Default | Description
+| ---- | ---- | ------- | ------- | -----------
+| `display` | `boolean` | | `true` | if true, angle lines are shown.
+| `color` | `Color` | Yes | `'rgba(0, 0, 0, 0.1)'` | Color of angled lines.
+| `lineWidth` | `number` | Yes | `1` | Width of angled lines.
+| `borderDash` | `number[]` | Yes* | `[]` | Length and spacing of dashes on angled lines. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash).
+| `borderDashOffset` | `number` | Yes | `0.0` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset).
+
+The `borderDash` setting only accepts a static value or a function. Passing an array of arrays is not supported.
+
+The scriptable context has the following form:
+
+```javascript
+{
+ chart,
+ scale,
+ index,
+ label
+}
+```
## Point Label Options
The following options are used to configure the point labels that are shown on the perimeter of the scale. They can be found in the `pointLabels` sub options.
-| Name | Type | Default | Description
-| ---- | ---- | ------- | -----------
-| `display` | `boolean` | `true` | if true, point labels are shown.
-| `callback` | `function` | | Callback function to transform data labels to point labels. The default implementation simply returns the current string.
-| `font` | `Font` | `defaults.font` | See [Fonts](fonts.md)
+| Name | Type | Scriptable | Default | Description
+| ---- | ---- | ------- | ------- | -----------
+| `display` | `boolean` | | `true` | if true, point labels are shown.
+| `callback` | `function` | | | Callback function to transform data labels to point labels. The default implementation simply returns the current string.
+| `font` | `Font` | Yes | `defaults.font` | See [Fonts](fonts.md)
+
+The scriptable context is the same as for the [Angle Line Options](#angle-line-options).
## Internal data format
* `helpers.findNextWhere`
* `helpers.findPreviousWhere`
* `helpers.extend`. Use `Object.assign` instead
+* `helpers.getValueAtIndexOrDefault`. Use `helpers.resolve` instead.
* `helpers.indexOf`
* `helpers.lineTo`
* `helpers.longestText` was moved to the `helpers.canvas` namespace and made private
* `helpers.getMaximumWidth` was renamed to `helpers.dom.getMaximumWidth`
* `helpers.getRelativePosition` was renamed to `helpers.dom.getRelativePosition`
* `helpers.getStyle` was renamed to `helpers.dom.getStyle`
-* `helpers.getValueAtIndexOrDefault` was renamed to `helpers.valueAtIndexOrDefault`
* `helpers.getValueOrDefault` was renamed to `helpers.valueOrDefault`
* `helpers.easingEffects` was renamed to `helpers.easing.effects`
* `helpers.log10` was renamed to `helpers.math.log10`
return typeof value === 'undefined' ? defaultValue : value;
}
-/**
- * Returns value at the given `index` in array if defined, else returns `defaultValue`.
- * @param {Array} value - The array to lookup for value at `index`.
- * @param {number} index - The index in `value` to lookup for value.
- * @param {*} defaultValue - The value to return if `value[index]` is undefined.
- * @returns {*}
- */
-export function valueAtIndexOrDefault(value, index, defaultValue) {
- return valueOrDefault(isArray(value) ? value[index] : value, defaultValue);
-}
-
/**
* Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
* value returned by `fn`. If `fn` is not a function, this method returns undefined.
import {isNumber, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math';
import LinearScaleBase from './scale.linearbase';
import Ticks from '../core/core.ticks';
-import {valueOrDefault, isArray, valueAtIndexOrDefault, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
+import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
import {toFont, resolve} from '../helpers/helpers.options';
//
// https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
- const plFont = toFont(scale.options.pointLabels.font);
-
// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
const furthestLimits = {
const furthestAngles = {};
let i, textSize, pointPosition;
- scale.ctx.font = plFont.string;
scale._pointLabelSizes = [];
const valueCount = scale.chart.data.labels.length;
for (i = 0; i < valueCount; i++) {
pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);
+
+ const context = {
+ chart: scale.chart,
+ scale,
+ index: i,
+ label: scale.pointLabels[i]
+ };
+ const plFont = toFont(resolve([scale.options.pointLabels.font], context, i));
+ scale.ctx.font = plFont.string;
textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]);
scale._pointLabelSizes[i] = textSize;
const pointLabelOpts = opts.pointLabels;
const tickBackdropHeight = getTickBackdropHeight(opts);
const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
- const plFont = toFont(pointLabelOpts.font);
ctx.save();
const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
- // Keep this in loop since we may support array properties here
+ const context = {
+ chart: scale.chart,
+ scale,
+ index: i,
+ label: scale.pointLabels[i],
+ };
+ const plFont = toFont(resolve([pointLabelOpts.font], context, i));
ctx.font = plFont.string;
ctx.fillStyle = plFont.color;
- const angleRadians = scale.getIndexAngle(i);
- const angle = toDegrees(angleRadians);
+ const angle = toDegrees(scale.getIndexAngle(i));
ctx.textAlign = getTextAlignForAngle(angle);
adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight);
const ctx = scale.ctx;
const circular = gridLineOpts.circular;
const valueCount = scale.chart.data.labels.length;
- const lineColor = valueAtIndexOrDefault(gridLineOpts.color, index - 1, undefined);
- const lineWidth = valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1, undefined);
+
+ const context = {
+ chart: scale.chart,
+ scale,
+ index,
+ tick: scale.ticks[index],
+ };
+ const lineColor = resolve([gridLineOpts.color], context, index - 1);
+ const lineWidth = resolve([gridLineOpts.lineWidth], context, index - 1);
let pointPosition;
if ((!circular && !valueCount) || !lineColor || !lineWidth) {
ctx.strokeStyle = lineColor;
ctx.lineWidth = lineWidth;
if (ctx.setLineDash) {
- ctx.setLineDash(gridLineOpts.borderDash || []);
- ctx.lineDashOffset = gridLineOpts.borderDashOffset || 0.0;
+ ctx.setLineDash(resolve([gridLineOpts.borderDash, []], context));
+ ctx.lineDashOffset = resolve([gridLineOpts.borderDashOffset], context, index - 1);
}
ctx.beginPath();
const opts = me.options;
const gridLineOpts = opts.gridLines;
const angleLineOpts = opts.angleLines;
- const lineWidth = valueOrDefault(angleLineOpts.lineWidth, gridLineOpts.lineWidth);
- const lineColor = valueOrDefault(angleLineOpts.color, gridLineOpts.color);
let i, offset, position;
if (opts.pointLabels.display) {
});
}
- if (angleLineOpts.display && lineWidth && lineColor) {
+ if (angleLineOpts.display) {
ctx.save();
- ctx.lineWidth = lineWidth;
- ctx.strokeStyle = lineColor;
- if (ctx.setLineDash) {
- ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));
- ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);
- }
for (i = me.chart.data.labels.length - 1; i >= 0; i--) {
+ const context = {
+ chart: me.chart,
+ scale: me,
+ index: i,
+ label: me.pointLabels[i],
+ };
+ const lineWidth = resolve([angleLineOpts.lineWidth, gridLineOpts.lineWidth], context, i);
+ const color = resolve([angleLineOpts.color, gridLineOpts.color], context, i);
+
+ if (!lineWidth || !color) {
+ continue;
+ }
+
+ ctx.lineWidth = lineWidth;
+ ctx.strokeStyle = color;
+
+ if (ctx.setLineDash) {
+ ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []], context));
+ ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0], context, i);
+ }
+
offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);
position = me.getPointPosition(i, offset);
ctx.beginPath();
}
const startAngle = me.getIndexAngle(0);
- const tickFont = toFont(tickOpts.font);
let offset, width;
ctx.save();
- ctx.font = tickFont.string;
ctx.translate(me.xCenter, me.yCenter);
ctx.rotate(startAngle);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
me.ticks.forEach((tick, index) => {
+ const context = {
+ chart: me.chart,
+ scale: me,
+ index,
+ tick,
+ };
+
if (index === 0 && !opts.reverse) {
return;
}
+ const tickFont = me._resolveTickFontOptions(index);
+ ctx.font = tickFont.string;
offset = me.getDistanceFromCenterForValue(me.ticks[index].value);
- if (tickOpts.showLabelBackdrop) {
+ const showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index);
+
+ if (showLabelBackdrop) {
width = ctx.measureText(tick.label).width;
- ctx.fillStyle = tickOpts.backdropColor;
+ ctx.fillStyle = resolve([tickOpts.backdropColor], context, index);
ctx.fillRect(
-width / 2 - tickOpts.backdropPaddingX,
--- /dev/null
+module.exports = {
+ config: {
+ type: 'radar',
+ data: {
+ labels: ['A', 'B', 'C', 'D', 'E']
+ },
+ options: {
+ responsive: false,
+ legend: false,
+ title: false,
+ scale: {
+ gridLines: {
+ display: true,
+ },
+ angleLines: {
+ color: ['red', 'green'],
+ lineWidth: [1, 5]
+ },
+ pointLabels: {
+ display: false
+ },
+ ticks: {
+ display: false
+ }
+ }
+ }
+ }
+};
--- /dev/null
+module.exports = {
+ config: {
+ type: 'radar',
+ data: {
+ labels: ['A', 'B', 'C', 'D', 'E']
+ },
+ options: {
+ responsive: false,
+ legend: false,
+ title: false,
+ scale: {
+ gridLines: {
+ display: true,
+ },
+ angleLines: {
+ color: function(context) {
+ return context.index % 2 === 0 ? 'red' : 'green';
+ },
+ lineWidth: function(context) {
+ return context.index % 2 === 0 ? 1 : 5;
+ },
+ },
+ pointLabels: {
+ display: false
+ },
+ ticks: {
+ display: false
+ }
+ }
+ }
+ }
+};
--- /dev/null
+module.exports = {
+ config: {
+ type: 'radar',
+ data: {
+ labels: ['A', 'B', 'C', 'D', 'E']
+ },
+ options: {
+ responsive: false,
+ legend: false,
+ title: false,
+ scale: {
+ gridLines: {
+ display: true,
+ color: function(context) {
+ return context.index % 2 === 0 ? 'red' : 'green';
+ },
+ lineWidth: function(context) {
+ return context.index % 2 === 0 ? 1 : 5;
+ },
+ },
+ angleLines: {
+ color: 'rgba(255, 255, 255, 0.5)',
+ lineWidth: 2
+ },
+ pointLabels: {
+ display: false
+ },
+ ticks: {
+ display: false
+ }
+ }
+ }
+ }
+};
});
});
- describe('valueAtIndexOrDefault', function() {
- it('should return the passed value if not an array', function() {
- expect(helpers.valueAtIndexOrDefault(0, 0, 42)).toBe(0);
- expect(helpers.valueAtIndexOrDefault('', 0, 42)).toBe('');
- expect(helpers.valueAtIndexOrDefault(null, 0, 42)).toBe(null);
- expect(helpers.valueAtIndexOrDefault(false, 0, 42)).toBe(false);
- expect(helpers.valueAtIndexOrDefault(98, 0, 42)).toBe(98);
- });
- it('should return the value at index if defined', function() {
- expect(helpers.valueAtIndexOrDefault([1, false, 'foo'], 1, 42)).toBe(false);
- expect(helpers.valueAtIndexOrDefault([1, false, 'foo'], 2, 42)).toBe('foo');
- });
- it('should return the default value if the passed value is undefined', function() {
- expect(helpers.valueAtIndexOrDefault(undefined, 0, 42)).toBe(42);
- });
- it('should return the default value if value at index is undefined', function() {
- expect(helpers.valueAtIndexOrDefault([1, false, 'foo'], 3, 42)).toBe(42);
- expect(helpers.valueAtIndexOrDefault([1, undefined, 'foo'], 1, 42)).toBe(42);
- });
- });
-
describe('callback', function() {
it('should return undefined if fn is not a function', function() {
expect(helpers.callback()).not.toBeDefined();