mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Make autoskip aware of major ticks (#6509)
* Make autoskip aware of major ticks * Address review comments * Fix codeclimate warning * Add test for major and minor tick autoskipping * Revert change for determining _majorUnit and fix sample
This commit is contained in:
parent
6bc6630b87
commit
69a5082bd6
@ -76,7 +76,7 @@
|
||||
var now = moment();
|
||||
var data = [];
|
||||
var lessThanDay = unitLessThanDay();
|
||||
for (; data.length < 60 && date.isBefore(now); date = date.clone().add(1, unit).startOf(unit)) {
|
||||
for (; data.length < 600 && date.isBefore(now); date = date.clone().add(1, unit).startOf(unit)) {
|
||||
if (outsideMarketHours(date)) {
|
||||
if (!lessThanDay || !beforeNineThirty(date)) {
|
||||
date = date.clone().add(date.isoWeekday() >= 5 ? 8 - date.isoWeekday() : 1, 'day');
|
||||
@ -112,13 +112,49 @@
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
animation: {
|
||||
duration: 0
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
distribution: 'series',
|
||||
ticks: {
|
||||
major: {
|
||||
enabled: true,
|
||||
fontStyle: 'bold'
|
||||
},
|
||||
source: 'data',
|
||||
autoSkip: true
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 75,
|
||||
maxRotation: 0,
|
||||
sampleSize: 100
|
||||
},
|
||||
afterBuildTicks: function(scale, ticks) {
|
||||
var majorUnit = scale._majorUnit;
|
||||
var firstTick = ticks[0];
|
||||
var i, ilen, val, tick, currMajor, lastMajor;
|
||||
|
||||
val = moment(ticks[0].value);
|
||||
if ((majorUnit === 'minute' && val.second() === 0)
|
||||
|| (majorUnit === 'hour' && val.minute() === 0)
|
||||
|| (majorUnit === 'day' && val.hour() === 9)
|
||||
|| (majorUnit === 'month' && val.date() <= 3 && val.isoWeekday() === 1)
|
||||
|| (majorUnit === 'year' && val.month() === 0)) {
|
||||
firstTick.major = true;
|
||||
} else {
|
||||
firstTick.major = false;
|
||||
}
|
||||
lastMajor = val.get(majorUnit);
|
||||
|
||||
for (i = 1, ilen = ticks.length; i < ilen; i++) {
|
||||
tick = ticks[i];
|
||||
val = moment(tick.value);
|
||||
currMajor = val.get(majorUnit);
|
||||
tick.major = currMajor !== lastMajor;
|
||||
lastMajor = currMajor;
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
|
||||
@ -214,6 +214,109 @@ function parseTickFontOptions(options) {
|
||||
return {minor: minor, major: major};
|
||||
}
|
||||
|
||||
function nonSkipped(ticksToFilter) {
|
||||
var filtered = [];
|
||||
var item, index, len;
|
||||
for (index = 0, len = ticksToFilter.length; index < len; ++index) {
|
||||
item = ticksToFilter[index];
|
||||
if (typeof item._index !== 'undefined') {
|
||||
filtered.push(item);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
function getEvenSpacing(arr) {
|
||||
var len = arr.length;
|
||||
var i, diff;
|
||||
|
||||
if (len < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (diff = arr[0], i = 1; i < len; ++i) {
|
||||
if (arr[i] - arr[i - 1] !== diff) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
function calculateSpacing(majorIndices, ticks, axisLength, ticksLimit) {
|
||||
var evenMajorSpacing = getEvenSpacing(majorIndices);
|
||||
var spacing = (ticks.length - 1) / ticksLimit;
|
||||
var factors, factor, i, ilen;
|
||||
|
||||
// If the major ticks are evenly spaced apart, place the minor ticks
|
||||
// so that they divide the major ticks into even chunks
|
||||
if (!evenMajorSpacing) {
|
||||
return Math.max(spacing, 1);
|
||||
}
|
||||
|
||||
factors = helpers.math._factorize(evenMajorSpacing);
|
||||
for (i = 0, ilen = factors.length - 1; i < ilen; i++) {
|
||||
factor = factors[i];
|
||||
if (factor > spacing) {
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
return Math.max(spacing, 1);
|
||||
}
|
||||
|
||||
function getMajorIndices(ticks) {
|
||||
var result = [];
|
||||
var i, ilen;
|
||||
for (i = 0, ilen = ticks.length; i < ilen; i++) {
|
||||
if (ticks[i].major) {
|
||||
result.push(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function skipMajors(ticks, majorIndices, spacing) {
|
||||
var count = 0;
|
||||
var next = majorIndices[0];
|
||||
var i, tick;
|
||||
|
||||
spacing = Math.ceil(spacing);
|
||||
for (i = 0; i < ticks.length; i++) {
|
||||
tick = ticks[i];
|
||||
if (i === next) {
|
||||
tick._index = i;
|
||||
count++;
|
||||
next = majorIndices[count * spacing];
|
||||
} else {
|
||||
delete tick.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function skip(ticks, spacing, majorStart, majorEnd) {
|
||||
var start = valueOrDefault(majorStart, 0);
|
||||
var end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
|
||||
var count = 0;
|
||||
var length, i, tick, next;
|
||||
|
||||
spacing = Math.ceil(spacing);
|
||||
if (majorEnd) {
|
||||
length = majorEnd - majorStart;
|
||||
spacing = length / Math.floor(length / spacing);
|
||||
}
|
||||
|
||||
next = start;
|
||||
for (i = Math.max(start, 0); i < end; i++) {
|
||||
tick = ticks[i];
|
||||
if (i === next) {
|
||||
tick._index = i;
|
||||
count++;
|
||||
next = Math.round(start + count * spacing);
|
||||
} else {
|
||||
delete tick.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Scale = Element.extend({
|
||||
|
||||
zeroLineIndex: 0,
|
||||
@ -364,7 +467,7 @@ var Scale = Element.extend({
|
||||
me.afterFit();
|
||||
|
||||
// Auto-skip
|
||||
me._ticksToDraw = tickOpts.display && tickOpts.autoSkip ? me._autoSkip(ticks) : ticks;
|
||||
me._ticksToDraw = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(ticks) : ticks;
|
||||
|
||||
if (samplingEnabled) {
|
||||
// Generate labels using all non-skipped ticks
|
||||
@ -848,40 +951,34 @@ var Scale = Element.extend({
|
||||
*/
|
||||
_autoSkip: function(ticks) {
|
||||
var me = this;
|
||||
var optionTicks = me.options.ticks;
|
||||
var tickCount = ticks.length;
|
||||
var skipRatio = false;
|
||||
var maxTicks = optionTicks.maxTicksLimit;
|
||||
|
||||
// Total space needed to display all ticks. First and last ticks are
|
||||
// drawn as their center at end of axis, so tickCount-1
|
||||
var ticksLength = me._tickSize() * (tickCount - 1);
|
||||
|
||||
var tickOpts = me.options.ticks;
|
||||
var axisLength = me._length;
|
||||
var result = [];
|
||||
var i, tick;
|
||||
var ticksLimit = tickOpts.maxTicksLimit || axisLength / me._tickSize() + 1;
|
||||
var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
|
||||
var numMajorIndices = majorIndices.length;
|
||||
var first = majorIndices[0];
|
||||
var last = majorIndices[numMajorIndices - 1];
|
||||
var i, ilen, spacing, avgMajorSpacing;
|
||||
|
||||
if (ticksLength > axisLength) {
|
||||
skipRatio = 1 + Math.floor(ticksLength / axisLength);
|
||||
// If there are too many major ticks to display them all
|
||||
if (numMajorIndices > ticksLimit) {
|
||||
skipMajors(ticks, majorIndices, numMajorIndices / ticksLimit);
|
||||
return nonSkipped(ticks);
|
||||
}
|
||||
|
||||
// if they defined a max number of optionTicks,
|
||||
// increase skipRatio until that number is met
|
||||
if (tickCount > maxTicks) {
|
||||
skipRatio = Math.max(skipRatio, 1 + Math.floor(tickCount / maxTicks));
|
||||
}
|
||||
spacing = calculateSpacing(majorIndices, ticks, axisLength, ticksLimit);
|
||||
|
||||
for (i = 0; i < tickCount; i++) {
|
||||
tick = ticks[i];
|
||||
|
||||
if (skipRatio <= 1 || i % skipRatio === 0) {
|
||||
tick._index = i;
|
||||
result.push(tick);
|
||||
} else {
|
||||
delete tick.label;
|
||||
if (numMajorIndices > 0) {
|
||||
for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
|
||||
skip(ticks, spacing, majorIndices[i], majorIndices[i + 1]);
|
||||
}
|
||||
avgMajorSpacing = numMajorIndices > 1 ? (last - first) / (numMajorIndices - 1) : null;
|
||||
skip(ticks, spacing, helpers.isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
|
||||
skip(ticks, spacing, last, helpers.isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
|
||||
return nonSkipped(ticks);
|
||||
}
|
||||
return result;
|
||||
skip(ticks, spacing);
|
||||
return nonSkipped(ticks);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -955,7 +1052,7 @@ var Scale = Element.extend({
|
||||
var alignBorderValue = function(pixel) {
|
||||
return alignPixel(chart, pixel, axisWidth);
|
||||
};
|
||||
var borderValue, i, tick, label, lineValue, alignedLineValue;
|
||||
var borderValue, i, tick, lineValue, alignedLineValue;
|
||||
var tx1, ty1, tx2, ty2, x1, y1, x2, y2, lineWidth, lineColor, borderDash, borderDashOffset;
|
||||
|
||||
if (position === 'top') {
|
||||
@ -986,10 +1083,9 @@ var Scale = Element.extend({
|
||||
|
||||
for (i = 0; i < ticksLength; ++i) {
|
||||
tick = ticks[i] || {};
|
||||
label = tick.label;
|
||||
|
||||
// autoskipper skipped this tick (#4635)
|
||||
if (isNullOrUndef(label) && i < ticks.length) {
|
||||
if (isNullOrUndef(tick.label) && i < ticks.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ var defaults = require('../core/core.defaults');
|
||||
var helpers = require('../helpers/index');
|
||||
var Scale = require('../core/core.scale');
|
||||
|
||||
var resolve = helpers.options.resolve;
|
||||
var valueOrDefault = helpers.valueOrDefault;
|
||||
var factorize = helpers.math._factorize;
|
||||
|
||||
// Integer constants are from the ES6 spec.
|
||||
var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
|
||||
@ -16,42 +16,42 @@ var INTERVALS = {
|
||||
millisecond: {
|
||||
common: true,
|
||||
size: 1,
|
||||
steps: factorize(1000)
|
||||
steps: 1000
|
||||
},
|
||||
second: {
|
||||
common: true,
|
||||
size: 1000,
|
||||
steps: factorize(60)
|
||||
steps: 60
|
||||
},
|
||||
minute: {
|
||||
common: true,
|
||||
size: 60000,
|
||||
steps: factorize(60)
|
||||
steps: 60
|
||||
},
|
||||
hour: {
|
||||
common: true,
|
||||
size: 3600000,
|
||||
steps: factorize(24)
|
||||
steps: 24
|
||||
},
|
||||
day: {
|
||||
common: true,
|
||||
size: 86400000,
|
||||
steps: factorize(10)
|
||||
steps: 30
|
||||
},
|
||||
week: {
|
||||
common: false,
|
||||
size: 604800000,
|
||||
steps: factorize(4)
|
||||
steps: 4
|
||||
},
|
||||
month: {
|
||||
common: true,
|
||||
size: 2.628e9,
|
||||
steps: factorize(12)
|
||||
steps: 12
|
||||
},
|
||||
quarter: {
|
||||
common: false,
|
||||
size: 7.884e9,
|
||||
steps: factorize(4)
|
||||
steps: 4
|
||||
},
|
||||
year: {
|
||||
common: true,
|
||||
@ -248,31 +248,6 @@ function parse(scale, input) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of unit to skip to be able to display up to `capacity` number of ticks
|
||||
* in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
|
||||
*/
|
||||
function determineStepSize(min, max, unit, capacity) {
|
||||
var range = max - min;
|
||||
var interval = INTERVALS[unit];
|
||||
var milliseconds = interval.size;
|
||||
var steps = interval.steps;
|
||||
var i, ilen, factor;
|
||||
|
||||
if (!steps) {
|
||||
return Math.ceil(range / (capacity * milliseconds));
|
||||
}
|
||||
|
||||
for (i = 0, ilen = steps.length; i < ilen; ++i) {
|
||||
factor = steps[i];
|
||||
if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out what unit results in an appropriate number of auto-generated ticks
|
||||
*/
|
||||
@ -282,7 +257,7 @@ function determineUnitForAutoTicks(minUnit, min, max, capacity) {
|
||||
|
||||
for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
|
||||
interval = INTERVALS[UNITS[i]];
|
||||
factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
|
||||
factor = interval.steps ? interval.steps / 2 : MAX_INTEGER;
|
||||
|
||||
if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
|
||||
return UNITS[i];
|
||||
@ -296,10 +271,9 @@ function determineUnitForAutoTicks(minUnit, min, max, capacity) {
|
||||
* Figures out what unit to format a set of ticks with
|
||||
*/
|
||||
function determineUnitForFormatting(scale, ticks, minUnit, min, max) {
|
||||
var ilen = UNITS.length;
|
||||
var i, unit;
|
||||
|
||||
for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
|
||||
for (i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
|
||||
unit = UNITS[i];
|
||||
if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= ticks.length - 1) {
|
||||
return unit;
|
||||
@ -319,7 +293,7 @@ function determineMajorUnit(unit) {
|
||||
|
||||
/**
|
||||
* Generates a maximum of `capacity` timestamps between min and max, rounded to the
|
||||
* `minor` unit, aligned on the `major` unit and using the given scale time `options`.
|
||||
* `minor` unit using the given scale time `options`.
|
||||
* Important: this method can return ticks outside the min and max range, it's the
|
||||
* responsibility of the calling code to clamp values if needed.
|
||||
*/
|
||||
@ -328,51 +302,33 @@ function generate(scale, min, max, capacity) {
|
||||
var options = scale.options;
|
||||
var timeOpts = options.time;
|
||||
var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
|
||||
var major = determineMajorUnit(minor);
|
||||
var stepSize = valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
|
||||
var stepSize = resolve([timeOpts.stepSize, timeOpts.unitStepSize, 1]);
|
||||
var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
|
||||
var majorTicksEnabled = options.ticks.major.enabled;
|
||||
var interval = INTERVALS[minor];
|
||||
var first = min;
|
||||
var last = max;
|
||||
var ticks = [];
|
||||
var time;
|
||||
|
||||
if (!stepSize) {
|
||||
stepSize = determineStepSize(min, max, minor, capacity);
|
||||
}
|
||||
|
||||
// For 'week' unit, handle the first day of week option
|
||||
if (weekday) {
|
||||
first = +adapter.startOf(first, 'isoWeek', weekday);
|
||||
last = +adapter.startOf(last, 'isoWeek', weekday);
|
||||
}
|
||||
|
||||
// Align first/last ticks on unit
|
||||
// Align first ticks on unit
|
||||
first = +adapter.startOf(first, weekday ? 'day' : minor);
|
||||
last = +adapter.startOf(last, weekday ? 'day' : minor);
|
||||
|
||||
// Make sure that the last tick include max
|
||||
if (last < max) {
|
||||
last = +adapter.add(last, 1, minor);
|
||||
// Prevent browser from freezing in case user options request millions of milliseconds
|
||||
if (adapter.diff(max, min, minor) > 100000 * stepSize) {
|
||||
throw min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor;
|
||||
}
|
||||
|
||||
time = first;
|
||||
|
||||
if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
|
||||
// Align the first tick on the previous `minor` unit aligned on the `major` unit:
|
||||
// we first aligned time on the previous `major` unit then add the number of full
|
||||
// stepSize there is between first and the previous major time.
|
||||
time = +adapter.startOf(time, major);
|
||||
time = +adapter.add(time, ~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
|
||||
for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {
|
||||
ticks.push(time);
|
||||
}
|
||||
|
||||
for (; time < last; time = +adapter.add(time, stepSize, minor)) {
|
||||
ticks.push(+time);
|
||||
if (time === max || options.bounds === 'ticks') {
|
||||
ticks.push(time);
|
||||
}
|
||||
|
||||
ticks.push(+time);
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
@ -609,18 +565,17 @@ module.exports = Scale.extend({
|
||||
var timeOpts = options.time;
|
||||
var timestamps = me._timestamps;
|
||||
var ticks = [];
|
||||
var capacity = me.getLabelCapacity(min);
|
||||
var source = options.ticks.source;
|
||||
var distribution = options.distribution;
|
||||
var i, ilen, timestamp;
|
||||
|
||||
switch (options.ticks.source) {
|
||||
case 'data':
|
||||
if (source === 'data' || (source === 'auto' && distribution === 'series')) {
|
||||
timestamps = timestamps.data;
|
||||
break;
|
||||
case 'labels':
|
||||
} else if (source === 'labels') {
|
||||
timestamps = timestamps.labels;
|
||||
break;
|
||||
case 'auto':
|
||||
default:
|
||||
timestamps = generate(me, min, max, me.getLabelCapacity(min), options);
|
||||
} else {
|
||||
timestamps = generate(me, min, max, capacity, options);
|
||||
}
|
||||
|
||||
if (options.bounds === 'ticks' && timestamps.length) {
|
||||
@ -645,8 +600,9 @@ module.exports = Scale.extend({
|
||||
|
||||
// PRIVATE
|
||||
me._unit = timeOpts.unit || determineUnitForFormatting(me, ticks, timeOpts.minUnit, me.min, me.max);
|
||||
me._majorUnit = determineMajorUnit(me._unit);
|
||||
me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
|
||||
me._majorUnit = !options.ticks.major.enabled || me._unit === 'year' ? undefined
|
||||
: determineMajorUnit(me._unit);
|
||||
me._table = buildLookupTable(me._timestamps.data, min, max, distribution);
|
||||
me._offsets = computeOffsets(me._table, ticks, min, max, options);
|
||||
|
||||
if (options.ticks.reverse) {
|
||||
@ -690,11 +646,10 @@ module.exports = Scale.extend({
|
||||
var majorFormat = formats[majorUnit];
|
||||
var tick = ticks[index];
|
||||
var tickOpts = options.ticks;
|
||||
var majorTickOpts = tickOpts.major;
|
||||
var major = majorTickOpts.enabled && majorUnit && majorFormat && tick && tick.major;
|
||||
var major = majorUnit && majorFormat && tick && tick.major;
|
||||
var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
|
||||
var nestedTickOpts = major ? majorTickOpts : tickOpts.minor;
|
||||
var formatter = helpers.options.resolve([
|
||||
var nestedTickOpts = major ? tickOpts.major : tickOpts.minor;
|
||||
var formatter = resolve([
|
||||
nestedTickOpts.callback,
|
||||
nestedTickOpts.userCallback,
|
||||
tickOpts.callback,
|
||||
|
||||
@ -617,21 +617,22 @@ describe('Time scale tests', function() {
|
||||
});
|
||||
|
||||
it('should build the correct ticks', function() {
|
||||
// Where 'correct' is a two year spacing.
|
||||
expect(getTicksLabels(this.scale)).toEqual(['2005', '2007', '2009', '2011', '2013', '2015', '2017', '2019']);
|
||||
expect(getTicksLabels(this.scale)).toEqual(['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017', '2018']);
|
||||
});
|
||||
|
||||
it('should have ticks with accurate labels', function() {
|
||||
var scale = this.scale;
|
||||
var ticks = scale.getTicks();
|
||||
var pixelsPerYear = scale.width / 14;
|
||||
// pixelsPerTick is an aproximation which assumes same number of milliseconds per year (not true)
|
||||
// we use a threshold of 1 day so that we still match these values
|
||||
var pixelsPerTick = scale.width / (ticks.length - 1);
|
||||
|
||||
for (var i = 0; i < ticks.length - 1; i++) {
|
||||
var offset = 2 * pixelsPerYear * i;
|
||||
var offset = pixelsPerTick * i;
|
||||
expect(scale.getValueForPixel(scale.left + offset)).toBeCloseToTime({
|
||||
value: moment(ticks[i].label + '-01-01'),
|
||||
unit: 'day',
|
||||
threshold: 0.5,
|
||||
threshold: 1,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -700,10 +701,9 @@ describe('Time scale tests', function() {
|
||||
it('should get the correct labels for ticks', function() {
|
||||
var scale = this.scale;
|
||||
|
||||
expect(scale._ticks.map(function(tick) {
|
||||
return tick.major;
|
||||
})).toEqual([true, false, false, false, false, false, true]);
|
||||
expect(scale.ticks).toEqual(['<8:00:00>', '<8:00:10>', '<8:00:20>', '<8:00:30>', '<8:00:40>', '<8:00:50>', '<8:01:00>']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('<8:00:00>');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('<8:01:00>');
|
||||
});
|
||||
|
||||
it('should update ticks.callback correctly', function() {
|
||||
@ -714,7 +714,9 @@ describe('Time scale tests', function() {
|
||||
return '{' + value + '}';
|
||||
};
|
||||
chart.update();
|
||||
expect(scale.ticks).toEqual(['{8:00:00}', '{8:00:10}', '{8:00:20}', '{8:00:30}', '{8:00:40}', '{8:00:50}', '{8:01:00}']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('{8:00:00}');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('{8:01:00}');
|
||||
});
|
||||
});
|
||||
|
||||
@ -760,10 +762,10 @@ describe('Time scale tests', function() {
|
||||
it('should get the correct labels for major and minor ticks', function() {
|
||||
var scale = this.scale;
|
||||
|
||||
expect(scale._ticks.map(function(tick) {
|
||||
return tick.major;
|
||||
})).toEqual([true, false, false, false, false, false, true]);
|
||||
expect(scale.ticks).toEqual(['[[8:00 pm]]', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '[[8:01 pm]]']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('[[8:00 pm]]');
|
||||
expect(scale.ticks[Math.floor(scale.ticks.length / 2)]).toEqual('(8:00:30 pm)');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('[[8:01 pm]]');
|
||||
});
|
||||
|
||||
it('should only use ticks.minor callback if ticks.major.enabled is false', function() {
|
||||
@ -772,7 +774,9 @@ describe('Time scale tests', function() {
|
||||
|
||||
chart.options.scales.xAxes[0].ticks.major.enabled = false;
|
||||
chart.update();
|
||||
expect(scale.ticks).toEqual(['(8:00:00 pm)', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '(8:01:00 pm)']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('(8:00:00 pm)');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('(8:01:00 pm)');
|
||||
});
|
||||
|
||||
it('should use ticks.callback if ticks.major.callback is omitted', function() {
|
||||
@ -781,7 +785,9 @@ describe('Time scale tests', function() {
|
||||
|
||||
chart.options.scales.xAxes[0].ticks.major.callback = undefined;
|
||||
chart.update();
|
||||
expect(scale.ticks).toEqual(['<8:00 pm>', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '<8:01 pm>']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('<8:00 pm>');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('<8:01 pm>');
|
||||
});
|
||||
|
||||
it('should use ticks.callback if ticks.minor.callback is omitted', function() {
|
||||
@ -790,7 +796,10 @@ describe('Time scale tests', function() {
|
||||
|
||||
chart.options.scales.xAxes[0].ticks.minor.callback = undefined;
|
||||
chart.update();
|
||||
expect(scale.ticks).toEqual(['[[8:00 pm]]', '<8:00:10 pm>', '<8:00:20 pm>', '<8:00:30 pm>', '<8:00:40 pm>', '<8:00:50 pm>', '[[8:01 pm]]']);
|
||||
expect(scale.ticks.length).toEqual(61);
|
||||
expect(scale.ticks[0]).toEqual('[[8:00 pm]]');
|
||||
expect(scale.ticks[Math.floor(scale.ticks.length / 2)]).toEqual('<8:00:30 pm>');
|
||||
expect(scale.ticks[scale.ticks.length - 1]).toEqual('[[8:01 pm]]');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1766,6 +1775,52 @@ describe('Time scale tests', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle autoskip with major and minor ticks', function() {
|
||||
var date = moment('Jan 01 1990', 'MMM DD YYYY');
|
||||
var data = [];
|
||||
for (var i = 0; i < 60; i++) {
|
||||
data.push({x: date.valueOf(), y: Math.random()});
|
||||
date = date.clone().add(1, 'month');
|
||||
}
|
||||
|
||||
var chart = window.acquireChart({
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
xAxisID: 'xScale0',
|
||||
data: data
|
||||
}],
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'xScale0',
|
||||
type: 'time',
|
||||
ticks: {
|
||||
major: {
|
||||
enabled: true
|
||||
},
|
||||
source: 'data',
|
||||
autoSkip: true
|
||||
}
|
||||
}],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var scale = chart.scales.xScale0;
|
||||
|
||||
var labels = scale._ticksToDraw.map(function(t) {
|
||||
return t.label;
|
||||
});
|
||||
expect(labels).toEqual([
|
||||
'1990', 'Apr 1990', 'Jul 1990', 'Oct 1990',
|
||||
'1991', 'Apr 1991', 'Jul 1991', 'Oct 1991',
|
||||
'1992', 'Apr 1992', 'Jul 1992', 'Oct 1992',
|
||||
'1993', 'Apr 1993', 'Jul 1993', 'Oct 1993',
|
||||
'1994', 'Apr 1994', 'Jul 1994', 'Oct 1994']);
|
||||
});
|
||||
|
||||
describe('Deprecations', function() {
|
||||
describe('options.time.displayFormats', function() {
|
||||
it('should generate defaults from adapter presets', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user