From d38111723676d51d6a2b49bd3eec71b675d508ca Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 3 Jul 2016 13:55:43 -0600 Subject: [PATCH 1/4] Issue #2252, added usePointStyle option to allow label boxes to match the shape(pointStyle) of the corresponding data. --- docs/01-Chart-Configuration.md | 4 ++ src/chart.js | 1 + src/core/core.canvasHelpers.js | 104 +++++++++++++++++++++++++++++++++ src/core/core.legend.js | 45 +++++++++++--- src/elements/element.point.js | 94 +---------------------------- test/core.legend.tests.js | 4 ++ test/element.point.tests.js | 3 + 7 files changed, 153 insertions(+), 102 deletions(-) create mode 100644 src/core/core.canvasHelpers.js diff --git a/docs/01-Chart-Configuration.md b/docs/01-Chart-Configuration.md index f2be7e3c253..a573c51ff12 100644 --- a/docs/01-Chart-Configuration.md +++ b/docs/01-Chart-Configuration.md @@ -132,6 +132,7 @@ fontColor | Color | "#666" | Font color inherited from global configuration fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family inherited from global configuration padding | Number | 10 | Padding between rows of colored boxes generateLabels: | Function | `function(chart) { }` | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#chart-configuration-legend-item-interface) for details. +usePointStyle | Boolean | false | Label style will match corresponding point style (size is based on fontSize, boxWidth is not used in this case). #### Legend Item Interface @@ -165,6 +166,9 @@ Items passed to the legend `onClick` function are the ones returned from `labels // Stroke style of the legend box strokeStyle: Color + + // Point style of the legend box (only used if usePointStyle is true) + pointStyle: String } ``` diff --git a/src/chart.js b/src/chart.js index 75bd4753841..a12890aa06b 100644 --- a/src/chart.js +++ b/src/chart.js @@ -4,6 +4,7 @@ var Chart = require('./core/core.js')(); require('./core/core.helpers')(Chart); +require('./core/core.canvasHelpers')(Chart); require('./core/core.element')(Chart); require('./core/core.animation')(Chart); require('./core/core.controller')(Chart); diff --git a/src/core/core.canvasHelpers.js b/src/core/core.canvasHelpers.js new file mode 100644 index 00000000000..f8c35c96e64 --- /dev/null +++ b/src/core/core.canvasHelpers.js @@ -0,0 +1,104 @@ +"use strict"; + +module.exports = function(Chart) { + // Global Chart canvas helpers object for drawing items to canvas + var helpers = Chart.canvasHelpers = {}; + + helpers.drawPoint = function(ctx, pointStyle, radius, x, y) { + var type, edgeLength, xOffset, yOffset, height, size; + + if (typeof pointStyle === 'object') { + type = pointStyle.toString(); + if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { + ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2); + return; + } + } + + if (isNaN(radius) || radius <= 0) { + return; + } + + switch (pointStyle) { + // Default includes circle + default: + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + break; + case 'triangle': + ctx.beginPath(); + edgeLength = 3 * radius / Math.sqrt(3); + height = edgeLength * Math.sqrt(3) / 2; + ctx.moveTo(x - edgeLength / 2, y + height / 3); + ctx.lineTo(x + edgeLength / 2, y + height / 3); + ctx.lineTo(x, y - 2 * height / 3); + ctx.closePath(); + ctx.fill(); + break; + case 'rect': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.fillRect(x - size, y - size, 2 * size, 2 * size); + ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); + break; + case 'rectRot': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y - size); + ctx.closePath(); + ctx.fill(); + break; + case 'cross': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'crossRot': + ctx.beginPath(); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'star': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'line': + ctx.beginPath(); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'dash': + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + } + + ctx.stroke(); + }; +}; \ No newline at end of file diff --git a/src/core/core.legend.js b/src/core/core.legend.js index 78c89c55925..26e17f9914b 100644 --- a/src/core/core.legend.js +++ b/src/core/core.legend.js @@ -52,6 +52,7 @@ module.exports = function(Chart) { lineJoin: dataset.borderJoinStyle, lineWidth: dataset.borderWidth, strokeStyle: dataset.borderColor, + pointStyle: dataset.pointStyle, // Below is extra data used for toggling the datasets datasetIndex: i @@ -201,7 +202,11 @@ module.exports = function(Chart) { ctx.textBaseline = 'top'; helpers.each(me.legendItems, function(legendItem, i) { - var width = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + var boxWidth = labelOpts.usePointStyle ? + fontSize * Math.sqrt(2) : + labelOpts.boxWidth; + + var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) { totalHeight += fontSize + (labelOpts.padding); lineWidths[lineWidths.length] = me.left; @@ -229,7 +234,11 @@ module.exports = function(Chart) { var itemHeight = fontSize + vPadding; helpers.each(me.legendItems, function(legendItem, i) { - var itemWidth = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + // If usePointStyle is set, multiple boxWidth by 2 since it represents + // the radius and not truly the width + var boxWidth = labelOpts.usePointStyle ? 2 * labelOpts.boxWidth : labelOpts.boxWidth; + + var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; // If too tall, go to new column if (currentColHeight + itemHeight > minSize.height) { @@ -303,6 +312,10 @@ module.exports = function(Chart) { // current position var drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0) { + return; + } + // Set the ctx for the box ctx.save(); @@ -318,9 +331,22 @@ module.exports = function(Chart) { ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash)); } - // Draw the box - ctx.strokeRect(x, y, boxWidth, fontSize); - ctx.fillRect(x, y, boxWidth, fontSize); + if (opts.labels && opts.labels.usePointStyle) { + // Recalulate x and y for drawPoint() because its expecting + // x and y to be center of figure (instead of top left) + var radius = fontSize * Math.SQRT2 / 2; + var offSet = radius / Math.SQRT2; + var centerX = x + offSet; + var centerY = y + offSet; + + // Draw pointStyle as legend symbol + Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY); + } + else { + // Draw box as legend symbol + ctx.strokeRect(x, y, boxWidth, fontSize); + ctx.fillRect(x, y, boxWidth, fontSize); + } ctx.restore(); }; @@ -348,7 +374,7 @@ module.exports = function(Chart) { } else { cursor = { x: me.left + labelOpts.padding, - y: me.top, + y: me.top + labelOpts.padding, line: 0 }; } @@ -356,13 +382,15 @@ module.exports = function(Chart) { var itemHeight = fontSize + labelOpts.padding; helpers.each(me.legendItems, function(legendItem, i) { var textWidth = ctx.measureText(legendItem.text).width, - width = boxWidth + (fontSize / 2) + textWidth, + width = labelOpts.usePointStyle ? + fontSize + (fontSize / 2) + textWidth : + boxWidth + (fontSize / 2) + textWidth, x = cursor.x, y = cursor.y; if (isHorizontal) { if (x + width >= legendWidth) { - y = cursor.y += fontSize + (labelOpts.padding); + y = cursor.y += itemHeight; cursor.line++; x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2); } @@ -374,7 +402,6 @@ module.exports = function(Chart) { } } - drawLegendBox(x, y, legendItem); hitboxes[i].left = x; diff --git a/src/elements/element.point.js b/src/elements/element.point.js index 3290041b2b9..4131f8ceded 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -42,108 +42,16 @@ module.exports = function(Chart) { var radius = vm.radius; var x = vm.x; var y = vm.y; - var type, edgeLength, xOffset, yOffset, height, size; if (vm.skip) { return; } - if (typeof pointStyle === 'object') { - type = pointStyle.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2); - return; - } - } - - if (isNaN(radius) || radius <= 0) { - return; - } - ctx.strokeStyle = vm.borderColor || defaultColor; ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth); ctx.fillStyle = vm.backgroundColor || defaultColor; - switch (pointStyle) { - // Default includes circle - default: - ctx.beginPath(); - ctx.arc(x, y, radius, 0, Math.PI * 2); - ctx.closePath(); - ctx.fill(); - break; - case 'triangle': - ctx.beginPath(); - edgeLength = 3 * radius / Math.sqrt(3); - height = edgeLength * Math.sqrt(3) / 2; - ctx.moveTo(x - edgeLength / 2, y + height / 3); - ctx.lineTo(x + edgeLength / 2, y + height / 3); - ctx.lineTo(x, y - 2 * height / 3); - ctx.closePath(); - ctx.fill(); - break; - case 'rect': - size = 1 / Math.SQRT2 * radius; - ctx.fillRect(x - size, y - size, 2 * size, 2 * size); - ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); - break; - case 'rectRot': - size = 1 / Math.SQRT2 * radius; - ctx.beginPath(); - ctx.moveTo(x - size, y); - ctx.lineTo(x, y + size); - ctx.lineTo(x + size, y); - ctx.lineTo(x, y - size); - ctx.closePath(); - ctx.fill(); - break; - case 'cross': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - case 'crossRot': - ctx.beginPath(); - xOffset = Math.cos(Math.PI / 4) * radius; - yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); - break; - case 'star': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - xOffset = Math.cos(Math.PI / 4) * radius; - yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); - break; - case 'line': - ctx.beginPath(); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - case 'dash': - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); - break; - } - - ctx.stroke(); + Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y); } }); }; diff --git a/test/core.legend.tests.js b/test/core.legend.tests.js index fa6e8e76f1d..2db970f3f0f 100644 --- a/test/core.legend.tests.js +++ b/test/core.legend.tests.js @@ -52,6 +52,7 @@ describe('Legend block tests', function() { label: 'dataset3', borderWidth: 10, borderColor: 'green', + pointStyle: 'crossRot', data: [] }], labels: [] @@ -68,6 +69,7 @@ describe('Legend block tests', function() { lineJoin: undefined, lineWidth: undefined, strokeStyle: undefined, + pointStyle: undefined, datasetIndex: 0 }, { text: 'dataset2', @@ -79,6 +81,7 @@ describe('Legend block tests', function() { lineJoin: 'miter', lineWidth: undefined, strokeStyle: undefined, + pointStyle: undefined, datasetIndex: 1 }, { text: 'dataset3', @@ -90,6 +93,7 @@ describe('Legend block tests', function() { lineJoin: undefined, lineWidth: 10, strokeStyle: 'green', + pointStyle: 'crossRot', datasetIndex: 2 }]); }); diff --git a/test/element.point.tests.js b/test/element.point.tests.js index 674682660ca..c257f7375ca 100644 --- a/test/element.point.tests.js +++ b/test/element.point.tests.js @@ -164,6 +164,9 @@ describe('Point element tests', function() { }, { name: 'setFillStyle', args: ['rgba(0, 255, 0)'] + }, { + name: 'beginPath', + args: [] }, { name: 'fillRect', args: [10 - 1 / Math.SQRT2 * 2, 15 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2] From 56be759d212eb6af2914fb2a7a17c418ffa76d9a Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 3 Jul 2016 18:40:15 -0600 Subject: [PATCH 2/4] Removed unused varaible from legend's draw() --- src/core/core.legend.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/core.legend.js b/src/core/core.legend.js index b291e9b2a1d..a13151bd332 100644 --- a/src/core/core.legend.js +++ b/src/core/core.legend.js @@ -286,7 +286,6 @@ module.exports = function(Chart) { var globalDefault = Chart.defaults.global, lineDefault = globalDefault.elements.line, legendWidth = me.width, - legendHeight = me.height, lineWidths = me.lineWidths; if (opts.display) { From ad7ed249af2faa0d4ae4b2607e3f788417d22cf9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 16 Jul 2016 18:58:04 -0600 Subject: [PATCH 3/4] Add an option for radar chart to have offsetAngle. Issue #1012 --- docs/05-Radar-Chart.md | 1 + src/scales/scale.radialLinear.js | 44 +++++++++++++++++++------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/docs/05-Radar-Chart.md b/docs/05-Radar-Chart.md index ce98dc4e973..4270203c70c 100644 --- a/docs/05-Radar-Chart.md +++ b/docs/05-Radar-Chart.md @@ -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. +offsetAngle | 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. diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index c69974f60ae..900ade4eac6 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -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; @@ -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; @@ -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 offsetAngle = this.chart.options && this.chart.options.offsetAngle ? + this.chart.options.offsetAngle : + 0; + + var offsetAngleRadians = offsetAngle * 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) + offsetAngleRadians; }, getDistanceFromCenterForValue: function(value) { var me = this; @@ -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'; From 1a63113bc0733f95db324b5498b6159256abbd34 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 17 Jul 2016 23:11:30 -0600 Subject: [PATCH 4/4] changed option name for radar chart from offsetAngle to startAngle. Added test to make sure correct angles are computed for all points in the radar chart (with and without startAngle option set). --- docs/05-Radar-Chart.md | 2 +- src/scales/scale.radialLinear.js | 8 +++---- test/scale.radialLinear.tests.js | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/docs/05-Radar-Chart.md b/docs/05-Radar-Chart.md index dbf3f3c57a2..e974d2a19c5 100644 --- a/docs/05-Radar-Chart.md +++ b/docs/05-Radar-Chart.md @@ -98,7 +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. -offsetAngle | Number | 0 | The number of degrees to rotate the chart clockwise. +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. diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 900ade4eac6..d0cb7f2c6d0 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -232,14 +232,14 @@ module.exports = function(Chart) { getIndexAngle: function(index) { var angleMultiplier = (Math.PI * 2) / this.getValueCount(); - var offsetAngle = this.chart.options && this.chart.options.offsetAngle ? - this.chart.options.offsetAngle : + var startAngle = this.chart.options && this.chart.options.startAngle ? + this.chart.options.startAngle : 0; - var offsetAngleRadians = offsetAngle * Math.PI * 2 / 360; + var startAngleRadians = startAngle * Math.PI * 2 / 360; // Start from the top instead of right, so remove a quarter of the circle - return index * angleMultiplier - (Math.PI / 2) + offsetAngleRadians; + return index * angleMultiplier - (Math.PI / 2) + startAngleRadians; }, getDistanceFromCenterForValue: function(value) { var me = this; diff --git a/test/scale.radialLinear.tests.js b/test/scale.radialLinear.tests.js index d7b61695eb2..bb84181e1a2 100644 --- a/test/scale.radialLinear.tests.js +++ b/test/scale.radialLinear.tests.js @@ -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); + } + }); });