mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-09 01:36:51 +01:00
Better default tick rotation and tick autoskip settings (#2258)
* Better default tick rotation and tick autoskip settings * scale.time: Use ctx to measure label, and <= instead of < for unit fitting * Test Changes * Passing Tests with new defaults
This commit is contained in:
@@ -31,13 +31,13 @@ module.exports = function(Chart) {
|
||||
// label settings
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20,
|
||||
autoSkipPadding: 0,
|
||||
callback: function(value) {
|
||||
return '' + value;
|
||||
}
|
||||
@@ -682,4 +682,4 @@ module.exports = function(Chart) {
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -62,7 +62,7 @@ module.exports = function(Chart) {
|
||||
}
|
||||
},
|
||||
ticks: {
|
||||
autoSkip: false,
|
||||
autoSkip: false
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,6 +137,13 @@ module.exports = function(Chart) {
|
||||
},
|
||||
buildTicks: function(index) {
|
||||
|
||||
this.ctx.save();
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
||||
this.ctx.font = tickLabelFont;
|
||||
|
||||
this.ticks = [];
|
||||
this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
|
||||
this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)
|
||||
@@ -149,16 +156,15 @@ module.exports = function(Chart) {
|
||||
this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1);
|
||||
} else {
|
||||
// Determine the smallest needed unit of the time
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
|
||||
|
||||
|
||||
// Crude approximation of what the label length might be
|
||||
var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []);
|
||||
var tickLabelWidth = tempFirstLabel.length * tickFontSize;
|
||||
var tickLabelWidth = this.ctx.measureText(tempFirstLabel).width;
|
||||
var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation));
|
||||
var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation));
|
||||
tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
|
||||
var labelCapacity = innerWidth / (tickLabelWidth + 10);
|
||||
var labelCapacity = innerWidth / (tickLabelWidth);
|
||||
|
||||
// Start as small as possible
|
||||
this.tickUnit = 'millisecond';
|
||||
@@ -176,7 +182,7 @@ module.exports = function(Chart) {
|
||||
if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
|
||||
// Use one of the prefedined steps
|
||||
for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
|
||||
if (unitDefinition.steps[idx] > Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
|
||||
if (unitDefinition.steps[idx] >= Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
|
||||
this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]);
|
||||
break;
|
||||
}
|
||||
@@ -257,6 +263,7 @@ module.exports = function(Chart) {
|
||||
this.lastTick = this.ticks[this.ticks.length - 1].clone();
|
||||
}
|
||||
}
|
||||
this.ctx.restore();
|
||||
},
|
||||
// Get tooltip label
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
@@ -335,4 +342,4 @@ module.exports = function(Chart) {
|
||||
});
|
||||
Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -230,14 +230,14 @@ describe('Core helper tests', function() {
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
},
|
||||
type: 'linear'
|
||||
}, {
|
||||
@@ -260,14 +260,14 @@ describe('Core helper tests', function() {
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
},
|
||||
type: 'linear'
|
||||
}]
|
||||
|
||||
@@ -49,21 +49,21 @@ describe('Test the layout service', function() {
|
||||
left: 50,
|
||||
right: 250,
|
||||
top: 0,
|
||||
bottom: 81.0423977855504,
|
||||
bottom: 83.6977778440511,
|
||||
});
|
||||
|
||||
// Is xScale at the right spot
|
||||
expect(xScale.left).toBe(50);
|
||||
expect(xScale.right).toBe(250);
|
||||
expect(xScale.top).toBe(81.0423977855504);
|
||||
expect(xScale.top).toBe(83.6977778440511);
|
||||
expect(xScale.bottom).toBe(150);
|
||||
expect(xScale.labelRotation).toBe(55);
|
||||
expect(xScale.labelRotation).toBe(50);
|
||||
|
||||
// Is yScale at the right spot
|
||||
expect(yScale.left).toBe(0);
|
||||
expect(yScale.right).toBe(50);
|
||||
expect(yScale.top).toBe(0);
|
||||
expect(yScale.bottom).toBe(81.0423977855504);
|
||||
expect(yScale.bottom).toBe(83.6977778440511);
|
||||
});
|
||||
|
||||
it('should fit scales that are in the top and right positions', function() {
|
||||
@@ -116,7 +116,7 @@ describe('Test the layout service', function() {
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 0,
|
||||
right: 200,
|
||||
top: 68.9576022144496,
|
||||
top: 66.3022221559489,
|
||||
bottom: 150,
|
||||
});
|
||||
|
||||
@@ -124,13 +124,13 @@ describe('Test the layout service', function() {
|
||||
expect(xScale.left).toBe(0);
|
||||
expect(xScale.right).toBe(200);
|
||||
expect(xScale.top).toBe(0);
|
||||
expect(xScale.bottom).toBe(68.9576022144496);
|
||||
expect(xScale.labelRotation).toBe(55);
|
||||
expect(xScale.bottom).toBe(66.3022221559489);
|
||||
expect(xScale.labelRotation).toBe(50);
|
||||
|
||||
// Is yScale at the right spot
|
||||
expect(yScale.left).toBe(200);
|
||||
expect(yScale.right).toBe(250);
|
||||
expect(yScale.top).toBe(68.9576022144496);
|
||||
expect(yScale.top).toBe(66.3022221559489);
|
||||
expect(yScale.bottom).toBe(150);
|
||||
});
|
||||
|
||||
@@ -196,30 +196,30 @@ describe('Test the layout service', function() {
|
||||
left: 110,
|
||||
right: 250,
|
||||
top: 0,
|
||||
bottom: 75,
|
||||
bottom: 83.6977778440511,
|
||||
});
|
||||
|
||||
// Is xScale at the right spot
|
||||
expect(xScale.left).toBe(110);
|
||||
expect(xScale.right).toBe(250);
|
||||
expect(xScale.top).toBe(75);
|
||||
expect(xScale.top).toBe(83.6977778440511);
|
||||
expect(xScale.bottom).toBe(150);
|
||||
|
||||
// Are yScales at the right spot
|
||||
expect(yScale1.left).toBe(0);
|
||||
expect(yScale1.right).toBe(50);
|
||||
expect(yScale1.top).toBe(0);
|
||||
expect(yScale1.bottom).toBe(75);
|
||||
expect(yScale1.bottom).toBe(83.6977778440511);
|
||||
|
||||
expect(yScale2.left).toBe(50);
|
||||
expect(yScale2.right).toBe(110);
|
||||
expect(yScale2.top).toBe(0);
|
||||
expect(yScale2.bottom).toBe(75);
|
||||
expect(yScale2.bottom).toBe(83.6977778440511);
|
||||
});
|
||||
|
||||
// This is an oddball case. What happens is, when the scales are fit the first time they must fit within the assigned size. In this case,
|
||||
// the labels on the xScale need to rotate to fit. However, when the scales are fit again after the width of the left axis is determined,
|
||||
// the labels do not need to rotate. Previously, the chart was too small because the chartArea did not expand to take up the space freed up
|
||||
// the labels on the xScale need to rotate to fit. However, when the scales are fit again after the width of the left axis is determined,
|
||||
// the labels do not need to rotate. Previously, the chart was too small because the chartArea did not expand to take up the space freed up
|
||||
// due to the lack of label rotation
|
||||
it('should fit scales that overlap the chart area', function() {
|
||||
var chartInstance = {
|
||||
@@ -337,13 +337,13 @@ describe('Test the layout service', function() {
|
||||
left: 60,
|
||||
right: 250,
|
||||
top: 54.495963211660246,
|
||||
bottom: 80.0664716027288,
|
||||
bottom: 83.6977778440511
|
||||
});
|
||||
|
||||
// Are xScales at the right spot
|
||||
expect(xScale1.left).toBe(60);
|
||||
expect(xScale1.right).toBe(250);
|
||||
expect(xScale1.top).toBeCloseTo(80.06, 1e-3);
|
||||
expect(xScale1.top).toBeCloseTo(83.69, 1e-3);
|
||||
expect(xScale1.bottom).toBe(150);
|
||||
|
||||
expect(xScale2.left).toBe(0);
|
||||
@@ -355,6 +355,6 @@ describe('Test the layout service', function() {
|
||||
expect(yScale.left).toBe(0);
|
||||
expect(yScale.right).toBe(60);
|
||||
expect(yScale.top).toBeCloseTo(54.49, 1e-3);
|
||||
expect(yScale.bottom).toBeCloseTo(80.06, 1e-3);
|
||||
expect(yScale.bottom).toBeCloseTo(83.69, 1e-3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,23 +20,23 @@ describe('Category scale tests', function() {
|
||||
offsetGridLines: false,
|
||||
display: true,
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
zeroLineWidth: 1,
|
||||
zeroLineWidth: 1
|
||||
},
|
||||
position: "bottom",
|
||||
scaleLabel: {
|
||||
labelString: '',
|
||||
display: false,
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
}
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('Category scale tests', function() {
|
||||
});
|
||||
|
||||
scale.buildTicks();
|
||||
|
||||
|
||||
expect(scale.getLabelForIndex(1)).toBe('tick2');
|
||||
});
|
||||
|
||||
@@ -340,4 +340,4 @@ describe('Category scale tests', function() {
|
||||
expect(scale.getPixelForValue(0, 3, 0, false)).toBe(199);
|
||||
expect(scale.getPixelForValue(0, 3, 0, true)).toBe(199);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,14 +28,14 @@ describe('Linear Scale', function() {
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: defaultConfig.ticks.callback, // make this work nicer, then check below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2049,4 +2049,4 @@ describe('Linear Scale', function() {
|
||||
"args": []
|
||||
}])
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,14 +27,14 @@ describe('Logarithmic Scale tests', function() {
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
},
|
||||
});
|
||||
|
||||
@@ -626,4 +626,4 @@ describe('Logarithmic Scale tests', function() {
|
||||
expect(horizontalScale.getPixelForValue(10, 0, 0)).toBeCloseTo(57.5, 1e-4); // halfway
|
||||
expect(horizontalScale.getPixelForValue(0, 0, 0)).toBe(5); // 0 is invalid, put it on the left.
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('Test the radial linear scale', function() {
|
||||
backdropPaddingY: 2,
|
||||
backdropPaddingX: 2,
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
@@ -49,7 +49,7 @@ describe('Test the radial linear scale', function() {
|
||||
display: true,
|
||||
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -44,23 +44,23 @@ describe('Time scale tests', function() {
|
||||
offsetGridLines: false,
|
||||
display: true,
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
zeroLineWidth: 1,
|
||||
zeroLineWidth: 1
|
||||
},
|
||||
position: "bottom",
|
||||
scaleLabel: {
|
||||
labelString: '',
|
||||
display: false,
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
maxRotation: 90,
|
||||
maxRotation: 50,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below,
|
||||
autoSkip: false,
|
||||
autoSkipPadding: 20
|
||||
autoSkipPadding: 0
|
||||
},
|
||||
time: {
|
||||
parser: false,
|
||||
@@ -77,8 +77,8 @@ describe('Time scale tests', function() {
|
||||
'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
|
||||
'month': 'MMM YYYY', // Sept 2015
|
||||
'quarter': '[Q]Q - YYYY', // Q3
|
||||
'year': 'YYYY', // 2015
|
||||
},
|
||||
'year': 'YYYY' // 2015
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('Time scale tests', function() {
|
||||
scale.update(400, 50);
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
|
||||
expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
|
||||
});
|
||||
|
||||
it('should build ticks using date objects', function() {
|
||||
@@ -136,7 +136,7 @@ describe('Time scale tests', function() {
|
||||
scale.update(400, 50);
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
|
||||
expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
|
||||
});
|
||||
|
||||
it('should build ticks when the data is xy points', function() {
|
||||
@@ -187,7 +187,7 @@ describe('Time scale tests', function() {
|
||||
scale.update(400, 50);
|
||||
|
||||
// Counts down because the lines are drawn top to bottom
|
||||
expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
|
||||
expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 6, 2015', 'Jan 11, 2015' ]);
|
||||
});
|
||||
|
||||
it('should allow custom time parsers', function() {
|
||||
@@ -302,7 +302,7 @@ describe('Time scale tests', function() {
|
||||
});
|
||||
|
||||
scale.update(400, 50);
|
||||
expect(scale.ticks).toEqual(['Jan 1, 4AM', 'Jan 1, 4PM', 'Jan 2, 4AM', 'Jan 2, 4PM', 'Jan 3, 4AM', 'Jan 3, 4PM', 'Jan 4, 4AM', 'Jan 4, 4PM', 'Jan 5, 4AM', 'Jan 5, 6AM']);
|
||||
expect(scale.ticks).toEqual([ 'Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015' ]);
|
||||
});
|
||||
|
||||
it('should get the correct pixel for a value', function() {
|
||||
@@ -329,14 +329,14 @@ describe('Time scale tests', function() {
|
||||
scale.update(400, 50);
|
||||
|
||||
expect(scale.width).toBe(400);
|
||||
expect(scale.height).toBe(50);
|
||||
expect(scale.height).toBe(28);
|
||||
scale.left = 0;
|
||||
scale.right = 400;
|
||||
scale.top = 10;
|
||||
scale.bottom = 38;
|
||||
|
||||
expect(scale.getPixelForValue('', 0, 0)).toBe(128);
|
||||
expect(scale.getPixelForValue('', 6, 0)).toBe(380);
|
||||
expect(scale.getPixelForValue('', 0, 0)).toBe(81);
|
||||
expect(scale.getPixelForValue('', 6, 0)).toBe(323);
|
||||
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('time'));
|
||||
verticalScaleConfig.position = "left";
|
||||
@@ -385,7 +385,7 @@ describe('Time scale tests', function() {
|
||||
scale.update(400, 50);
|
||||
|
||||
expect(scale.width).toBe(400);
|
||||
expect(scale.height).toBe(50);
|
||||
expect(scale.height).toBe(28);
|
||||
scale.left = 0;
|
||||
scale.right = 400;
|
||||
scale.top = 10;
|
||||
|
||||
Reference in New Issue
Block a user