var prev, curr, i, ilen;
for (i = 1, ilen = pixels.length; i < ilen; ++i) {
- min = Math.min(min, pixels[i] - pixels[i - 1]);
+ min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
}
for (i = 0, ilen = ticks.length; i < ilen; ++i) {
if (prev === null) {
// first data: its size is double based on the next point or,
- // if it's also the last data, we use the scale end extremity.
- prev = curr - (next === null ? ruler.end - curr : next - curr);
+ // if it's also the last data, we use the scale size.
+ prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
}
if (next === null) {
next = curr + curr - prev;
}
- start = curr - ((curr - prev) / 2) * percent;
- size = ((next - prev) / 2) * percent;
+ start = curr - (curr - Math.min(prev, next)) / 2 * percent;
+ size = Math.abs(next - prev) / 2 * percent;
return {
chunk: size / ruler.stackCount,
}
/**
- * Returns the end and start offsets from edges in the form of {start, end}.
+ * Returns the start and end offsets from edges in the form of {start, end}
+ * where each value is a relative width to the scale and ranges between 0 and 1.
+ * They add extra margins on the both sides by scaling down the original scale.
* Offsets are added when the `offset` option is true.
*/
function computeOffsets(table, ticks, min, max, options) {
var start = 0;
var end = 0;
- var upper, lower;
+ var first, last;
if (options.offset && ticks.length) {
if (!options.time.min) {
- upper = ticks.length > 1 ? ticks[1] : max;
- lower = ticks[0];
- start = (
- interpolate(table, 'time', upper, 'pos') -
- interpolate(table, 'time', lower, 'pos')
- ) / 2;
+ first = interpolate(table, 'time', ticks[0], 'pos');
+ if (ticks.length === 1) {
+ start = 1 - first;
+ } else {
+ start = (interpolate(table, 'time', ticks[1], 'pos') - first) / 2;
+ }
}
if (!options.time.max) {
- upper = ticks[ticks.length - 1];
- lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
- end = (
- interpolate(table, 'time', upper, 'pos') -
- interpolate(table, 'time', lower, 'pos')
- ) / 2;
+ last = interpolate(table, 'time', ticks[ticks.length - 1], 'pos');
+ if (ticks.length === 1) {
+ end = last;
+ } else {
+ end = (last - interpolate(table, 'time', ticks[ticks.length - 2], 'pos')) / 2;
+ }
}
}
- return options.ticks.reverse ? {start: end, end: start} : {start: start, end: end};
+ return {start: start, end: end};
}
function ticksFromTimestamps(values, majorUnit) {
--- /dev/null
+{
+ "config": {
+ "type": "bar",
+ "data": {
+ "labels": ["2016", "2018", "2020", "2024", "2030"],
+ "datasets": [{
+ "backgroundColor": "#FF6384",
+ "data": [1]
+ }]
+ },
+ "options": {
+ "responsive": false,
+ "legend": false,
+ "title": false,
+ "scales": {
+ "xAxes": [{
+ "type": "time",
+ "display": false,
+ "barThickness": "flex",
+ "barPercentage": 1,
+ "categoryPercentage": 1,
+ "ticks": {
+ "source": "labels",
+ "reverse": true
+ }
+ }],
+ "yAxes": [{
+ "display": false,
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+ },
+ "options": {
+ "canvas": {
+ "height": 256,
+ "width": 512
+ }
+ }
+}
--- /dev/null
+{
+ "config": {
+ "type": "bar",
+ "data": {
+ "labels": ["2016", "2018", "2020", "2024", "2030"],
+ "datasets": [{
+ "backgroundColor": "#FF6384",
+ "data": [1]
+ }]
+ },
+ "options": {
+ "responsive": false,
+ "legend": false,
+ "title": false,
+ "scales": {
+ "xAxes": [{
+ "type": "time",
+ "display": false,
+ "barThickness": "flex",
+ "barPercentage": 1,
+ "categoryPercentage": 1,
+ "ticks": {
+ "source": "labels"
+ }
+ }],
+ "yAxes": [{
+ "display": false,
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+ },
+ "options": {
+ "canvas": {
+ "height": 256,
+ "width": 512
+ }
+ }
+}
--- /dev/null
+{
+ "config": {
+ "type": "bar",
+ "data": {
+ "labels": ["2016", "2018", "2020", "2024", "2030"],
+ "datasets": [{
+ "backgroundColor": "#FF6384",
+ "data": [1, null, 3, 4, 5]
+ }, {
+ "backgroundColor": "#36A2EB",
+ "data": [5, 4, 3, null, 1]
+ }, {
+ "backgroundColor": "#FFCE56",
+ "data": [3, 5, 2, null, 4]
+ }]
+ },
+ "options": {
+ "responsive": false,
+ "legend": false,
+ "title": false,
+ "scales": {
+ "xAxes": [{
+ "type": "time",
+ "display": false,
+ "barPercentage": 1,
+ "categoryPercentage": 1,
+ "ticks": {
+ "source": "labels",
+ "reverse": true
+ }
+ }],
+ "yAxes": [{
+ "display": false,
+ "ticks": {
+ "beginAtZero": true
+ }
+ }]
+ }
+ }
+ },
+ "options": {
+ "canvas": {
+ "height": 256,
+ "width": 512
+ }
+ }
+}
describe('when ticks.reverse', function() {
describe('is "true"', function() {
- it ('should reverse the labels', function() {
+ beforeEach(function() {
this.chart = window.acquireChart({
type: 'line',
data: {
}
}
});
+ });
+
+ it ('should reverse the labels', function() {
var scale = this.chart.scales.x;
expect(scale.getPixelForValue('2017')).toBeCloseToPixel(scale.left + scale.width);
expect(scale.getPixelForValue('2042')).toBeCloseToPixel(scale.left);
});
+
+ it ('should reverse the bars and add offsets if offset is true', function() {
+ var chart = this.chart;
+ var scale = chart.scales.x;
+ var options = chart.options.scales.xAxes[0];
+
+ options.offset = true;
+ chart.update();
+
+ var numTicks = scale.ticks.length;
+ var firstTickInterval = scale.getPixelForTick(1) - scale.getPixelForTick(0);
+ var lastTickInterval = scale.getPixelForTick(numTicks - 1) - scale.getPixelForTick(numTicks - 2);
+
+ expect(scale.getPixelForValue('2017')).toBeCloseToPixel(scale.left + scale.width - lastTickInterval / 2);
+ expect(scale.getPixelForValue('2042')).toBeCloseToPixel(scale.left + firstTickInterval / 2);
+ });
});
});