diff --git a/docs/docs/axes/_common.md b/docs/docs/axes/_common.md index 9e35464611c..1e9ba6450f1 100644 --- a/docs/docs/axes/_common.md +++ b/docs/docs/axes/_common.md @@ -5,6 +5,7 @@ Namespace: `options.scales[scaleId]` | Name | Type | Default | Description | ---- | ---- | ------- | ----------- | `type` | `string` | | Type of scale being employed. Custom scales can be created and registered with a string key. This allows changing the type of an axis for a chart. +| `backgroundColor` | [`Color`](../general/colors.md) | | Background color of the scale area. | `display` | `boolean`\|`string` | `true` | Controls the axis global visibility (visible when `true`, hidden when `false`). When `display: 'auto'`, the axis is visible only if at least one associated dataset is visible. | `gridLines` | `object` | | Grid line configuration. [more...](./styling.mdx#grid-line-configuration) | `min` | `number` | | User defined minimum number for the scale, overrides minimum value from data. [more...](./index.mdx#axis-range-settings) diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 684916e7fee..41606d91bcf 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1575,6 +1575,19 @@ export default class Scale extends Element { } } + /** + * @protected + */ + drawBackground() { + const {ctx, options: {backgroundColor}, left, top, width, height} = this; + if (backgroundColor) { + ctx.save(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(left, top, width, height); + ctx.restore(); + } + } + /** * @protected */ @@ -1730,6 +1743,7 @@ export default class Scale extends Element { return; } + me.drawBackground(); me.drawGrid(chartArea); me.drawTitle(); me.drawLabels(chartArea); @@ -1758,6 +1772,7 @@ export default class Scale extends Element { return [{ z: gz, draw(chartArea) { + me.drawBackground(); me.drawGrid(chartArea); me.drawTitle(); } diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 2d04d365f99..17928a7e751 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -93,7 +93,7 @@ function fitWithPointLabels(scale) { const labelSizes = []; const padding = []; - const valueCount = scale.chart.data.labels.length; + const valueCount = scale.getLabels().length; for (i = 0; i < valueCount; i++) { const opts = scale.options.pointLabels.setContext(scale.getContext(i)); padding[i] = opts.padding; @@ -196,17 +196,11 @@ function adjustPointPositionForLabelHeight(angle, textSize, position) { } } -function drawPointLabels(scale) { - const ctx = scale.ctx; - const opts = scale.options; - const pointLabelOpts = opts.pointLabels; - - ctx.save(); - - ctx.textBaseline = 'middle'; +function drawPointLabels(scale, labelCount) { + const {ctx, options: {pointLabels}} = scale; - for (let i = scale.chart.data.labels.length - 1; i >= 0; i--) { - const optsAtIndex = pointLabelOpts.setContext(scale.getContext(i)); + for (let i = labelCount - 1; i >= 0; i--) { + const optsAtIndex = pointLabels.setContext(scale.getContext(i)); const plFont = toFont(optsAtIndex.font); const {x, y, textAlign} = scale._pointLabelItems[i]; renderText( @@ -218,45 +212,47 @@ function drawPointLabels(scale) { { color: optsAtIndex.color, textAlign: textAlign, + textBaseline: 'middle' } ); } - ctx.restore(); } -function drawRadiusLine(scale, gridLineOpts, radius) { +function pathRadiusLine(scale, radius, circular, labelCount) { + const {ctx} = scale; + if (circular) { + // Draw circular arcs between the points + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); + } else { + // Draw straight lines connecting each index + let pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + + for (let i = 1; i < labelCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } +} + +function drawRadiusLine(scale, gridLineOpts, radius, labelCount) { const ctx = scale.ctx; const circular = gridLineOpts.circular; - const valueCount = scale.chart.data.labels.length; - const lineColor = gridLineOpts.color; - const lineWidth = gridLineOpts.lineWidth; - let pointPosition; + const {color, lineWidth} = gridLineOpts; - if ((!circular && !valueCount) || !lineColor || !lineWidth || radius < 0) { + if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) { return; } ctx.save(); - ctx.strokeStyle = lineColor; + ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.setLineDash(gridLineOpts.borderDash); ctx.lineDashOffset = gridLineOpts.borderDashOffset; ctx.beginPath(); - if (circular) { - // Draw circular arcs between the points - ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); - } else { - // Draw straight lines connecting each index - pointPosition = scale.getPointPosition(0, radius); - ctx.moveTo(pointPosition.x, pointPosition.y); - - for (let i = 1; i < valueCount; i++) { - pointPosition = scale.getPointPosition(i, radius); - ctx.lineTo(pointPosition.x, pointPosition.y); - } - } + pathRadiusLine(scale, radius, circular, labelCount); ctx.closePath(); ctx.stroke(); ctx.restore(); @@ -319,7 +315,7 @@ export default class RadialLinearScale extends LinearScaleBase { LinearScaleBase.prototype.generateTickLabels.call(me, ticks); // Point labels - me._pointLabels = me.chart.data.labels.map((value, index) => { + me._pointLabels = me.getLabels().map((value, index) => { const label = callCallback(me.options.pointLabels.callback, [value, index], me); return label || label === 0 ? label : ''; }); @@ -428,6 +424,24 @@ export default class RadialLinearScale extends LinearScaleBase { }; } + /** + * @protected + */ + drawBackground() { + const me = this; + const {backgroundColor, gridLines: {circular}} = me.options; + if (backgroundColor) { + const ctx = me.ctx; + ctx.save(); + ctx.beginPath(); + pathRadiusLine(me, me.getDistanceFromCenterForValue(me._endValue), circular, me.getLabels().length); + ctx.closePath(); + ctx.fillStyle = backgroundColor; + ctx.fill(); + ctx.restore(); + } + } + /** * @protected */ @@ -435,31 +449,31 @@ export default class RadialLinearScale extends LinearScaleBase { const me = this; const ctx = me.ctx; const opts = me.options; - const gridLineOpts = opts.gridLines; - const angleLineOpts = opts.angleLines; + const {angleLines, gridLines} = opts; + const labelCount = me.getLabels().length; + let i, offset, position; if (opts.pointLabels.display) { - drawPointLabels(me); + drawPointLabels(me, labelCount); } - if (gridLineOpts.display) { + if (gridLines.display) { me.ticks.forEach((tick, index) => { if (index !== 0) { - offset = me.getDistanceFromCenterForValue(me.ticks[index].value); - const optsAtIndex = gridLineOpts.setContext(me.getContext(index - 1)); - drawRadiusLine(me, optsAtIndex, offset); + offset = me.getDistanceFromCenterForValue(tick.value); + const optsAtIndex = gridLines.setContext(me.getContext(index - 1)); + drawRadiusLine(me, optsAtIndex, offset, labelCount); } }); } - if (angleLineOpts.display) { + if (angleLines.display) { ctx.save(); - for (i = me.chart.data.labels.length - 1; i >= 0; i--) { - const optsAtIndex = angleLineOpts.setContext(me.getContext(i)); - const lineWidth = optsAtIndex.lineWidth; - const color = optsAtIndex.color; + for (i = me.getLabels().length - 1; i >= 0; i--) { + const optsAtIndex = angleLines.setContext(me.getContext(i)); + const {color, lineWidth} = optsAtIndex; if (!lineWidth || !color) { continue; @@ -518,11 +532,12 @@ export default class RadialLinearScale extends LinearScaleBase { width = ctx.measureText(tick.label).width; ctx.fillStyle = optsAtIndex.backdropColor; + const {backdropPaddingX, backdropPaddingY} = optsAtIndex; ctx.fillRect( - -width / 2 - optsAtIndex.backdropPaddingX, - -offset - tickFont.size / 2 - optsAtIndex.backdropPaddingY, - width + optsAtIndex.backdropPaddingX * 2, - tickFont.size + optsAtIndex.backdropPaddingY * 2 + -width / 2 - backdropPaddingX, + -offset - tickFont.size / 2 - backdropPaddingY, + width + backdropPaddingX * 2, + tickFont.size + backdropPaddingY * 2 ); } diff --git a/test/fixtures/core.scale/backgroundColor.js b/test/fixtures/core.scale/backgroundColor.js new file mode 100644 index 00000000000..47be5469fec --- /dev/null +++ b/test/fixtures/core.scale/backgroundColor.js @@ -0,0 +1,58 @@ +const ticks = { + display: false +}; +const gridLines = { + display: false +}; +const title = { + display: true, + test: '' +}; +module.exports = { + config: { + type: 'line', + options: { + events: [], + scales: { + top: { + type: 'linear', + backgroundColor: 'red', + position: 'top', + ticks, + gridLines, + title + }, + left: { + type: 'linear', + backgroundColor: 'green', + position: 'left', + ticks, + gridLines, + title + }, + bottom: { + type: 'linear', + backgroundColor: 'blue', + position: 'bottom', + ticks, + gridLines, + title + }, + right: { + type: 'linear', + backgroundColor: 'gray', + position: 'right', + ticks, + gridLines, + title + }, + } + } + }, + options: { + canvas: { + height: 256, + width: 256 + }, + } +}; diff --git a/test/fixtures/core.scale/backgroundColor.png b/test/fixtures/core.scale/backgroundColor.png new file mode 100644 index 00000000000..5855420b931 Binary files /dev/null and b/test/fixtures/core.scale/backgroundColor.png differ diff --git a/test/fixtures/scale.radialLinear/backgroundColor.js b/test/fixtures/scale.radialLinear/backgroundColor.js new file mode 100644 index 00000000000..405877d3d3c --- /dev/null +++ b/test/fixtures/scale.radialLinear/backgroundColor.js @@ -0,0 +1,37 @@ +module.exports = { + threshold: 0.01, + config: { + type: 'radar', + data: { + labels: [1, 2, 3, 4, 5, 6], + datasets: [ + { + data: [3, 2, 2, 1, 3, 1] + } + ] + }, + options: { + plugins: { + legend: false, + tooltip: false, + filler: false + }, + scales: { + r: { + backgroundColor: '#00FF00', + min: 0, + max: 3, + pointLabels: { + display: false + }, + ticks: { + display: false, + stepSize: 1, + } + } + }, + responsive: true, + maintainAspectRatio: false + } + }, +}; diff --git a/test/fixtures/scale.radialLinear/backgroundColor.png b/test/fixtures/scale.radialLinear/backgroundColor.png new file mode 100644 index 00000000000..d61a1c9218d Binary files /dev/null and b/test/fixtures/scale.radialLinear/backgroundColor.png differ diff --git a/test/fixtures/scale.radialLinear/circular-backgroundColor.js b/test/fixtures/scale.radialLinear/circular-backgroundColor.js new file mode 100644 index 00000000000..5e21f244e6c --- /dev/null +++ b/test/fixtures/scale.radialLinear/circular-backgroundColor.js @@ -0,0 +1,40 @@ +module.exports = { + threshold: 0.05, + config: { + type: 'radar', + data: { + labels: [1, 2, 3, 4, 5, 6], + datasets: [ + { + data: [3, 2, 2, 1, 3, 1] + } + ] + }, + options: { + plugins: { + legend: false, + tooltip: false, + filler: false + }, + scales: { + r: { + backgroundColor: '#00FF00', + min: 0, + max: 3, + gridLines: { + circular: true + }, + pointLabels: { + display: false + }, + ticks: { + display: false, + stepSize: 1, + } + } + }, + responsive: true, + maintainAspectRatio: false + } + }, +}; diff --git a/test/fixtures/scale.radialLinear/circular-backgroundColor.png b/test/fixtures/scale.radialLinear/circular-backgroundColor.png new file mode 100644 index 00000000000..5da9a2d6213 Binary files /dev/null and b/test/fixtures/scale.radialLinear/circular-backgroundColor.png differ