Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/05-Radar-Chart.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ scale | Object | [See Scales](#scales) and [Defaults for Radial Linear Scale](#s
*scale*.type | String |"radialLinear" | As defined in ["Radial Linear"](#scales-radial-linear-scale).
*elements*.line | Object | | Options for all line elements used on the chart, as defined in the global elements, duplicated here to show Radar chart specific defaults.
*elements.line*.lineTension | Number | 0 | Tension exhibited by lines when calculating splineCurve. Setting to 0 creates straight lines.
startAngle | Number | 0 | The number of degrees to rotate the chart clockwise.

You can override these for your `Chart` instance by passing a second argument into the `Radar` method as an object with the keys you want to override.

Expand Down
44 changes: 26 additions & 18 deletions src/scales/scale.radialLinear.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,13 @@ module.exports = function(Chart) {
// 5px to space the text slightly out - similar to what we do in the draw function.
pointPosition = this.getPointPosition(i, largestPossibleRadius);
textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5;
if (i === 0 || i === this.getValueCount() / 2) {
// If we're at index zero, or exactly the middle, we're at exactly the top/bottom

// Add quarter circle to make degree 0 mean top of circle
var angleRadians = this.getIndexAngle(i) + (Math.PI / 2);
var angle = (angleRadians * 360 / (2 * Math.PI)) % 360;

if (angle === 0 || angle === 180) {
// At angle 0 and 180, we're at exactly the top/bottom
// of the radar chart, so text will be aligned centrally, so we'll half it and compare
// w/left and right text sizes
halfTextWidth = textWidth / 2;
Expand All @@ -184,13 +189,13 @@ module.exports = function(Chart) {
furthestLeft = pointPosition.x - halfTextWidth;
furthestLeftIndex = i;
}
} else if (i < this.getValueCount() / 2) {
} else if (angle < 180) {
// Less than half the values means we'll left align the text
if (pointPosition.x + textWidth > furthestRight) {
furthestRight = pointPosition.x + textWidth;
furthestRightIndex = i;
}
} else if (i > this.getValueCount() / 2) {
} else {
// More than half the values means we'll right align the text
if (pointPosition.x - textWidth < furthestLeft) {
furthestLeft = pointPosition.x - textWidth;
Expand Down Expand Up @@ -227,9 +232,14 @@ module.exports = function(Chart) {

getIndexAngle: function(index) {
var angleMultiplier = (Math.PI * 2) / this.getValueCount();
// Start from the top instead of right, so remove a quarter of the circle
var startAngle = this.chart.options && this.chart.options.startAngle ?
this.chart.options.startAngle :
0;

var startAngleRadians = startAngle * Math.PI * 2 / 360;

return index * angleMultiplier - (Math.PI / 2);
// Start from the top instead of right, so remove a quarter of the circle
return index * angleMultiplier - (Math.PI / 2) + startAngleRadians;
},
getDistanceFromCenterForValue: function(value) {
var me = this;
Expand Down Expand Up @@ -373,26 +383,24 @@ module.exports = function(Chart) {
ctx.font = pointLabeFont;
ctx.fillStyle = pointLabelFontColor;

var pointLabels = me.pointLabels,
labelsCount = pointLabels.length,
halfLabelsCount = pointLabels.length / 2,
quarterLabelsCount = halfLabelsCount / 2,
upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
if (i === 0) {
ctx.textAlign = 'center';
} else if (i === halfLabelsCount) {
var pointLabels = me.pointLabels;

// Add quarter circle to make degree 0 mean top of circle
var angleRadians = this.getIndexAngle(i) + (Math.PI / 2);
var angle = (angleRadians * 360 / (2 * Math.PI)) % 360;

if (angle === 0 || angle === 180) {
ctx.textAlign = 'center';
} else if (i < halfLabelsCount) {
} else if (angle < 180) {
ctx.textAlign = 'left';
} else {
ctx.textAlign = 'right';
}

// Set the correct text baseline based on outer positioning
if (exactQuarter) {
if (angle === 90 || angle === 270) {
ctx.textBaseline = 'middle';
} else if (upperHalf) {
} else if (angle > 270 || angle < 90) {
ctx.textBaseline = 'bottom';
} else {
ctx.textBaseline = 'top';
Expand Down
39 changes: 39 additions & 0 deletions test/scale.radialLinear.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,4 +420,43 @@ describe('Test the radial linear scale', function() {
expect(chartInstance.scale.getDistanceFromCenterForValue(chartInstance.scale.min)).toBe(225);
expect(chartInstance.scale.getDistanceFromCenterForValue(chartInstance.scale.max)).toBe(0);
});

it('should correctly get angles for all points', function() {
chartInstance = window.acquireChart({
type: 'radar',
data: {
datasets: [{
data: [10, 5, 0, 25, 78]
}],
labels: ['label1', 'label2', 'label3', 'label4', 'label5']
},
options: {
scale: {
pointLabels: {
callback: function(value, index) {
return index.toString();
}
}
},
startAngle: 15
}
});

var radToNearestDegree = function(rad) {
return Math.round((360 * rad) / (2 * Math.PI));
}

var slice = 72; // (360 / 5)

for(var i = 0; i < 5; i++) {
expect(radToNearestDegree(chartInstance.scale.getIndexAngle(i))).toBe(15 + (slice * i) - 90);
}

chartInstance.options.startAngle = 0;
chartInstance.update();

for(var i = 0; i < 5; i++) {
expect(radToNearestDegree(chartInstance.scale.getIndexAngle(i))).toBe((slice * i) - 90);
}
});
});