mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Convert the radialLinear scale to derive from Core.scale. Radial linear scale is now fit using the scale service. Added tests for the radialLinear scale.
This commit is contained in:
parent
be4facdea9
commit
bc7d1d39fd
@ -97,13 +97,6 @@
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
|
||||
Chart.scaleService.update(this, this.chart.width, this.chart.height);
|
||||
//this.chart.scale.setScaleSize();
|
||||
this.chart.scale.calculateRange();
|
||||
this.chart.scale.generateTicks();
|
||||
this.chart.scale.buildYLabels();
|
||||
|
||||
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
|
||||
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
|
||||
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;
|
||||
|
||||
@ -120,11 +120,6 @@
|
||||
var scale = this.chart.scale;
|
||||
var scaleBase;
|
||||
|
||||
scale.setScaleSize();
|
||||
scale.calculateRange();
|
||||
scale.generateTicks();
|
||||
scale.buildYLabels();
|
||||
|
||||
if (scale.min < 0 && scale.max < 0) {
|
||||
scaleBase = scale.getPointPositionForValue(0, scale.max);
|
||||
} else if (scale.min > 0 && scale.max > 0) {
|
||||
|
||||
@ -157,6 +157,8 @@
|
||||
});
|
||||
|
||||
this.scale = scale;
|
||||
|
||||
this.scales['radialScale'] = scale;
|
||||
}
|
||||
|
||||
Chart.scaleService.update(this, this.chart.width, this.chart.height);
|
||||
|
||||
@ -46,6 +46,11 @@
|
||||
return scaleInstance.options.position == "bottom";
|
||||
});
|
||||
|
||||
// Scales that overlay the chartarea such as the radialLinear scale
|
||||
var chartAreaScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "chartArea";
|
||||
});
|
||||
|
||||
// Essentially we now have any number of scales on each of the 4 sides.
|
||||
// Our canvas looks like the following.
|
||||
// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
|
||||
@ -71,6 +76,7 @@
|
||||
// 6. Refit each axis
|
||||
// 7. Position each axis in the final location
|
||||
// 8. Tell the chart the final location of the chart area
|
||||
// 9. Tell any axes that overlay the chart area the positions of the chart area
|
||||
|
||||
// Step 1
|
||||
var chartWidth = width / 2; // min 50%
|
||||
@ -311,6 +317,16 @@
|
||||
right: totalLeftWidth + maxChartWidth,
|
||||
bottom: totalTopHeight + maxChartHeight,
|
||||
};
|
||||
|
||||
// Step 9
|
||||
helpers.each(chartAreaScales, function(scaleInstance) {
|
||||
scaleInstance.left = chartInstance.chartArea.left;
|
||||
scaleInstance.top = chartInstance.chartArea.top;
|
||||
scaleInstance.right = chartInstance.chartArea.right;
|
||||
scaleInstance.bottom = chartInstance.chartArea.bottom;
|
||||
|
||||
scaleInstance.update(maxChartWidth, maxChartHeight);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -10,35 +10,17 @@
|
||||
|
||||
//Boolean - Whether to animate scaling the chart from the centre
|
||||
animate: true,
|
||||
|
||||
lineArc: false,
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
show: true,
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
lineWidth: 1,
|
||||
},
|
||||
position: "chartArea",
|
||||
|
||||
angleLines: {
|
||||
show: true,
|
||||
color: "rgba(0,0,0, 0.1)",
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
lineWidth: 1
|
||||
},
|
||||
|
||||
// scale numbers
|
||||
reverse: false,
|
||||
beginAtZero: true,
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
show: true,
|
||||
template: "<%=value.toLocaleString()%>",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
|
||||
ticks: {
|
||||
//Boolean - Show a backdrop to the scale label
|
||||
showLabelBackdrop: true,
|
||||
|
||||
@ -67,29 +49,21 @@
|
||||
},
|
||||
};
|
||||
|
||||
var LinearRadialScale = Chart.Element.extend({
|
||||
initialize: function() {
|
||||
this.height = this.chart.height;
|
||||
this.width = this.chart.width;
|
||||
this.xCenter = this.chart.width / 2;
|
||||
this.yCenter = this.chart.height / 2;
|
||||
this.size = helpers.min([this.height, this.width]);
|
||||
this.labels = this.data.labels;
|
||||
this.drawingArea = (this.options.display) ? (this.size / 2) - (this.options.labels.fontSize / 2 + this.options.labels.backdropPaddingY) : (this.size / 2);
|
||||
},
|
||||
var LinearRadialScale = Chart.Scale.extend({
|
||||
getValueCount: function() {
|
||||
return this.data.labels.length;
|
||||
},
|
||||
update: function() {
|
||||
if (!this.options.lineArc) {
|
||||
this.setScaleSize();
|
||||
} else {
|
||||
this.drawingArea = (this.options.display) ? (this.size / 2) - (this.fontSize / 2 + this.backdropPaddingY) : (this.size / 2);
|
||||
}
|
||||
|
||||
this.buildYLabels();
|
||||
setDimensions: function() {
|
||||
// Set the unconstrained dimension before label rotation
|
||||
this.width = this.maxWidth;
|
||||
this.height = this.maxHeight;
|
||||
this.xCenter = Math.round(this.width / 2);
|
||||
this.yCenter = Math.round(this.height / 2);
|
||||
|
||||
var minSize = helpers.min([this.height, this.width]);
|
||||
this.drawingArea = (this.options.display) ? (minSize / 2) - (this.options.ticks.fontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
|
||||
},
|
||||
calculateRange: function() {
|
||||
buildTicks: function() {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
@ -110,105 +84,72 @@
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
generateTicks: function() {
|
||||
// We need to decide how many ticks we are going to have. Each tick draws a grid line.
|
||||
// There are two possibilities. The first is that the user has manually overridden the scale
|
||||
// calculations in which case the job is easy. The other case is that we have to do it ourselves
|
||||
//
|
||||
// We assume at this point that the scale object has been updated with the following values
|
||||
// by the chart.
|
||||
// min: this is the minimum value of the scale
|
||||
// max: this is the maximum value of the scale
|
||||
// options: contains the options for the scale. This is referenced from the user settings
|
||||
// rather than being cloned. This ensures that updates always propogate to a redraw
|
||||
|
||||
// Reset the ticks array. Later on, we will draw a grid line at these positions
|
||||
// The array simply contains the numerical value of the spots where ticks will be
|
||||
if (this.min === this.max) {
|
||||
this.min--;
|
||||
this.max++;
|
||||
}
|
||||
|
||||
this.ticks = [];
|
||||
|
||||
if (this.options.override) {
|
||||
// The user has specified the manual override. We use <= instead of < so that
|
||||
// we get the final line
|
||||
for (var i = 0; i <= this.options.override.steps; ++i) {
|
||||
var value = this.options.override.start + (i * this.options.override.stepWidth);
|
||||
this.ticks.push(value);
|
||||
}
|
||||
} else {
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
var maxTicks = Math.min(11, Math.ceil(this.drawingArea / (1.5 * this.options.ticks.fontSize)));
|
||||
maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks
|
||||
|
||||
var maxTicks = Math.min(11, Math.ceil(this.drawingArea / (2 * this.options.labels.fontSize)));
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
// Make sure we always have at least 2 ticks
|
||||
maxTicks = Math.max(2, maxTicks);
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
if (this.options.ticks.beginAtZero) {
|
||||
var minSign = helpers.sign(this.min);
|
||||
var maxSign = helpers.sign(this.max);
|
||||
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
if (this.options.beginAtZero) {
|
||||
var minSign = helpers.sign(this.min);
|
||||
var maxSign = helpers.sign(this.max);
|
||||
|
||||
if (minSign < 0 && maxSign < 0) {
|
||||
// move the top up to 0
|
||||
this.max = 0;
|
||||
} else if (minSign > 0 && maxSign > 0) {
|
||||
// move the botttom down to 0
|
||||
this.min = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
var niceMin = Math.floor(this.min / spacing) * spacing;
|
||||
var niceMax = Math.ceil(this.max / spacing) * spacing;
|
||||
|
||||
// Put the values into the ticks array
|
||||
for (var j = niceMin; j <= niceMax; j += spacing) {
|
||||
this.ticks.push(j);
|
||||
if (minSign < 0 && maxSign < 0) {
|
||||
// move the top up to 0
|
||||
this.max = 0;
|
||||
} else if (minSign > 0 && maxSign > 0) {
|
||||
// move the botttom down to 0
|
||||
this.min = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.position == "left" || this.options.position == "right") {
|
||||
// We are in a vertical orientation. The top value is the highest. So reverse the array
|
||||
this.ticks.reverse();
|
||||
var niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
var niceMin = Math.floor(this.min / spacing) * spacing;
|
||||
var niceMax = Math.ceil(this.max / spacing) * spacing;
|
||||
|
||||
// Put the values into the ticks array
|
||||
for (var j = niceMin; j <= niceMax; j += spacing) {
|
||||
this.ticks.push(j);
|
||||
}
|
||||
|
||||
// At this point, we need to update our max and min given the tick values since we have expanded the
|
||||
// range of the scale
|
||||
this.max = helpers.max(this.ticks);
|
||||
this.min = helpers.min(this.ticks);
|
||||
},
|
||||
buildYLabels: function() {
|
||||
this.yLabels = [];
|
||||
|
||||
helpers.each(this.ticks, function(tick, index, ticks) {
|
||||
var label;
|
||||
if (this.options.ticks.reverse) {
|
||||
this.ticks.reverse();
|
||||
|
||||
if (this.options.labels.userCallback) {
|
||||
// If the user provided a callback for label generation, use that as first priority
|
||||
label = this.options.labels.userCallback(tick, index, ticks);
|
||||
} else if (this.options.labels.template) {
|
||||
// else fall back to the template string
|
||||
label = helpers.template(this.options.labels.template, {
|
||||
value: tick
|
||||
});
|
||||
}
|
||||
this.start = this.max;
|
||||
this.end = this.min;
|
||||
} else {
|
||||
this.start = this.min;
|
||||
this.end = this.max;
|
||||
}
|
||||
|
||||
this.yLabels.push(label ? label : "");
|
||||
}, this);
|
||||
this.zeroLineIndex = this.ticks.indexOf(0);
|
||||
},
|
||||
getCircumference: function() {
|
||||
return ((Math.PI * 2) / this.getValueCount());
|
||||
},
|
||||
setScaleSize: function() {
|
||||
fit: function() {
|
||||
/*
|
||||
* Right, this is really confusing and there is a lot of maths going on here
|
||||
* The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
|
||||
@ -260,8 +201,8 @@
|
||||
for (i = 0; i < this.getValueCount(); i++) {
|
||||
// 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(helpers.template(this.options.labels.template, {
|
||||
value: this.labels[i]
|
||||
textWidth = this.ctx.measureText(helpers.template(this.options.ticks.template, {
|
||||
value: this.data.labels[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
|
||||
@ -292,35 +233,29 @@
|
||||
}
|
||||
|
||||
xProtrusionLeft = furthestLeft;
|
||||
|
||||
xProtrusionRight = Math.ceil(furthestRight - this.width);
|
||||
|
||||
furthestRightAngle = this.getIndexAngle(furthestRightIndex);
|
||||
|
||||
furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
|
||||
|
||||
radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2);
|
||||
|
||||
radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2);
|
||||
|
||||
// Ensure we actually need to reduce the size of the chart
|
||||
radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
|
||||
radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
|
||||
|
||||
this.drawingArea = largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2;
|
||||
|
||||
//this.drawingArea = min([maxWidthRadius, (this.height - (2 * (this.pointLabelFontSize + 5)))/2])
|
||||
this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2);
|
||||
this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
|
||||
|
||||
},
|
||||
setCenterPoint: function(leftMovement, rightMovement) {
|
||||
|
||||
var maxRight = this.width - rightMovement - this.drawingArea,
|
||||
maxLeft = leftMovement + this.drawingArea;
|
||||
|
||||
this.xCenter = (maxLeft + maxRight) / 2;
|
||||
this.xCenter = Math.round(((maxLeft + maxRight) / 2) + this.left);
|
||||
// Always vertically in the centre as the text height doesn't change
|
||||
this.yCenter = (this.height / 2);
|
||||
this.yCenter = Math.round((this.height / 2) + this.top);
|
||||
},
|
||||
|
||||
getIndexAngle: function(index) {
|
||||
@ -352,7 +287,7 @@
|
||||
draw: function() {
|
||||
if (this.options.display) {
|
||||
var ctx = this.ctx;
|
||||
helpers.each(this.yLabels, function(label, index) {
|
||||
helpers.each(this.ticks, function(label, index) {
|
||||
// Don't draw a centre value (if it is minimum)
|
||||
if (index > 0 || this.options.reverse) {
|
||||
var yCenterOffset = this.getDistanceFromCenterForValue(this.ticks[index]);
|
||||
@ -385,23 +320,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.labels.show) {
|
||||
ctx.font = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
if (this.options.ticks.show) {
|
||||
ctx.font = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
|
||||
if (this.options.labels.showLabelBackdrop) {
|
||||
if (this.options.ticks.showLabelBackdrop) {
|
||||
var labelWidth = ctx.measureText(label).width;
|
||||
ctx.fillStyle = this.options.labels.backdropColor;
|
||||
ctx.fillStyle = this.options.ticks.backdropColor;
|
||||
ctx.fillRect(
|
||||
this.xCenter - labelWidth / 2 - this.options.labels.backdropPaddingX,
|
||||
yHeight - this.fontSize / 2 - this.options.labels.backdropPaddingY,
|
||||
labelWidth + this.options.labels.backdropPaddingX * 2,
|
||||
this.options.labels.fontSize + this.options.labels.backdropPaddingY * 2
|
||||
this.xCenter - labelWidth / 2 - this.options.ticks.backdropPaddingX,
|
||||
yHeight - this.options.ticks.fontSize / 2 - this.options.ticks.backdropPaddingY,
|
||||
labelWidth + this.options.ticks.backdropPaddingX * 2,
|
||||
this.options.ticks.fontSize + this.options.ticks.backdropPaddingY * 2
|
||||
);
|
||||
}
|
||||
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = this.options.labels.fontColor;
|
||||
ctx.fillStyle = this.options.ticks.fontColor;
|
||||
ctx.fillText(label, this.xCenter, yHeight);
|
||||
}
|
||||
}
|
||||
@ -425,8 +360,8 @@
|
||||
ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily);
|
||||
ctx.fillStyle = this.options.pointLabels.fontColor;
|
||||
|
||||
var labelsCount = this.labels.length,
|
||||
halfLabelsCount = this.labels.length / 2,
|
||||
var labelsCount = this.data.labels.length,
|
||||
halfLabelsCount = this.data.labels.length / 2,
|
||||
quarterLabelsCount = halfLabelsCount / 2,
|
||||
upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
|
||||
exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
|
||||
@ -449,7 +384,7 @@
|
||||
ctx.textBaseline = 'top';
|
||||
}
|
||||
|
||||
ctx.fillText(this.labels[i], pointLabelPosition.x, pointLabelPosition.y);
|
||||
ctx.fillText(this.data.labels[i], pointLabelPosition.x, pointLabelPosition.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +68,7 @@
|
||||
clearRect: function() {},
|
||||
closePath: function() {},
|
||||
fill: function() {},
|
||||
fillRect: function() {},
|
||||
fillText: function() {},
|
||||
lineTo: function(x, y) {},
|
||||
measureText: function(text) {
|
||||
|
||||
773
test/scale.radialLinear.tests.js
Normal file
773
test/scale.radialLinear.tests.js
Normal file
@ -0,0 +1,773 @@
|
||||
// Tests for the radial linear scale used by the polar area and radar charts
|
||||
describe('Test the radial linear scale', function() {
|
||||
it('Should register the constructor with the scale service', function() {
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
expect(Constructor).not.toBe(undefined);
|
||||
expect(typeof Constructor).toBe('function');
|
||||
});
|
||||
|
||||
it('Should have the correct default config', function() {
|
||||
var defaultConfig = Chart.scaleService.getScaleDefaults('radialLinear');
|
||||
expect(defaultConfig).toEqual({
|
||||
angleLines: {
|
||||
show: true,
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
lineWidth: 1
|
||||
},
|
||||
animate: true,
|
||||
display: true,
|
||||
gridLines: {
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
drawOnChartArea: true,
|
||||
drawTicks: true,
|
||||
lineWidth: 1,
|
||||
offsetGridLines: false,
|
||||
show: true,
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
zeroLineWidth: 1,
|
||||
},
|
||||
lineArc: false,
|
||||
pointLabels: {
|
||||
fontColor: "#666",
|
||||
fontFamily: "'Arial'",
|
||||
fontSize: 10,
|
||||
fontStyle: "normal",
|
||||
},
|
||||
position: "chartArea",
|
||||
scaleLabel: {
|
||||
fontColor: '#666',
|
||||
fontFamily: 'Helvetica Neue',
|
||||
fontSize: 12,
|
||||
fontStyle: 'normal',
|
||||
labelString: '',
|
||||
show: false,
|
||||
},
|
||||
ticks: {
|
||||
backdropColor: "rgba(255,255,255,0.75)",
|
||||
backdropPaddingY: 2,
|
||||
backdropPaddingX: 2,
|
||||
beginAtZero: false,
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
maxRotation: 90,
|
||||
minRotation: 20,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
showLabelBackdrop: true,
|
||||
show: true,
|
||||
template: "<%=value%>",
|
||||
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should correctly determine the max & min data values', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, -5, 78, -100]
|
||||
}, {
|
||||
yAxisID: scaleID,
|
||||
data: [150]
|
||||
}],
|
||||
labels: ['lablel1', 'label2', 'label3', 'label4', 'label5', 'label6']
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: Chart.scaleService.getScaleDefaults('radialLinear'), // use default config for scale
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.update(200, 300);
|
||||
expect(scale.min).toBe(-100);
|
||||
expect(scale.max).toBe(200);
|
||||
});
|
||||
|
||||
it('Should ensure that the scale has a max and min that are not equal', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [],
|
||||
labels: []
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: Chart.scaleService.getScaleDefaults('radialLinear'), // use default config for scale
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.update(200, 300);
|
||||
expect(scale.min).toBe(-1);
|
||||
expect(scale.max).toBe(1);
|
||||
});
|
||||
|
||||
it('should forcibly include 0 in the range if the beginAtZero option is used', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [20, 30, 40, 50]
|
||||
}],
|
||||
labels: [],
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
config.ticks.beginAtZero = false;
|
||||
scale.update(400, 400);
|
||||
expect(scale.ticks).toEqual(['20', '25', '30', '35', '40', '45', '50']);
|
||||
|
||||
config.ticks.beginAtZero = true;
|
||||
scale.update(400, 400);
|
||||
expect(scale.ticks).toEqual(['0', '5', '10', '15', '20', '25', '30', '35', '40', '45', '50']);
|
||||
|
||||
mockData.datasets[0].data = [-20, -30, -40, -50];
|
||||
scale.update(400, 400);
|
||||
expect(scale.ticks).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20', '-15', '-10', '-5', '0']);
|
||||
|
||||
config.ticks.beginAtZero = false;
|
||||
scale.update(400, 400);
|
||||
expect(scale.ticks).toEqual(['-50', '-45', '-40', '-35', '-30', '-25', '-20']);
|
||||
});
|
||||
|
||||
it('Should generate tick marks in the correct order in reversed mode', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, 25, 78]
|
||||
}],
|
||||
labels: []
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
config.ticks.reverse = true;
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.update(200, 300);
|
||||
|
||||
// Reverse mode makes this count up
|
||||
expect(scale.ticks).toEqual(['80', '60', '40', '20', '0']);
|
||||
expect(scale.start).toBe(80);
|
||||
expect(scale.end).toBe(0);
|
||||
});
|
||||
|
||||
it('Should build labels using the user supplied callback', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, 25, 78]
|
||||
}],
|
||||
labels: []
|
||||
};
|
||||
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
config.ticks.userCallback = function(value, index) {
|
||||
return index.toString();
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.update(200, 300);
|
||||
|
||||
// Just the index
|
||||
expect(scale.ticks).toEqual(['0', '1', '2', '3', '4']);
|
||||
});
|
||||
|
||||
it('should correctly set the center point', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, 25, 78]
|
||||
}],
|
||||
labels: ['point1', 'point2', 'point3', 'point4', 'point5'] // used in radar charts which use the same scales
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.left = 10;
|
||||
scale.right = 210;
|
||||
scale.top = 5;
|
||||
scale.bottom = 305;
|
||||
scale.update(200, 300);
|
||||
|
||||
expect(scale.drawingArea).toBe(36);
|
||||
expect(scale.xCenter).toBe(110);
|
||||
expect(scale.yCenter).toBe(155);
|
||||
});
|
||||
|
||||
it('should get the correct distance from the center point', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, 25, 78]
|
||||
}],
|
||||
labels: ['point1', 'point2', 'point3', 'point4', 'point5'] // used in radar charts which use the same scales
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.left = 0;
|
||||
scale.right = 200;
|
||||
scale.top = 0;
|
||||
scale.bottom = 300;
|
||||
scale.update(200, 300);
|
||||
|
||||
expect(scale.getDistanceFromCenterForValue(scale.min)).toBe(0);
|
||||
expect(scale.getDistanceFromCenterForValue(scale.max)).toBe(36);
|
||||
expect(scale.getPointPositionForValue(1, 5)).toEqual({
|
||||
x: 102.13987716166409,
|
||||
y: 149.30471176265638,
|
||||
});
|
||||
|
||||
config.reverse = true;
|
||||
|
||||
scale.update(200, 300);
|
||||
|
||||
expect(scale.getDistanceFromCenterForValue(scale.min)).toBe(36);
|
||||
expect(scale.getDistanceFromCenterForValue(scale.max)).toBe(0);
|
||||
});
|
||||
|
||||
it('should draw correctly when there are no point labels', function() {
|
||||
var scaleID = 'myScale';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
yAxisID: scaleID,
|
||||
data: [10, 5, 0, 25, 78]
|
||||
}, ],
|
||||
labels: ['point1', 'point2', 'point3', 'point4', 'point5'] // used in radar charts which use the same scales
|
||||
};
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
config.lineArc = true;
|
||||
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scale = new Constructor({
|
||||
ctx: mockContext,
|
||||
options: config,
|
||||
data: mockData,
|
||||
id: scaleID,
|
||||
});
|
||||
|
||||
scale.left = 0;
|
||||
scale.right = 200;
|
||||
scale.top = 0;
|
||||
scale.bottom = 300;
|
||||
scale.update(200, 300);
|
||||
|
||||
scale.draw();
|
||||
|
||||
var expected = [{
|
||||
"name": "measureText",
|
||||
"args": ["0"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["80"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["point1"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["point2"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["point3"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["point4"]
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["point5"]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "arc",
|
||||
"args": [100, 150, 9, 0, 6.283185307179586]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["20"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 133, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["20", 100, 141]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "arc",
|
||||
"args": [100, 150, 18, 0, 6.283185307179586]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["40"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 124, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["40", 100, 132]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "arc",
|
||||
"args": [100, 150, 27, 0, 6.283185307179586]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["60"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 115, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["60", 100, 123]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "arc",
|
||||
"args": [100, 150, 36, 0, 6.283185307179586]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["80"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 106, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["80", 100, 114]
|
||||
}];
|
||||
expect(mockContext.getCalls()).toEqual(expected);
|
||||
|
||||
mockContext.resetCalls();
|
||||
config.lineArc = false;
|
||||
scale.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 141]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [108.55950864665638, 147.21884705062547]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [105.29006727063226, 157.28115294937453]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [94.70993272936774, 157.28115294937453]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [91.44049135334362, 147.21884705062547]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["20"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 133, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["20", 100, 141]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 132]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [117.11901729331277, 144.43769410125094]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [110.58013454126451, 164.56230589874906]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [89.41986545873549, 164.56230589874906]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [82.88098270668723, 144.43769410125094]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["40"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 124, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["40", 100, 132]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 123]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [125.67852593996915, 141.6565411518764]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [115.87020181189678, 171.8434588481236]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [84.12979818810322, 171.8434588481236]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [74.32147406003085, 141.6565411518764]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["60"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 115, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["60", 100, 123]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 114]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [134.23803458662553, 138.87538820250188]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [121.16026908252903, 179.12461179749812]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [78.83973091747097, 179.12461179749812]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [65.76196541337447, 138.8753882025019]
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "measureText",
|
||||
"args": ["80"]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["rgba(255,255,255,0.75)"]
|
||||
}, {
|
||||
"name": "fillRect",
|
||||
"args": [88, 106, 24, 16]
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["80", 100, 114]
|
||||
}, {
|
||||
"name": "setLineWidth",
|
||||
"args": [1]
|
||||
}, {
|
||||
"name": "setStrokeStyle",
|
||||
"args": ["rgba(0, 0, 0, 0.1)"]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 150]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [65.76196541337447, 138.8753882025019]
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["point5", 61.0066828318987, 137.33030323062715]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 150]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [78.83973091747097, 179.12461179749812]
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["point4", 75.9008046560086, 183.16969676937285]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 150]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [121.16026908252903, 179.12461179749812]
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["point3", 124.0991953439914, 183.16969676937285]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 150]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [134.23803458662553, 138.87538820250188]
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["point2", 138.9933171681013, 137.33030323062715]
|
||||
}, {
|
||||
"name": "beginPath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "moveTo",
|
||||
"args": [100, 150]
|
||||
}, {
|
||||
"name": "lineTo",
|
||||
"args": [100, 114]
|
||||
}, {
|
||||
"name": "stroke",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "closePath",
|
||||
"args": []
|
||||
}, {
|
||||
"name": "setFillStyle",
|
||||
"args": ["#666"]
|
||||
}, {
|
||||
"name": "fillText",
|
||||
"args": ["point1", 100, 109]
|
||||
}]);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user