Skip to content

Commit

Permalink
Add centerPointLabels option for linear radial scale (#9949)
Browse files Browse the repository at this point in the history
* center point labels to slices in polar chart

* remove unnecessary comments

* put the code together in one line

* fix the code according to the code review

* Undo changes related to the createContext function

* add documentation and types.
  • Loading branch information
t-mangoe committed Dec 21, 2021
1 parent 0d250a1 commit 961533c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/axes/radial/linear.md
Expand Up @@ -125,6 +125,7 @@ Namespace: `options.scales[scaleId].pointLabels`
| `color` | [`Color`](../../general/colors.md) | Yes | `Chart.defaults.color` | Color of label.
| `font` | `Font` | Yes | `Chart.defaults.font` | See [Fonts](../../general/fonts.md)
| `padding` | `number` | Yes | 5 | Padding between chart and point labels.
| `centerPointLabels` | `boolean` | | `false` | if true, point labels are centered.

The scriptable context is described in [Options](../../general/options.md#scale) section.

Expand Down
16 changes: 10 additions & 6 deletions src/scales/scale.radialLinear.js
@@ -1,6 +1,6 @@
import defaults from '../core/core.defaults';
import {_longestText, renderText} from '../helpers/helpers.canvas';
import {HALF_PI, isNumber, TAU, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math';
import {HALF_PI, isNumber, TAU, toDegrees, toRadians, _normalizeAngle, PI} from '../helpers/helpers.math';
import LinearScaleBase from './scale.linearbase';
import Ticks from '../core/core.ticks';
import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
Expand Down Expand Up @@ -133,12 +133,13 @@ function buildPointLabelItems(scale, labelSizes, padding) {
const opts = scale.options;
const tickBackdropHeight = getTickBackdropHeight(opts);
const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0;

for (let i = 0; i < valueCount; i++) {
// Extra pixels out for some label spacing
const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i]);
const angle = toDegrees(scale.getIndexAngle(i));
const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle);
const angle = toDegrees(pointLabelPosition.angle + HALF_PI);
const size = labelSizes[i];
const y = yForAngle(pointLabelPosition.y, size.h, angle);
const textAlign = getTextAlignForAngle(angle);
Expand Down Expand Up @@ -404,8 +405,8 @@ export default class RadialLinearScale extends LinearScaleBase {
}
}

getPointPosition(index, distanceFromCenter) {
const angle = this.getIndexAngle(index) - HALF_PI;
getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;
return {
x: Math.cos(angle) * distanceFromCenter + this.xCenter,
y: Math.sin(angle) * distanceFromCenter + this.yCenter,
Expand Down Expand Up @@ -618,7 +619,10 @@ RadialLinearScale.defaults = {
},

// Number - Additionl padding between scale and pointLabel
padding: 5
padding: 5,

// Boolean - if true, center point labels to slices in polar chart
centerPointLabels: false
}
};

Expand Down
58 changes: 57 additions & 1 deletion test/specs/scale.radialLinear.tests.js
Expand Up @@ -48,7 +48,8 @@ describe('Test the radial linear scale', function() {
size: 10
},
callback: defaultConfig.pointLabels.callback,
padding: 5
padding: 5,
centerPointLabels: false
}
});

Expand Down Expand Up @@ -590,4 +591,59 @@ describe('Test the radial linear scale', function() {
});
});
});

it('should correctly get the point positions in center', function() {
var chart = window.acquireChart({
type: 'polarArea',
data: {
datasets: [{
data: [10, 5, 0, 25, 78]
}],
labels: ['label1', 'label2', 'label3', 'label4', 'label5']
},
options: {
scales: {
r: {
pointLabels: {
display: true,
padding: 5,
centerPointLabels: true
},
ticks: {
display: false
}
}
}
}
});

const PI = Math.PI;
const lavelNum = 5;
const padding = 5;
const pointLabelItems = chart.scales.r._pointLabelItems;
const additionalAngle = PI / lavelNum;
const opts = chart.scales.r.options;
const outerDistance = chart.scales.r.getDistanceFromCenterForValue(opts.ticks.reverse ? chart.scales.r.min : chart.scales.r.max);
const tickBackdropHeight = 0;
const yForAngle = function(y, h, angle) {
if (angle === 90 || angle === 270) {
y -= (h / 2);
} else if (angle > 270 || angle < 90) {
y -= h;
}
return y;
};
const toDegrees = function(radians) {
return radians * (180 / PI);
};

for (var i = 0; i < 5; i++) {
const extra = (i === 0 ? tickBackdropHeight / 2 : 0);
const pointLabelItem = pointLabelItems[i];
const pointPosition = chart.scales.r.getPointPosition(i, outerDistance + extra + padding, additionalAngle);
expect(pointLabelItem.x).toBe(pointPosition.x);
expect(pointLabelItem.y).toBe(yForAngle(pointPosition.y, 12, toDegrees(pointPosition.angle + PI / 2)));
}

});
});
6 changes: 6 additions & 0 deletions types/index.esm.d.ts
Expand Up @@ -3347,6 +3347,12 @@ export type RadialLinearScaleOptions = CoreScaleOptions & {
* Callback function to transform data labels to point labels. The default implementation simply returns the current string.
*/
callback: (label: string, index: number) => string | string[] | number | number[];

/**
* if true, point labels are centered.
* @default false
*/
centerPointLabels: boolean;
};

/**
Expand Down

0 comments on commit 961533c

Please sign in to comment.