diff --git a/docs/charts/polar.md b/docs/charts/polar.md index 3782d2b83a6..e4bb628597c 100644 --- a/docs/charts/polar.md +++ b/docs/charts/polar.md @@ -101,7 +101,7 @@ These are the customisation options specific to Polar Area charts. These options | Name | Type | Default | Description | ---- | ---- | ------- | ----------- -| `startAngle` | `number` | `-0.5 * Math.PI` | Starting angle to draw arcs for the first item in a dataset. +| `startAngle` | `number` | `0` | Starting angle to draw arcs for the first item in a dataset. In degrees, 0 is at top. | `animation.animateRotate` | `boolean` | `true` | If true, the chart will animate in with a rotation animation. This property is in the `options.animation` object. | `animation.animateScale` | `boolean` | `true` | If true, will animate scaling the chart from the center outwards. @@ -112,6 +112,7 @@ The polar area chart uses the [radialLinear](../axes/radial/linear.md) scale. Ad We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.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.polarArea.animation.animateScale = false; ``` diff --git a/docs/getting-started/v3-migration.md b/docs/getting-started/v3-migration.md index 8ceb8fb01cf..5f8cea12636 100644 --- a/docs/getting-started/v3-migration.md +++ b/docs/getting-started/v3-migration.md @@ -43,6 +43,7 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released ### Options +* `Polar area` `startAngle` option is now consistent with `Radar`, 0 is at top and value is in degrees. Default is changed from `-½π` to `0`. * `scales.[x/y]Axes` arrays were removed. Scales are now configured directly to `options.scales` object with the object key being the scale Id. * `scales.[x/y]Axes.barPercentage` was moved to dataset option `barPercentage` * `scales.[x/y]Axes.barThickness` was moved to dataset option `barThickness` diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index ac07a3bb300..8eb1e6b0ecc 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -32,7 +32,7 @@ defaults._set('polarArea', { } }, - startAngle: -0.5 * Math.PI, + startAngle: 0, legend: { labels: { generateLabels: function(chart) { @@ -85,6 +85,12 @@ defaults._set('polarArea', { } }); +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. + return helpers.math.toRadians(deg) - 0.5 * Math.PI; +} + export default DatasetController.extend({ dataElementType: elements.Arc, @@ -117,13 +123,10 @@ export default DatasetController.extend({ }, update: function(mode) { - var me = this; - var meta = me._cachedMeta; - var arcs = meta.data; - - me._updateRadius(); + const arcs = this._cachedMeta.data; - me.updateElements(arcs, 0, mode); + this._updateRadius(); + this.updateElements(arcs, 0, mode); }, /** @@ -154,7 +157,7 @@ export default DatasetController.extend({ const scale = chart.scales.r; const centerX = scale.xCenter; const centerY = scale.yCenter; - const datasetStartAngle = opts.startAngle || 0; + const datasetStartAngle = getStartAngleRadians(opts.startAngle); let angle = datasetStartAngle; let i; diff --git a/src/helpers/helpers.math.js b/src/helpers/helpers.math.js index 215b44db790..a08ed5ea5a5 100644 --- a/src/helpers/helpers.math.js +++ b/src/helpers/helpers.math.js @@ -83,11 +83,11 @@ export const sign = Math.sign ? }; export function toRadians(degrees) { - return degrees * (Math.PI / 180); + return degrees * (PI / 180); } export function toDegrees(radians) { - return radians * (180 / Math.PI); + return radians * (180 / PI); } /** @@ -118,8 +118,8 @@ export function getAngleFromPoint(centrePoint, anglePoint) { var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); - if (angle < (-0.5 * Math.PI)) { - angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2] + if (angle < (-0.5 * PI)) { + angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2] } return { diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 433088b0f8e..0150ba70daa 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -2,7 +2,7 @@ import defaults from '../core/core.defaults'; import helpers from '../helpers/index'; -import {isNumber, toDegrees} from '../helpers/helpers.math'; +import {isNumber, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math'; import LinearScaleBase from './scale.linearbase'; import Ticks from '../core/core.ticks'; @@ -157,7 +157,7 @@ function fitWithPointLabels(scale) { // Add quarter circle to make degree 0 mean top of circle var angleRadians = scale.getIndexAngle(i); - var angle = toDegrees(angleRadians) % 360; + var angle = toDegrees(angleRadians); var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); @@ -380,14 +380,11 @@ class RadialLinearScale extends LinearScaleBase { getIndexAngle(index) { var chart = this.chart; - var angleMultiplier = 360 / chart.data.labels.length; + var angleMultiplier = Math.PI * 2 / chart.data.labels.length; var options = chart.options || {}; var startAngle = options.startAngle || 0; - // Start from the top instead of right, so remove a quarter of the circle - var angle = (index * angleMultiplier + startAngle) % 360; - - return (angle < 0 ? angle + 360 : angle) * Math.PI * 2 / 360; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); } getDistanceFromCenterForValue(value) { diff --git a/test/fixtures/controller.polarArea/angle-lines.json b/test/fixtures/controller.polarArea/angle-lines.json new file mode 100644 index 00000000000..01474c028d6 --- /dev/null +++ b/test/fixtures/controller.polarArea/angle-lines.json @@ -0,0 +1,35 @@ +{ + "threshold": 0.05, + "config": { + "type": "polarArea", + "data": { + "labels": ["A", "B", "C", "D", "E"], + "datasets": [{ + "data": [11, 16, 21, 7, 10], + "backgroundColor": [ + "rgba(255, 99, 132, 0.8)", + "rgba(54, 162, 235, 0.8)", + "rgba(255, 206, 86, 0.8)", + "rgba(75, 192, 192, 0.8)", + "rgba(153, 102, 255, 0.8)", + "rgba(255, 159, 64, 0.8)" + ] + }] + }, + "options": { + "responsive": false, + "legend": false, + "title": false, + "scale": { + "display": true, + "angleLines": { + "display": true, + "color": "#000" + }, + "ticks": { + "display": false + } + } + } + } +} diff --git a/test/fixtures/controller.polarArea/angle-lines.png b/test/fixtures/controller.polarArea/angle-lines.png new file mode 100644 index 00000000000..3890d7cb64a Binary files /dev/null and b/test/fixtures/controller.polarArea/angle-lines.png differ diff --git a/test/specs/controller.polarArea.tests.js b/test/specs/controller.polarArea.tests.js index f7ea6e6a5bf..7780f9fde3b 100644 --- a/test/specs/controller.polarArea.tests.js +++ b/test/specs/controller.polarArea.tests.js @@ -156,7 +156,7 @@ describe('Chart.controllers.polarArea', function() { showLines: true, legend: false, title: false, - startAngle: 0, // default is -0.5 * Math.PI + startAngle: 90, // default is 0 elements: { arc: { backgroundColor: 'rgb(255, 0, 0)', diff --git a/test/specs/scale.radialLinear.tests.js b/test/specs/scale.radialLinear.tests.js index a64157a7e69..d8a50712f76 100644 --- a/test/specs/scale.radialLinear.tests.js +++ b/test/specs/scale.radialLinear.tests.js @@ -535,7 +535,7 @@ describe('Test the radial linear scale', function() { scale.ctx.getCalls().filter(function(x) { return x.name === 'setTextAlign'; }).forEach(function(x, i) { - expect(x.args[0]).toBe(expected.textAlign[i]); + expect(x.args[0]).withContext('startAngle: ' + expected.startAngle + ', tick: ' + i).toBe(expected.textAlign[i]); }); scale.ctx.getCalls().filter(function(x) {