diff --git a/src/constants/numerical.js b/src/constants/numerical.js index 17111ce1a6d..b7b497c7b97 100644 --- a/src/constants/numerical.js +++ b/src/constants/numerical.js @@ -31,13 +31,17 @@ module.exports = { * to remind us that not all years and months * have the same length */ + ONEMAXYEAR: 31622400000, // 366 * ONEDAY ONEAVGYEAR: 31557600000, // 365.25 days + ONEMINYEAR: 31536000000, // 365 * ONEDAY + ONEMAXQUARTER: 7948800000, // 92 * ONEDAY ONEAVGQUARTER: 7889400000, // 1/4 of ONEAVGYEAR + ONEMINQUARTER: 7689600000, // 89 * ONEDAY ONEMAXMONTH: 2678400000, // 31 * ONEDAY ONEAVGMONTH: 2629800000, // 1/12 of ONEAVGYEAR ONEMINMONTH: 2419200000, // 28 * ONEDAY ONEWEEK: 604800000, // 7 * ONEDAY - ONEDAY: 86400000, + ONEDAY: 86400000, // 24 * ONEHOUR ONEHOUR: 3600000, ONEMIN: 60000, ONESEC: 1000, diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 26e73e7b0cf..0e27a0bfada 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -23,13 +23,18 @@ var axAttrs = require('./layout_attributes'); var cleanTicks = require('./clean_ticks'); var constants = require('../../constants/numerical'); +var ONEMAXYEAR = constants.ONEMAXYEAR; var ONEAVGYEAR = constants.ONEAVGYEAR; +var ONEMINYEAR = constants.ONEMINYEAR; +var ONEMAXQUARTER = constants.ONEMAXQUARTER; var ONEAVGQUARTER = constants.ONEAVGQUARTER; +var ONEMINQUARTER = constants.ONEMINQUARTER; var ONEMAXMONTH = constants.ONEMAXMONTH; var ONEAVGMONTH = constants.ONEAVGMONTH; var ONEMINMONTH = constants.ONEMINMONTH; var ONEWEEK = constants.ONEWEEK; var ONEDAY = constants.ONEDAY; +var HALFDAY = ONEDAY / 2; var ONEHOUR = constants.ONEHOUR; var ONEMIN = constants.ONEMIN; var ONESEC = constants.ONESEC; @@ -499,7 +504,7 @@ function autoShiftMonthBins(binStart, data, dtick, dataMin, calendar) { // will always give a somewhat odd-looking label, until we do something // smarter like showing the bin boundaries (or the bounds of the actual // data in each bin) - binStart -= ONEDAY / 2; + binStart -= HALFDAY; } var nextBinStart = axes.tickIncrement(binStart, dtick); @@ -698,22 +703,28 @@ axes.calcTicks = function calcTicks(ax, opts) { var maxRange = Math.max(rng[0], rng[1]); var definedDelta; - if(isPeriod && ax.tickformat) { + var tickformat = axes.getTickFormat(ax); + if(isPeriod && tickformat) { if( - !(/%[fLQsSMHIpX]/.test(ax.tickformat)) + !(/%[fLQsSMX]/.test(tickformat)) // %f: microseconds as a decimal number [000000, 999999] // %L: milliseconds as a decimal number [000, 999] // %Q: milliseconds since UNIX epoch // %s: seconds since UNIX epoch // %S: second as a decimal number [00,61] // %M: minute as a decimal number [00,59] - // %H: hour (24-hour clock) as a decimal number [00,23] - // %I: hour (12-hour clock) as a decimal number [01,12] - // %p: either AM or PM // %X: the locale’s time, such as %-I:%M:%S %p ) { if( - /%[Aadejuwx]/.test(ax.tickformat) + /%[HI]/.test(tickformat) + // %H: hour (24-hour clock) as a decimal number [00,23] + // %I: hour (12-hour clock) as a decimal number [01,12] + ) definedDelta = ONEHOUR; + else if( + /%p/.test(tickformat) // %p: either AM or PM + ) definedDelta = HALFDAY; + else if( + /%[Aadejuwx]/.test(tickformat) // %A: full weekday name // %a: abbreviated weekday name // %d: zero-padded day of the month as a decimal number [01,31] @@ -724,75 +735,124 @@ axes.calcTicks = function calcTicks(ax, opts) { // %x: the locale’s date, such as %-m/%-d/%Y ) definedDelta = ONEDAY; else if( - /%[UVW]/.test(ax.tickformat) + /%[UVW]/.test(tickformat) // %U: Sunday-based week of the year as a decimal number [00,53] // %V: ISO 8601 week of the year as a decimal number [01, 53] // %W: Monday-based week of the year as a decimal number [00,53] ) definedDelta = ONEWEEK; else if( - /%[Bbm]/.test(ax.tickformat) + /%[Bbm]/.test(tickformat) // %B: full month name // %b: abbreviated month name // %m: month as a decimal number [01,12] ) definedDelta = ONEAVGMONTH; else if( - /%[q]/.test(ax.tickformat) + /%[q]/.test(tickformat) // %q: quarter of the year as a decimal number [1,4] ) definedDelta = ONEAVGQUARTER; else if( - /%[Yy]/.test(ax.tickformat) + /%[Yy]/.test(tickformat) // %Y: year with century as a decimal number, such as 1999 // %y: year without century as a decimal number [00,99] ) definedDelta = ONEAVGYEAR; } } - var removedPreTick0Label = false; - var ticksOut = new Array(tickVals.length); + var ticksOut = []; var i; + var prevText; for(i = 0; i < tickVals.length; i++) { var _minor = tickVals[i].minor; var _value = tickVals[i].value; - ticksOut[i] = axes.tickText( + var t = axes.tickText( ax, _value, false, // hover _minor // noSuffixPrefix ); - if(isPeriod) { - var v = tickVals[i].value; + if(isPeriod && prevText === t.text) continue; + prevText = t.text; + + ticksOut.push(t); + } + + if(isPeriod) { + var removedPreTick0Label = false; + + for(i = 0; i < ticksOut.length; i++) { + var v = ticksOut[i].x; var a = i; var b = i + 1; - if(i < tickVals.length - 1) { + if(i < ticksOut.length - 1) { a = i; b = i + 1; - } else { + } else if(i > 0) { a = i - 1; b = i; + } else { + a = i; + b = i; } - var A = tickVals[a].value; - var B = tickVals[b].value; + var A = ticksOut[a].x; + var B = ticksOut[b].x; + var actualDelta = Math.abs(B - A); + var delta = definedDelta || actualDelta; + var periodLength = 0; - var delta = definedDelta || Math.abs(B - A); - if(delta >= ONEDAY * 365) { // Years could have days less than ONEAVGYEAR period - v += ONEAVGYEAR / 2; - } else if(delta >= ONEAVGQUARTER) { - v += ONEAVGQUARTER / 2; - } else if(delta >= ONEMINMONTH) { // Months could have days less than ONEAVGMONTH period - var actualDelta = Math.abs(B - A); + if(delta >= ONEMINYEAR) { + if(actualDelta >= ONEMINYEAR && actualDelta <= ONEMAXYEAR) { + periodLength = actualDelta; + } else { + periodLength = ONEAVGYEAR; + } + } else if(definedDelta === ONEAVGQUARTER && delta >= ONEMINQUARTER) { + if(actualDelta >= ONEMINQUARTER && actualDelta <= ONEMAXQUARTER) { + periodLength = actualDelta; + } else { + periodLength = ONEAVGQUARTER; + } + } else if(delta >= ONEMINMONTH) { if(actualDelta >= ONEMINMONTH && actualDelta <= ONEMAXMONTH) { - v += actualDelta / 2; + periodLength = actualDelta; } else { - v += ONEAVGMONTH / 2; + periodLength = ONEAVGMONTH; } - } else if(delta >= ONEWEEK) { - v += ONEWEEK / 2; + } else if(definedDelta === ONEWEEK && delta >= ONEWEEK) { + periodLength = ONEWEEK; } else if(delta >= ONEDAY) { - v += ONEDAY / 2; + periodLength = ONEDAY; + } else if(definedDelta === HALFDAY && delta >= HALFDAY) { + periodLength = HALFDAY; + } else if(definedDelta === ONEHOUR && delta >= ONEHOUR) { + periodLength = ONEHOUR; + } + + if(periodLength && ax.rangebreaks) { + var nFirstHalf = 0; + var nSecondHalf = 0; + var nAll = 2 * 3 * 7; // number of samples + for(var c = 0; c < nAll; c++) { + var r = c / nAll; + if(ax.maskBreaks(A * (1 - r) + B * r) !== BADNUM) { + if(r < 0.5) { + nFirstHalf++; + } else { + nSecondHalf++; + } + } + } + + if(nSecondHalf) { + periodLength *= (nFirstHalf + nSecondHalf) / nAll; + } + } + + if(periodLength <= actualDelta) { // i.e. to ensure new label positions remain between ticks + v += periodLength / 2; } ticksOut[i].periodX = v; @@ -802,15 +862,15 @@ axes.calcTicks = function calcTicks(ax, opts) { removedPreTick0Label = true; } } - } - if(removedPreTick0Label) { - for(i = 0; i < ticksOut.length; i++) { - if(ticksOut[i].periodX <= maxRange && ticksOut[i].periodX >= minRange) { - // redo first visible tick - ax._prevDateHead = ''; - ticksOut[i].text = axes.tickText(ax, tickVals[i].value).text; - break; + if(removedPreTick0Label) { + for(i = 0; i < ticksOut.length; i++) { + if(ticksOut[i].periodX <= maxRange && ticksOut[i].periodX >= minRange) { + // redo first visible tick + ax._prevDateHead = ''; + ticksOut[i].text = axes.tickText(ax, ticksOut[i].x).text; + break; + } } } } @@ -924,7 +984,8 @@ axes.autoTicks = function(ax, roughDTick) { // 2 or 3 days... but that's a weird enough case that we'll ignore it. ax.tick0 = Lib.dateTick0(ax.calendar, true); - if(/%[uVW]/.test(ax.tickformat)) { + var tickformat = axes.getTickFormat(ax); + if(/%[uVW]/.test(tickformat)) { // replace Sunday with Monday for ISO and Monday-based formats var len = ax.tick0.length; var lastD = +ax.tick0[len - 1]; diff --git a/test/image/baselines/date_axes_period.png b/test/image/baselines/date_axes_period.png index 991ce21014b..c335091cbec 100644 Binary files a/test/image/baselines/date_axes_period.png and b/test/image/baselines/date_axes_period.png differ diff --git a/test/image/baselines/date_axes_period2.png b/test/image/baselines/date_axes_period2.png index c7882225fdc..808786263fe 100644 Binary files a/test/image/baselines/date_axes_period2.png and b/test/image/baselines/date_axes_period2.png differ diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 1f9e9ca9781..021c92d0a19 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -5198,6 +5198,7 @@ describe('Test axes', function() { }); describe('label positioning using *ticklabelmode*: "period"', function() { + var hovertemplate = 'x:%{x|%x %X}'; // to make debugging easier var gd; beforeEach(function() { @@ -5216,30 +5217,31 @@ describe('Test axes', function() { expect(labels).withContext(msg).toEqual(expLabels); } - ['%Y', '%y'].forEach(function(tickformat, i) { - it('should respect yearly tickformat that includes ' + tickformat, function(done) { + ['%Y', '%y'].forEach(function(formatter, i) { + it('should respect yearly tickformat that includes ' + formatter, function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-01-01', '2026-01-01'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: tickformat + tickformat: formatter } } }) .then(function() { _assert('', [ - '2019-07-02 15:00', - '2020-07-01 15:00', - '2021-07-02 15:00', - '2022-07-02 15:00', - '2023-07-02 15:00', - '2024-07-01 15:00', - '2025-07-02 15:00', - '2026-07-02 15:00' + '2019-07-02 12:00', + '2020-07-02', + '2021-07-02 12:00', + '2022-07-02 12:00', + '2023-07-02 12:00', + '2024-07-02', + '2025-07-02 12:00', + '2026-07-02 12:00' ], [ ['', '2020', '2021', '2022', '2023', '2024', '2025', ''], ['', '20', '21', '22', '23', '24', '25', ''] @@ -5253,45 +5255,76 @@ describe('Test axes', function() { it('should respect quarters tickformat that includes %q', function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-01-01', '2022-01-01'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%Y-%q' + tickformat: '%Y-Q%q' } } }) .then(function() { _assert('', [ - '2019-11-15 15:45', + '2019-11-16', + '2020-02-15 12:00', + '2020-05-16 12:00', + '2020-08-16', + '2020-11-16', + '2021-02-15', + '2021-05-16 12:00', + '2021-08-16', + '2021-11-16', + '2022-02-16' + ], ['', '2020-Q1', '2020-Q2', '2020-Q3', '2020-Q4', '2021-Q1', '2021-Q2', '2021-Q3', '2021-Q4', '']); + }) + .catch(failTest) + .then(done); + }); + + it('should position quarters - case of dtick set to M6', function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: ['2020-01-01', '2022-01-01'] + }], + layout: { + width: 1000, + xaxis: { + dtick: 'M6', + ticklabelmode: 'period', + tickformat: '%Y-Q%q' + } + } + }) + .then(function() { + _assert('', [ + '2019-08-15 15:45', '2020-02-15 15:45', - '2020-05-16 15:45', '2020-08-15 15:45', - '2020-11-15 15:45', '2021-02-15 15:45', - '2021-05-16 15:45', '2021-08-15 15:45', - '2021-11-15 15:45', '2022-02-15 15:45' - ], ['', '2020-1', '2020-2', '2020-3', '2020-4', '2021-1', '2021-2', '2021-3', '2021-4', '']); + ], ['', '2020-Q1', '2020-Q3', '2021-Q1', '2021-Q3', '']); }) .catch(failTest) .then(done); }); - ['%B', '%b', '%m'].forEach(function(tickformat, i) { - it('should respect monthly tickformat that includes ' + tickformat, function(done) { + ['%B', '%b', '%m'].forEach(function(formatter, i) { + it('should respect monthly tickformat that includes ' + formatter, function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-01-01', '2020-07-01'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%q-' + tickformat + tickformat: 'Q%q-' + formatter } } }) @@ -5306,9 +5339,9 @@ describe('Test axes', function() { '2020-06-16', '2020-07-16' ], [ - ['', '1-January', '1-February', '1-March', '2-April', '2-May', '2-June', ''], - ['', '1-Jan', '1-Feb', '1-Mar', '2-Apr', '2-May', '2-Jun', ''], - ['', '1-01', '1-02', '1-03', '2-04', '2-05', '2-06', ''] + ['', 'Q1-January', 'Q1-February', 'Q1-March', 'Q2-April', 'Q2-May', 'Q2-June', ''], + ['', 'Q1-Jan', 'Q1-Feb', 'Q1-Mar', 'Q2-Apr', 'Q2-May', 'Q2-Jun', ''], + ['', 'Q1-01', 'Q1-02', 'Q1-03', 'Q2-04', 'Q2-05', 'Q2-06', ''] ][i]); }) .catch(failTest) @@ -5319,13 +5352,14 @@ describe('Test axes', function() { it('should respect Sunday-based week tickformat that includes %U', function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-02-01', '2020-04-01'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%b-%U' + tickformat: '%b-W%U' } } }) @@ -5341,23 +5375,24 @@ describe('Test axes', function() { '2020-03-18 12:00', '2020-03-25 12:00', '2020-04-01 12:00' - ], ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13']); + ], ['Jan-W04', 'Feb-W05', 'Feb-W06', 'Feb-W07', 'Feb-W08', 'Mar-W09', 'Mar-W10', 'Mar-W11', 'Mar-W12', 'Mar-W13']); }) .catch(failTest) .then(done); }); - ['%V', '%W'].forEach(function(tickformat, i) { - it('should respect Monday-based week tickformat that includes ' + tickformat, function(done) { + ['%V', '%W'].forEach(function(formatter, i) { + it('should respect Monday-based week tickformat that includes ' + formatter, function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-02-01', '2020-04-01'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%b-' + tickformat + tickformat: '%b-W' + formatter } } }) @@ -5374,8 +5409,72 @@ describe('Test axes', function() { '2020-03-26 12:00', '2020-04-02 12:00' ], [ - ['Jan-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Feb-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13', 'Mar-14'], - ['Jan-04', 'Feb-05', 'Feb-06', 'Feb-07', 'Feb-08', 'Mar-09', 'Mar-10', 'Mar-11', 'Mar-12', 'Mar-13'] + ['Jan-W05', 'Feb-W06', 'Feb-W07', 'Feb-W08', 'Feb-W09', 'Mar-W10', 'Mar-W11', 'Mar-W12', 'Mar-W13', 'Mar-W14'], + ['Jan-W04', 'Feb-W05', 'Feb-W06', 'Feb-W07', 'Feb-W08', 'Mar-W09', 'Mar-W10', 'Mar-W11', 'Mar-W12', 'Mar-W13'] + ][i]); + }) + .catch(failTest) + .then(done); + }); + }); + + ['%U', '%V', '%W'].forEach(function(formatter, i) { + it('should move weekly labels by one day (i.e. to help center the labels) when *day of week* rangebreak is present', function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: [ + '2020-01-01', + '2020-01-02', + '2020-01-03', + '2020-01-04', + '2020-01-05', + '2020-01-06', + '2020-01-07', + '2020-01-08', + '2020-01-09', + '2020-01-10', + '2020-01-11', + '2020-01-12', + '2020-01-13', + '2020-01-14', + '2020-01-15', + '2020-01-16', + '2020-01-17', + '2020-01-18', + '2020-01-19', + '2020-01-20', + '2020-01-21', + '2020-01-22', + '2020-01-23', + '2020-01-24', + '2020-01-25', + '2020-01-26', + '2020-01-27', + '2020-01-28', + '2020-01-29', + '2020-01-30', + '2020-01-31' + ] + }], + layout: { + width: 1000, + xaxis: { + rangebreaks: [{bounds: ['sat', 'mon']}], + ticklabelmode: 'period', + tickformat: '%b-W' + formatter + } + } + }) + .then(function() { + _assert('', [ + ['2019-12-31 04:00', '2020-01-08 12:00', '2020-01-15 12:00', '2020-01-22 12:00', '2020-01-29 12:00'], + ['2020-01-01 12:00', '2020-01-08 12:00', '2020-01-15 12:00', '2020-01-22 12:00', '2020-01-29 12:00'], + ['2020-01-01 12:00', '2020-01-08 12:00', '2020-01-15 12:00', '2020-01-22 12:00', '2020-01-29 12:00'] + ][i], [ + ['', 'Jan-W01', 'Jan-W02', 'Jan-W03', 'Jan-W04'], + ['Dec-W01', 'Jan-W02', 'Jan-W03', 'Jan-W04', 'Jan-W05'], + ['Dec-W52', 'Jan-W01', 'Jan-W02', 'Jan-W03', 'Jan-W04'] ][i]); }) .catch(failTest) @@ -5383,17 +5482,18 @@ describe('Test axes', function() { }); }); - ['%A', '%a', '%d', '%e', '%j', '%u', '%w', '%x'].forEach(function(tickformat, i) { - it('should respect daily tickformat that includes ' + tickformat, function(done) { + ['%A', '%a', '%d', '%e', '%j', '%u', '%w', '%x'].forEach(function(formatter, i) { + it('should respect daily tickformat that includes ' + formatter, function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-01-01', '2020-01-08'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%b-' + tickformat + tickformat: '%b-' + formatter } } }) @@ -5424,17 +5524,18 @@ describe('Test axes', function() { }); }); - ['%f', '%L', '%Q', '%s', '%S', '%M', '%H', '%I', '%p', '%X'].forEach(function(tickformat, i) { - it('should respect daily tickformat that includes ' + tickformat, function(done) { + ['%Q', '%s', '%X'].forEach(function(formatter, i) { + it('should respect daily tickformat that includes ' + formatter, function(done) { Plotly.newPlot(gd, { data: [{ + hovertemplate: hovertemplate, x: ['2020-01-01', '2020-01-02'] }], layout: { width: 1000, xaxis: { ticklabelmode: 'period', - tickformat: '%a-' + tickformat + tickformat: '%a-' + formatter } } }) @@ -5451,15 +5552,8 @@ describe('Test axes', function() { '2020-01-01 21:00', '2020-01-02' ], [ - ['', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Wed-0', 'Thu-0'], - ['', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Wed-000', 'Thu-000'], ['', 'Wed-1577836800000', 'Wed-1577847600000', 'Wed-1577858400000', 'Wed-1577869200000', 'Wed-1577880000000', 'Wed-1577890800000', 'Wed-1577901600000', 'Wed-1577912400000', 'Thu-1577923200000'], ['', 'Wed-1577836800', 'Wed-1577847600', 'Wed-1577858400', 'Wed-1577869200', 'Wed-1577880000', 'Wed-1577890800', 'Wed-1577901600', 'Wed-1577912400', 'Thu-1577923200'], - ['', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Thu-00'], - ['', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Wed-00', 'Thu-00'], - ['', 'Wed-00', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-15', 'Wed-18', 'Wed-21', 'Thu-00'], - ['', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Thu-12'], - ['', 'Wed-AM', 'Wed-AM', 'Wed-AM', 'Wed-AM', 'Wed-PM', 'Wed-PM', 'Wed-PM', 'Wed-PM', 'Thu-AM'], ['', 'Wed-00:00:00', 'Wed-03:00:00', 'Wed-06:00:00', 'Wed-09:00:00', 'Wed-12:00:00', 'Wed-15:00:00', 'Wed-18:00:00', 'Wed-21:00:00', 'Thu-00:00:00'] ][i]); }) @@ -5467,6 +5561,413 @@ describe('Test axes', function() { .then(done); }); }); + + + [ + { + formatter: '%H', + positions: ['2019-12-31 21:30', '2020-01-01 00:30', '2020-01-01 03:30', '2020-01-01 06:30', '2020-01-01 09:30', '2020-01-01 12:30', '2020-01-01 15:30', '2020-01-01 18:30', '2020-01-01 21:30', '2020-01-02 00:30'], + labels: ['', 'Wed-00', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-15', 'Wed-18', 'Wed-21', 'Thu-00'] + }, + { + formatter: '%I', + positions: ['2019-12-31 21:30', '2020-01-01 00:30', '2020-01-01 03:30', '2020-01-01 06:30', '2020-01-01 09:30', '2020-01-01 12:30', '2020-01-01 15:30', '2020-01-01 18:30', '2020-01-01 21:30', '2020-01-02 00:30'], + labels: ['', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Wed-12', 'Wed-03', 'Wed-06', 'Wed-09', 'Thu-12'] + }, + { + formatter: '%p', + positions: ['2019-12-31 21:00', '2020-01-01 06:00', '2020-01-01 18:00', '2020-01-02 06:00'], + labels: ['', 'Wed-AM', 'Wed-PM', ''] + }, + { + formatter: '%M', + positions: ['2019-12-31 21:00', '2020-01-01 12:00', '2020-01-02 12:00'], + labels: ['', 'Wed-00', ''] + }, + { + formatter: '%S', + positions: ['2019-12-31 21:00', '2020-01-01 12:00', '2020-01-02 12:00'], + labels: ['', 'Wed-00', ''] + }, + { + formatter: '%L', + positions: ['2019-12-31 21:00', '2020-01-01 12:00', '2020-01-02 12:00'], + labels: ['', 'Wed-000', ''] + }, + { + formatter: '%f', + positions: ['2019-12-31 21:00', '2020-01-01 12:00', '2020-01-02 12:00'], + labels: ['', 'Wed-0', ''] + } + ].forEach(function(t) { + it('should respect time tickformat that includes ' + t.formatter, function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: ['2020-01-01', '2020-01-02'] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + tickformat: '%a-' + t.formatter + } + } + }) + .then(function() { + _assert('', t.positions, t.labels); + }) + .catch(failTest) + .then(done); + }); + }); + + [ + { + range: ['2020-12-15', '2084-12-15'], + positions: ['2020-07-01 15:00', '2030-07-02 15:00', '2040-07-01 15:00', '2050-07-02 15:00', '2060-07-01 15:00', '2070-07-02 15:00', '2080-07-01 15:00'], + labels: ['', '2030', '2040', '2050', '2060', '2070', '2080'] + }, + { + range: ['2020-12-15', '2052-12-15'], + positions: ['2020-07-01 15:00', '2025-07-02 15:00', '2030-07-02 15:00', '2035-07-02 15:00', '2040-07-01 15:00', '2045-07-02 15:00', '2050-07-02 15:00'], + labels: ['', '2025', '2030', '2035', '2040', '2045', '2050'] + }, + { + range: ['2020-12-15', '2036-12-15'], + positions: ['2020-07-01 15:00', '2022-07-02 15:00', '2024-07-01 15:00', '2026-07-02 15:00', '2028-07-01 15:00', '2030-07-02 15:00', '2032-07-01 15:00', '2034-07-02 15:00', '2036-07-01 15:00'], + labels: ['', '2022', '2024', '2026', '2028', '2030', '2032', '2034', '2036'] + }, + { + range: ['2020-12-15', '2028-12-15'], + positions: ['2020-07-02', '2021-07-02 12:00', '2022-07-02 12:00', '2023-07-02 12:00', '2024-07-02', '2025-07-02 12:00', '2026-07-02 12:00', '2027-07-02 12:00', '2028-07-01 12:00'], + labels: ['', '2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028'] + }, + { + range: ['2020-12-15', '2024-12-15'], + positions: ['2020-07-16 05:15', '2021-01-16 05:15', '2021-07-16 05:15', '2022-01-16 05:15', '2022-07-16 05:15', '2023-01-16 05:15', '2023-07-16 05:15', '2024-01-16 05:15', '2024-07-16 05:15'], + labels: ['', 'Jan 2021', 'Jul 2021', 'Jan 2022', 'Jul 2022', 'Jan 2023', 'Jul 2023', 'Jan 2024', 'Jul 2024'] + }, + { + range: ['2020-12-15', '2022-12-15'], + positions: ['2020-10-16 05:15', '2021-01-16 05:15', '2021-04-16 05:15', '2021-07-16 05:15', '2021-10-16 05:15', '2022-01-16 05:15', '2022-04-16 05:15', '2022-07-16 05:15', '2022-10-16 05:15'], + labels: ['', 'Jan 2021', 'Apr 2021', 'Jul 2021', 'Oct 2021', 'Jan 2022', 'Apr 2022', 'Jul 2022', 'Oct 2022'] + }, + { + range: ['2020-12-15', '2021-12-15'], + positions: ['2020-11-16 05:15', '2021-01-16 05:15', '2021-03-16 05:15', '2021-05-16 05:15', '2021-07-16 05:15', '2021-09-16 05:15', '2021-11-16 05:15'], + labels: ['', 'Jan 2021', 'Mar 2021', 'May 2021', 'Jul 2021', 'Sep 2021', 'Nov 2021'] + }, + { + range: ['2020-12-15', '2021-06-15'], + positions: ['2020-12-16 12:00', '2021-01-16 12:00', '2021-02-15', '2021-03-16 12:00', '2021-04-16', '2021-05-16 12:00', '2021-06-16 12:00'], + labels: ['Dec 2020', 'Jan 2021', 'Feb 2021', 'Mar 2021', 'Apr 2021', 'May 2021', ''] + }, + { + range: ['2020-12-15', '2021-02-15'], + positions: ['2020-12-13 12:00', '2020-12-20 12:00', '2020-12-27 12:00', '2021-01-03 12:00', '2021-01-10 12:00', '2021-01-17 12:00', '2021-01-24 12:00', '2021-01-31 12:00', '2021-02-07 12:00', '2021-02-14 12:00'], + labels: ['', 'Dec 20
2020', 'Dec 27', 'Jan 3
2021', 'Jan 10', 'Jan 17', 'Jan 24', 'Jan 31', 'Feb 7', 'Feb 14'] + }, + { + range: ['2020-12-15', '2021-01-15'], + positions: ['2020-12-13 12:00', '2020-12-20 12:00', '2020-12-27 12:00', '2021-01-03 12:00', '2021-01-10 12:00'], + labels: ['', 'Dec 20
2020', 'Dec 27', 'Jan 3
2021', 'Jan 10'] + }, + { + range: ['2020-12-15', '2021-01-01'], + positions: ['2020-12-14 12:00', '2020-12-16 12:00', '2020-12-18 12:00', '2020-12-20 12:00', '2020-12-22 12:00', '2020-12-24 12:00', '2020-12-26 12:00', '2020-12-28 12:00', '2020-12-30 12:00', '2021-01-01 12:00'], + labels: ['', 'Dec 16
2020', 'Dec 18', 'Dec 20', 'Dec 22', 'Dec 24', 'Dec 26', 'Dec 28', 'Dec 30', ''] + }, + { + range: ['2020-12-15', '2020-12-21'], + positions: ['2020-12-14 12:00', '2020-12-15 12:00', '2020-12-16 12:00', '2020-12-17 12:00', '2020-12-18 12:00', '2020-12-19 12:00', '2020-12-20 12:00', '2020-12-21 12:00'], + labels: ['', 'Dec 15
2020', 'Dec 16', 'Dec 17', 'Dec 18', 'Dec 19', 'Dec 20', ''] + }, + { + range: ['2020-12-15', '2020-12-16'], + positions: ['2020-12-14 21:00', '2020-12-15', '2020-12-15 03:00', '2020-12-15 06:00', '2020-12-15 09:00', '2020-12-15 12:00', '2020-12-15 15:00', '2020-12-15 18:00', '2020-12-15 21:00', '2020-12-16'], + labels: ['', '00:00
Dec 15, 2020', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00', '00:00
Dec 16, 2020'] + }, + { + range: ['2020-12-15', '2020-12-15 12:00'], + positions: ['2020-12-14 22:00', '2020-12-15', '2020-12-15 02:00', '2020-12-15 04:00', '2020-12-15 06:00', '2020-12-15 08:00', '2020-12-15 10:00', '2020-12-15 12:00'], + labels: ['', '00:00
Dec 15, 2020', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00'] + } + ].forEach(function(t) { + it('should position auto labels | range:' + t.range, function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: [ + '2020-12-15', + '2020-12-15 0:45', + '2020-12-15 1:30', + '2020-12-15 3:00', + '2020-12-15 6:00', + '2020-12-15 12:00', + '2020-12-16', + '2020-12-18', + '2020-12-24', + '2021-01-01', + '2021-01-15', + '2021-02-15', + '2021-03-15', + '2021-04-15', + '2021-05-15', + '2021-06-15', + '2021-07-01', + '2022-07-01', + '2023-07-01', + '2024-07-01', + '2025-07-01', + '2030-07-01', + '2035-07-01', + '2040-07-01', + '2080-07-01', + '2160-07-01' + ] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + range: t.range + } + } + }) + .then(function() { + _assert('', t.positions, t.labels); + }) + .catch(failTest) + .then(done); + }); + }); + + [ + { + range: ['2084-12-15', '2020-12-15'], + positions: ['2090-07-02 15:00', '2080-07-01 15:00', '2070-07-02 15:00', '2060-07-01 15:00', '2050-07-02 15:00', '2040-07-01 15:00', '2030-07-02 15:00'], + labels: ['', '2080', '2070', '2060', '2050', '2040', '2030'] + }, + { + range: ['2052-12-15', '2020-12-15'], + positions: ['2055-07-02 15:00', '2050-07-02 15:00', '2045-07-02 15:00', '2040-07-01 15:00', '2035-07-02 15:00', '2030-07-02 15:00', '2025-07-02 15:00'], + labels: ['', '2050', '2045', '2040', '2035', '2030', '2025'] + }, + { + range: ['2036-12-15', '2020-12-15'], + positions: ['2038-07-02 15:00', '2036-07-01 15:00', '2034-07-02 15:00', '2032-07-01 15:00', '2030-07-02 15:00', '2028-07-01 15:00', '2026-07-02 15:00', '2024-07-01 15:00', '2022-07-02 15:00'], + labels: ['', '2036', '2034', '2032', '2030', '2028', '2026', '2024', '2022'] + }, + { + range: ['2028-12-15', '2020-12-15'], + positions: ['2029-07-03', '2028-07-01 12:00', '2027-07-02 12:00', '2026-07-02 12:00', '2025-07-03', '2024-07-01 12:00', '2023-07-02 12:00', '2022-07-02 12:00', '2021-07-02 12:00'], + labels: ['', '2028', '2027', '2026', '2025', '2024', '2023', '2022', '2021'] + }, + { + range: ['2024-12-15', '2020-12-15'], + positions: ['2025-01-16 05:15', '2024-07-16 05:15', '2024-01-16 05:15', '2023-07-16 05:15', '2023-01-16 05:15', '2022-07-16 05:15', '2022-01-16 05:15', '2021-07-16 05:15', '2021-01-16 05:15'], + labels: ['', 'Jul 2024', 'Jan 2024', 'Jul 2023', 'Jan 2023', 'Jul 2022', 'Jan 2022', 'Jul 2021', 'Jan 2021'] + }, + { + range: ['2022-12-15', '2020-12-15'], + positions: ['2023-01-16 05:15', '2022-10-16 05:15', '2022-07-16 05:15', '2022-04-16 05:15', '2022-01-16 05:15', '2021-10-16 05:15', '2021-07-16 05:15', '2021-04-16 05:15', '2021-01-16 05:15'], + labels: ['', 'Oct 2022', 'Jul 2022', 'Apr 2022', 'Jan 2022', 'Oct 2021', 'Jul 2021', 'Apr 2021', 'Jan 2021'] + }, + { + range: ['2021-12-15', '2020-12-15'], + positions: ['2022-01-16 05:15', '2021-11-16 05:15', '2021-09-16 05:15', '2021-07-16 05:15', '2021-05-16 05:15', '2021-03-16 05:15', '2021-01-16 05:15'], + labels: ['', 'Nov 2021', 'Sep 2021', 'Jul 2021', 'May 2021', 'Mar 2021', 'Jan 2021'] + }, + { + range: ['2021-06-15', '2020-12-15'], + positions: ['2021-07-16', '2021-06-16 12:00', '2021-05-16', '2021-04-16 12:00', '2021-03-15', '2021-02-16 12:00', '2021-01-16 12:00'], + labels: ['', '', 'May 2021', 'Apr 2021', 'Mar 2021', 'Feb 2021', 'Jan 2021'] + }, + { + range: ['2021-02-15', '2020-12-15'], + positions: ['2021-02-21 12:00', '2021-02-14 12:00', '2021-02-07 12:00', '2021-01-31 12:00', '2021-01-24 12:00', '2021-01-17 12:00', '2021-01-10 12:00', '2021-01-03 12:00', '2020-12-27 12:00', '2020-12-20 12:00'], + labels: ['', 'Feb 14
2021', 'Feb 7', 'Jan 31', 'Jan 24', 'Jan 17', 'Jan 10', 'Jan 3', 'Dec 27
2020', 'Dec 20'] + }, + { + range: ['2021-01-15', '2020-12-15'], + positions: ['2021-01-17 12:00', '2021-01-10 12:00', '2021-01-03 12:00', '2020-12-27 12:00', '2020-12-20 12:00'], + labels: ['', 'Jan 10
2021', 'Jan 3', 'Dec 27
2020', 'Dec 20'] + }, + { + range: ['2021-01-01', '2020-12-15'], + positions: ['2021-01-03 12:00', '2021-01-01 12:00', '2020-12-30 12:00', '2020-12-28 12:00', '2020-12-26 12:00', '2020-12-24 12:00', '2020-12-22 12:00', '2020-12-20 12:00', '2020-12-18 12:00', '2020-12-16 12:00'], + labels: ['', '', 'Dec 30
2020', 'Dec 28', 'Dec 26', 'Dec 24', 'Dec 22', 'Dec 20', 'Dec 18', 'Dec 16'] + }, + { + range: ['2020-12-21', '2020-12-15'], + positions: ['2020-12-22 12:00', '2020-12-21 12:00', '2020-12-20 12:00', '2020-12-19 12:00', '2020-12-18 12:00', '2020-12-17 12:00', '2020-12-16 12:00', '2020-12-15 12:00'], + labels: ['', '', 'Dec 20
2020', 'Dec 19', 'Dec 18', 'Dec 17', 'Dec 16', 'Dec 15'] + }, + { + range: ['2020-12-16', '2020-12-15'], + positions: ['2020-12-16 03:00', '2020-12-16', '2020-12-15 21:00', '2020-12-15 18:00', '2020-12-15 15:00', '2020-12-15 12:00', '2020-12-15 09:00', '2020-12-15 06:00', '2020-12-15 03:00', '2020-12-15'], + labels: ['', '00:00
Dec 16, 2020', '21:00
Dec 15, 2020', '18:00', '15:00', '12:00', '09:00', '06:00', '03:00', '00:00'] + }, + { + range: ['2020-12-15 12:00', '2020-12-15'], + positions: ['2020-12-15 14:00', '2020-12-15 12:00', '2020-12-15 10:00', '2020-12-15 08:00', '2020-12-15 06:00', '2020-12-15 04:00', '2020-12-15 02:00', '2020-12-15'], + labels: ['', '12:00
Dec 15, 2020', '10:00', '08:00', '06:00', '04:00', '02:00', '00:00'] + } + ].forEach(function(t) { + it('should position auto labels | reversed range:' + t.range, function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: [ + '2020-12-15', + '2020-12-15 0:45', + '2020-12-15 1:30', + '2020-12-15 3:00', + '2020-12-15 6:00', + '2020-12-15 12:00', + '2020-12-16', + '2020-12-18', + '2020-12-24', + '2021-01-01', + '2021-01-15', + '2021-02-15', + '2021-03-15', + '2021-04-15', + '2021-05-15', + '2021-06-15', + '2021-07-01', + '2022-07-01', + '2023-07-01', + '2024-07-01', + '2025-07-01', + '2030-07-01', + '2035-07-01', + '2040-07-01', + '2080-07-01', + '2160-07-01' + ] + }], + layout: { + width: 1000, + xaxis: { + ticklabelmode: 'period', + range: t.range + } + } + }) + .then(function() { + _assert('', t.positions, t.labels); + }) + .catch(failTest) + .then(done); + }); + }); + + [ + { + range: ['2020-12-14 08:00', '2022-12-14 08:00'], + positions: ['2020-12-06 10:26:47.1429', '2021-03-07 09:50:21.4286', '2021-06-06 16:26:47.1429', '2021-09-06 16:26:47.1429', '2021-12-07 09:50:21.4286', '2022-03-06 16:26:47.1429', '2022-06-06 16:26:47.1429', '2022-09-07 01:08:34.2857', '2022-12-07 01:08:34.2857'], + labels: ['', 'Mar 2021', 'Jun 2021', 'Sep 2021', 'Dec 2021', 'Mar 2022', 'Jun 2022', 'Sep 2022', 'Dec 2022'] + }, + { + range: ['2020-12-14 08:00', '2021-08-14 08:00'], + positions: ['2020-12-06 04:17:08.5714', '2020-12-27 22:00', '2021-01-24 22:00', '2021-02-21 22:00', '2021-03-21 22:00', '2021-04-18 22:00', '2021-05-16 22:00', '2021-06-13 22:00', '2021-07-11 22:00', '2021-08-08 22:00'], + labels: ['', 'Dec 21
2020', 'Jan 18
2021', 'Feb 15', 'Mar 15', 'Apr 12', 'May 10', 'Jun 7', 'Jul 5', 'Aug 2'] + }, + { + range: ['2020-12-14 08:00', '2021-04-14 08:00'], + positions: ['2020-12-13 03:42:51.4286', '2020-12-21 11:42:51.4286', '2021-01-04 11:42:51.4286', '2021-01-18 11:42:51.4286', '2021-02-01 11:42:51.4286', '2021-02-15 11:42:51.4286', '2021-03-01 11:42:51.4286', '2021-03-15 11:42:51.4286', '2021-03-29 11:42:51.4286', '2021-04-12 11:42:51.4286'], + labels: ['', 'Dec 21
2020', 'Jan 4
2021', 'Jan 18', 'Feb 1', 'Feb 15', 'Mar 1', 'Mar 15', 'Mar 29', 'Apr 12'] + }, + { + range: ['2020-12-14 08:00', '2021-02-14 08:00'], + positions: ['2020-12-13 03:42:51.4286', '2020-12-21 10:17:08.5714', '2020-12-28 10:17:08.5714', '2021-01-04 10:17:08.5714', '2021-01-11 10:17:08.5714', '2021-01-18 10:17:08.5714', '2021-01-25 10:17:08.5714', '2021-02-01 10:17:08.5714', '2021-02-08 11:42:51.4286', '2021-02-14 13:42:51.4286'], + labels: ['', 'Dec 21
2020', 'Dec 28', 'Jan 4
2021', 'Jan 11', 'Jan 18', 'Jan 25', 'Feb 1', 'Feb 8', ''] + }, + { + range: ['2020-12-14 08:00', '2021-01-14 08:00'], + positions: ['2020-12-14 05:08:34.2857', '2020-12-16 12:17:08.5714', '2020-12-18 09:08:34.2857', '2020-12-22 12:17:08.5714', '2020-12-24 18:00', '2020-12-28 12:17:08.5714', '2020-12-30 12:17:08.5714', '2021-01-01 09:08:34.2857', '2021-01-05 12:17:08.5714', '2021-01-07 18:00', '2021-01-11 12:17:08.5714', '2021-01-13 12:17:08.5714'], + labels: ['', 'Dec 16
2020', 'Dec 18', 'Dec 22', 'Dec 24', 'Dec 28', 'Dec 30', 'Jan 1
2021', 'Jan 5', 'Jan 7', 'Jan 11', 'Jan 13'] + }, + { + range: ['2020-12-14 08:00', '2021-01-01 08:00'], + positions: ['2020-12-14 05:08:34.2857', '2020-12-16 12:17:08.5714', '2020-12-18 09:08:34.2857', '2020-12-22 12:17:08.5714', '2020-12-24 18:00', '2020-12-28 12:17:08.5714', '2020-12-30 12:17:08.5714', '2021-01-01 12:17:08.5714'], + labels: ['', 'Dec 16
2020', 'Dec 18', 'Dec 22', 'Dec 24', 'Dec 28', 'Dec 30', ''] + }, + { + range: ['2020-12-14 08:00', '2020-12-22 08:00'], + positions: ['2020-12-14 04:51:25.7143', '2020-12-15 18:00', '2020-12-16 18:00', '2020-12-17 18:00', '2020-12-18 18:00', '2020-12-21 18:00', '2020-12-22 18:00'], + labels: ['', '06:00
Dec 15, 2020', '06:00
Dec 16, 2020', '06:00
Dec 17, 2020', '06:00
Dec 18, 2020', '06:00
Dec 21, 2020', ''] + }, + { + range: ['2020-12-14 08:00', '2020-12-18 08:00'], + positions: ['2020-12-14 06:00', '2020-12-14 12:00', '2020-12-15 06:00', '2020-12-15 12:00', '2020-12-16 06:00', '2020-12-16 12:00', '2020-12-17 06:00', '2020-12-17 12:00', '2020-12-18 06:00'], + labels: ['', '12:00
Dec 14, 2020', '06:00
Dec 15, 2020', '12:00', '06:00
Dec 16, 2020', '12:00', '06:00
Dec 17, 2020', '12:00', '06:00
Dec 18, 2020'] + }, + { + range: ['2020-12-14 08:00', '2020-12-16 08:00'], + positions: ['2020-12-14 06:00', '2020-12-14 09:00', '2020-12-14 12:00', '2020-12-14 15:00', '2020-12-15 06:00', '2020-12-15 09:00', '2020-12-15 12:00', '2020-12-15 15:00', '2020-12-16 06:00'], + labels: ['', '09:00
Dec 14, 2020', '12:00', '15:00', '06:00
Dec 15, 2020', '09:00', '12:00', '15:00', '06:00
Dec 16, 2020'] + } + ].forEach(function(t) { + it('should position auto labels with rangebreaks | range:' + t.range, function(done) { + Plotly.newPlot(gd, { + data: [{ + hovertemplate: hovertemplate, + x: [ + '2020-12-14 08:00', '2020-12-14 12:00', '2020-12-14 16:00', + '2020-12-15 08:00', '2020-12-15 12:00', '2020-12-15 16:00', + '2020-12-16 08:00', '2020-12-16 12:00', '2020-12-16 16:00', + '2020-12-17 08:00', '2020-12-17 12:00', '2020-12-17 16:00', + '2020-12-18 08:00', '2020-12-18 12:00', '2020-12-18 16:00', + + '2020-12-21 08:00', '2020-12-21 12:00', '2020-12-21 16:00', + '2020-12-22 08:00', '2020-12-22 12:00', '2020-12-22 16:00', + '2020-12-23 08:00', '2020-12-23 12:00', '2020-12-23 16:00', + '2020-12-24 08:00', '2020-12-24 12:00', '2020-12-24 16:00', + '2020-12-25 08:00', '2020-12-25 12:00', '2020-12-25 16:00', + + '2020-12-28 08:00', '2020-12-28 12:00', '2020-12-28 16:00', + '2020-12-29 08:00', '2020-12-29 12:00', '2020-12-29 16:00', + '2020-12-30 08:00', '2020-12-30 12:00', '2020-12-30 16:00', + '2020-12-31 08:00', '2020-12-31 12:00', '2020-12-31 16:00', + '2021-01-01 08:00', '2021-01-01 12:00', '2021-01-01 16:00', + + '2021-01-04 08:00', '2021-01-04 12:00', '2021-01-04 16:00', + '2021-01-05 08:00', '2021-01-05 12:00', '2021-01-05 16:00', + '2021-01-06 08:00', '2021-01-06 12:00', '2021-01-06 16:00', + '2021-01-07 08:00', '2021-01-07 12:00', '2021-01-07 16:00', + '2021-01-08 08:00', '2021-01-08 12:00', '2021-01-08 16:00', + + '2021-01-11 08:00', '2021-01-11 12:00', '2021-01-11 16:00', + '2021-01-12 08:00', '2021-01-12 12:00', '2021-01-12 16:00', + '2021-01-13 08:00', '2021-01-13 12:00', '2021-01-13 16:00', + '2021-01-14 08:00', '2021-01-14 12:00', '2021-01-14 16:00', + '2021-01-15 08:00', '2021-01-15 12:00', '2021-01-15 16:00', + ] + }], + layout: { + width: 1000, + xaxis: { + rangebreaks: [{ + bounds: ['sat', 'mon'] + }, { + bounds: [18, 6], + pattern: 'hour' + }], + ticklabelmode: 'period', + range: t.range + } + } + }) + .then(function() { + _assert('', t.positions, t.labels); + }) + .catch(failTest) + .then(done); + }); + }); }); });