From 84e54e490be147aefe13b9537f1ab811f773bc78 Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 16 Mar 2020 15:20:34 -0400 Subject: [PATCH 01/12] replace rangebrekas.pattern (%w) with (week of day) --- src/plots/cartesian/layout_attributes.js | 6 ++-- src/plots/cartesian/set_convert.js | 8 ++--- test/image/mocks/axes_breaks-finance.json | 4 +-- test/image/mocks/axes_breaks-rangeslider.json | 2 +- .../axes_breaks-weekends-weeknights.json | 2 +- ...es_breaks-weekends_autorange-reversed.json | 8 ++--- test/jasmine/tests/axes_test.js | 32 +++++++++---------- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index caca53ef82e..388b20360d5 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -279,19 +279,19 @@ module.exports = { pattern: { valType: 'enumerated', // TODO could add '%H:%M:%S' - values: ['%w', '%H', ''], + values: ['day of week', '%H', ''], dflt: '', role: 'info', editType: 'calc', description: [ 'Determines a pattern on the time line that generates breaks.', - 'If *%w* - Sunday-based weekday as a decimal number [0, 6].', + 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', 'If *%H* - hour (24-hour clock) as a decimal number [0, 23].', 'These are the same directive as in `tickformat`, see', 'https://github.com/d3/d3-time-format#locale_format', 'for more info.', 'Examples:', - '- { pattern: \'%w\', bounds: [6, 0], operation: \'[]\' }', + '- { pattern: \'day of week\', bounds: [6, 0], operation: \'[]\' }', ' breaks from Saturday to Monday (i.e. skips the weekends).', '- { pattern: \'%H\', bounds: [17, 8] }', ' breaks from 5pm to 8am (i.e. skips non-work hours).' diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 7f4b834ee4e..32afd9f8809 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -625,7 +625,7 @@ module.exports = function setConvert(ax, fullLayout) { var doesCrossPeriod = false; switch(brk.pattern) { - case '%w': + case 'day of week': bnds = Lib.simpleMap(brk.bounds, cleanNumber); b0 = bnds[0]; b1 = bnds[1]; @@ -699,8 +699,8 @@ module.exports = function setConvert(ax, fullLayout) { if(!ax.rangebreaks) return rangebreaksOut; var rangebreaksIn = ax.rangebreaks.slice().sort(function(a, b) { - if(a.pattern === '%w' && b.pattern === '%H') return -1; - else if(b.pattern === '%w' && a.pattern === '%H') return 1; + if(a.pattern === 'day of week' && b.pattern === '%H') return -1; + else if(b.pattern === 'day of week' && a.pattern === '%H') return 1; return 0; }); @@ -756,7 +756,7 @@ module.exports = function setConvert(ax, fullLayout) { var t; switch(brk.pattern) { - case '%w': + case 'day of week': b0 = bnds[0] + (op0 === '(' ? 1 : 0); b1 = bnds[1]; r0Pattern = r0Date.getUTCDay(); diff --git a/test/image/mocks/axes_breaks-finance.json b/test/image/mocks/axes_breaks-finance.json index 21b7056a1b6..05c43622f4f 100644 --- a/test/image/mocks/axes_breaks-finance.json +++ b/test/image/mocks/axes_breaks-finance.json @@ -363,7 +363,7 @@ "rangeslider": { "visible": true }, "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 ] }, { @@ -376,7 +376,7 @@ "rangeslider": { "visible": true }, "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 ] }, { diff --git a/test/image/mocks/axes_breaks-rangeslider.json b/test/image/mocks/axes_breaks-rangeslider.json index f7e9bf30c0d..fecb9c2a784 100644 --- a/test/image/mocks/axes_breaks-rangeslider.json +++ b/test/image/mocks/axes_breaks-rangeslider.json @@ -2654,7 +2654,7 @@ "tickfont": {"size": 8}, "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [6, 0], "operation": "[]" }, diff --git a/test/image/mocks/axes_breaks-weekends-weeknights.json b/test/image/mocks/axes_breaks-weekends-weeknights.json index 9ac70567ba0..a6c48fca6aa 100644 --- a/test/image/mocks/axes_breaks-weekends-weeknights.json +++ b/test/image/mocks/axes_breaks-weekends-weeknights.json @@ -15,7 +15,7 @@ "xaxis": { "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 ], "operation": "[]" }, diff --git a/test/image/mocks/axes_breaks-weekends_autorange-reversed.json b/test/image/mocks/axes_breaks-weekends_autorange-reversed.json index 07911549448..cd0d5e8f59d 100644 --- a/test/image/mocks/axes_breaks-weekends_autorange-reversed.json +++ b/test/image/mocks/axes_breaks-weekends_autorange-reversed.json @@ -88,7 +88,7 @@ "xaxis": { "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 @@ -104,7 +104,7 @@ "xaxis2": { "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 @@ -149,7 +149,7 @@ "yaxis3": { "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 @@ -166,7 +166,7 @@ "yaxis4": { "rangebreaks": [ { - "pattern": "%w", + "pattern": "day of week", "bounds": [ 6, 0 diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 3f25a078996..2df57e42190 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -1125,14 +1125,14 @@ describe('Test axes', function() { it('should only coerce rangebreaks *pattern* with *bounds*', function() { layoutIn = { xaxis: {type: 'date', rangebreaks: [{bounds: ['2020-01-04', '2020-01-05']}]}, - xaxis2: {type: 'date', rangebreaks: [{bounds: [6, 0], pattern: '%w'}]}, + xaxis2: {type: 'date', rangebreaks: [{bounds: [6, 0], pattern: 'day of week'}]}, xaxis3: {type: 'date', rangebreaks: [{values: ['2020-01-04', '2020-01-05'], pattern: 'NOP'}]}, }; layoutOut._subplots.xaxis.push('x2', 'x3'); supplyLayoutDefaults(layoutIn, layoutOut, fullData); expect(layoutOut.xaxis.rangebreaks[0].pattern).toBe('', 'coerced to dflt value'); - expect(layoutOut.xaxis2.rangebreaks[0].pattern).toBe('%w', 'coerced'); + expect(layoutOut.xaxis2.rangebreaks[0].pattern).toBe('day of week', 'coerced'); expect(layoutOut.xaxis3.rangebreaks[0].pattern).toBe(undefined, 'not coerce, using *values*'); }); }); @@ -4104,7 +4104,7 @@ describe('Test axes', function() { _assert('with mixed operation values', [0, BADNUM, BADNUM, 90, 100, BADNUM, BADNUM, 200]); }); - it('should discard coords within break bounds - date %w case', function() { + it('should discard coords within break bounds - date day of week case', function() { var x = [ // Thursday '2020-01-02 08:00', '2020-01-02 16:00', @@ -4132,7 +4132,7 @@ describe('Test axes', function() { _calc({x: x}, { xaxis: { rangebreaks: [ - {pattern: '%w', bounds: [6, 0], operation: '[]'} + {pattern: 'day of week', bounds: [6, 0], operation: '[]'} ] } }); @@ -4141,7 +4141,7 @@ describe('Test axes', function() { _calc({x: x}, { xaxis: { rangebreaks: [ - {pattern: '%w', bounds: [5, 1], operation: '()'} + {pattern: 'day of week', bounds: [5, 1], operation: '()'} ] } }); @@ -4150,7 +4150,7 @@ describe('Test axes', function() { _calc({x: x}, { xaxis: { rangebreaks: [ - {pattern: '%w', bounds: [6, 1], operation: '[)'} + {pattern: 'day of week', bounds: [6, 1], operation: '[)'} ] } }); @@ -4159,7 +4159,7 @@ describe('Test axes', function() { _calc({x: x}, { xaxis: { rangebreaks: [ - {pattern: '%w', bounds: [5, 0], operation: '(]'} + {pattern: 'day of week', bounds: [5, 0], operation: '(]'} ] } }); @@ -4611,7 +4611,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [5, 1], operation: '()'} + {pattern: 'day of week', bounds: [5, 1], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4626,7 +4626,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [6, 0], operation: '[]'} + {pattern: 'day of week', bounds: [6, 0], operation: '[]'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4641,7 +4641,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [4, 6], operation: '()'} + {pattern: 'day of week', bounds: [4, 6], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4656,7 +4656,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [5, 5], operation: '[]'} + {pattern: 'day of week', bounds: [5, 5], operation: '[]'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4671,7 +4671,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [5, 5], operation: '()'} + {pattern: 'day of week', bounds: [5, 5], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4705,7 +4705,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [5, 1], operation: '()'}, + {pattern: 'day of week', bounds: [5, 1], operation: '()'}, {pattern: '%H', bounds: [17, 8], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); @@ -4729,7 +4729,7 @@ describe('Test axes', function() { .then(function() { gd.layout.xaxis.rangebreaks = [ {pattern: '%H', bounds: [17, 8], operation: '()'}, - {pattern: '%w', bounds: [5, 1], operation: '()'} + {pattern: 'day of week', bounds: [5, 1], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4772,7 +4772,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%w', bounds: [1, 4], operation: '()'} + {pattern: 'day of week', bounds: [1, 4], operation: '()'} ]; // N.B. xaxis.range[0] falls within a break gd.layout.xaxis.autorange = false; @@ -4780,7 +4780,7 @@ describe('Test axes', function() { return Plotly.react(gd, gd.data, gd.layout); }) .then(function() { - _assert('when range[0] falls within a break pattern (%w case)', 'x', { + _assert('when range[0] falls within a break pattern (day of week case)', 'x', { rangebreaks: [ ['2020-01-01 00:00:00', '2020-01-02 00:00:00'].map(Lib.dateTime2ms), ['2020-01-07 00:00:00', '2020-01-09 00:00:00'].map(Lib.dateTime2ms) From 918abcad1bcb8cb169a36ad19b78e761afb0b00f Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 16 Mar 2020 15:32:06 -0400 Subject: [PATCH 02/12] replace rangebrekas.pattern (%H) with (time of day) --- src/plots/cartesian/layout_attributes.js | 6 +++--- src/plots/cartesian/set_convert.js | 8 ++++---- .../axes_breaks-night_autorange-reversed.json | 8 ++++---- test/image/mocks/axes_breaks-rangeslider.json | 6 +++--- .../axes_breaks-weekends-weeknights.json | 2 +- test/jasmine/tests/axes_test.js | 20 +++++++++---------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 388b20360d5..e8fc1b762df 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -279,21 +279,21 @@ module.exports = { pattern: { valType: 'enumerated', // TODO could add '%H:%M:%S' - values: ['day of week', '%H', ''], + values: ['day of week', 'time of day', ''], dflt: '', role: 'info', editType: 'calc', description: [ 'Determines a pattern on the time line that generates breaks.', 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', - 'If *%H* - hour (24-hour clock) as a decimal number [0, 23].', + 'If *time of day* - hour (24-hour clock) as a decimal number [0, 23].', 'These are the same directive as in `tickformat`, see', 'https://github.com/d3/d3-time-format#locale_format', 'for more info.', 'Examples:', '- { pattern: \'day of week\', bounds: [6, 0], operation: \'[]\' }', ' breaks from Saturday to Monday (i.e. skips the weekends).', - '- { pattern: \'%H\', bounds: [17, 8] }', + '- { pattern: \'time of day\', bounds: [17, 8] }', ' breaks from 5pm to 8am (i.e. skips non-work hours).' ].join(' ') }, diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 32afd9f8809..0ebd9605892 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -632,7 +632,7 @@ module.exports = function setConvert(ax, fullLayout) { vb = (new Date(v)).getUTCDay(); if(bnds[0] > bnds[1]) doesCrossPeriod = true; break; - case '%H': + case 'time of day': bnds = Lib.simpleMap(brk.bounds, cleanNumber); b0 = bnds[0]; b1 = bnds[1]; @@ -699,8 +699,8 @@ module.exports = function setConvert(ax, fullLayout) { if(!ax.rangebreaks) return rangebreaksOut; var rangebreaksIn = ax.rangebreaks.slice().sort(function(a, b) { - if(a.pattern === 'day of week' && b.pattern === '%H') return -1; - else if(b.pattern === 'day of week' && a.pattern === '%H') return 1; + if(a.pattern === 'day of week' && b.pattern === 'time of day') return -1; + else if(b.pattern === 'day of week' && a.pattern === 'time of day') return 1; return 0; }); @@ -771,7 +771,7 @@ module.exports = function setConvert(ax, fullLayout) { r0Date.getUTCSeconds() * ONESEC - r0Date.getUTCMilliseconds(); break; - case '%H': + case 'time of day': b0 = bnds[0]; b1 = bnds[1]; r0Pattern = r0Date.getUTCHours(); diff --git a/test/image/mocks/axes_breaks-night_autorange-reversed.json b/test/image/mocks/axes_breaks-night_autorange-reversed.json index a2dcf78bf23..1c64e9a884b 100644 --- a/test/image/mocks/axes_breaks-night_autorange-reversed.json +++ b/test/image/mocks/axes_breaks-night_autorange-reversed.json @@ -192,7 +192,7 @@ "xaxis": { "rangebreaks": [ { - "pattern": "%H", + "pattern": "time of day", "bounds": [ 18, 6 @@ -208,7 +208,7 @@ "xaxis2": { "rangebreaks": [ { - "pattern": "%H", + "pattern": "time of day", "bounds": [ 18, 6 @@ -253,7 +253,7 @@ "yaxis3": { "rangebreaks": [ { - "pattern": "%H", + "pattern": "time of day", "bounds": [ 18, 6 @@ -270,7 +270,7 @@ "yaxis4": { "rangebreaks": [ { - "pattern": "%H", + "pattern": "time of day", "bounds": [ 18, 6 diff --git a/test/image/mocks/axes_breaks-rangeslider.json b/test/image/mocks/axes_breaks-rangeslider.json index fecb9c2a784..368c3b81d19 100644 --- a/test/image/mocks/axes_breaks-rangeslider.json +++ b/test/image/mocks/axes_breaks-rangeslider.json @@ -2659,17 +2659,17 @@ "operation": "[]" }, { - "pattern": "%H", + "pattern": "time of day", "bounds": [0, 9], "operation": "()" }, { - "pattern": "%H", + "pattern": "time of day", "bounds": [12, 13], "operation": "()" }, { - "pattern": "%H", + "pattern": "time of day", "bounds": [15, 21], "operation": "()" } diff --git a/test/image/mocks/axes_breaks-weekends-weeknights.json b/test/image/mocks/axes_breaks-weekends-weeknights.json index a6c48fca6aa..8331593616d 100644 --- a/test/image/mocks/axes_breaks-weekends-weeknights.json +++ b/test/image/mocks/axes_breaks-weekends-weeknights.json @@ -20,7 +20,7 @@ "operation": "[]" }, { - "pattern": "%H", + "pattern": "time of day", "bounds": [ 16, 8 ], "operation": "()" } diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 2df57e42190..524788639ab 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4166,7 +4166,7 @@ describe('Test axes', function() { _assert('(5,0]', noWeekend); }); - it('should discard coords within break bounds - date %H case', function() { + it('should discard coords within break bounds - date time of day case', function() { _calc({ x: [ '2020-01-02 08:00', '2020-01-02 20:00', @@ -4179,7 +4179,7 @@ describe('Test axes', function() { }, { xaxis: { rangebreaks: [ - {pattern: '%H', bounds: [17, 8], operation: '()'} + {pattern: 'time of day', bounds: [17, 8], operation: '()'} ] } }); @@ -4193,7 +4193,7 @@ describe('Test axes', function() { ]); }); - it('should discard coords within break bounds - date %H / high precision case', function() { + it('should discard coords within break bounds - date time of day / high precision case', function() { _calc({ x: [ '2020-01-03 17:00', @@ -4207,7 +4207,7 @@ describe('Test axes', function() { }, { xaxis: { rangebreaks: [ - {pattern: '%H', bounds: [17, 8], operation: '()'} + {pattern: 'time of day', bounds: [17, 8], operation: '()'} ] } }); @@ -4680,7 +4680,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%H', bounds: [17, 8], operation: '()'} + {pattern: 'time of day', bounds: [17, 8], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4706,7 +4706,7 @@ describe('Test axes', function() { .then(function() { gd.layout.xaxis.rangebreaks = [ {pattern: 'day of week', bounds: [5, 1], operation: '()'}, - {pattern: '%H', bounds: [17, 8], operation: '()'} + {pattern: 'time of day', bounds: [17, 8], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4728,7 +4728,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%H', bounds: [17, 8], operation: '()'}, + {pattern: 'time of day', bounds: [17, 8], operation: '()'}, {pattern: 'day of week', bounds: [5, 1], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); @@ -4751,7 +4751,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: '%H', bounds: [17, 8], operation: '()'} + {pattern: 'time of day', bounds: [17, 8], operation: '()'} ]; // N.B. xaxis.range[0] falls within a break gd.layout.xaxis.autorange = false; @@ -4759,7 +4759,7 @@ describe('Test axes', function() { return Plotly.react(gd, gd.data, gd.layout); }) .then(function() { - _assert('when range[0] falls within a break pattern (%H case)', 'x', { + _assert('when range[0] falls within a break pattern (time of day case)', 'x', { rangebreaks: [ [1577908800000, Lib.dateTime2ms('2020-01-02 08:00:00')], ['2020-01-02 17:00:00', '2020-01-03 08:00:00'].map(Lib.dateTime2ms), @@ -4917,7 +4917,7 @@ describe('Test axes', function() { ] }], { xaxis: { - rangebreaks: [{pattern: '%H', bounds: [17, 8]}] + rangebreaks: [{pattern: 'time of day', bounds: [17, 8]}] } }) .then(function() { From 0bf5ceb2e06123352a6ce271eb194853aa18866f Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 16 Mar 2020 16:03:22 -0400 Subject: [PATCH 03/12] update pattern description --- src/plots/cartesian/layout_attributes.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index e8fc1b762df..b5796ab65ea 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -287,14 +287,14 @@ module.exports = { 'Determines a pattern on the time line that generates breaks.', 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', 'If *time of day* - hour (24-hour clock) as a decimal number [0, 23].', - 'These are the same directive as in `tickformat`, see', - 'https://github.com/d3/d3-time-format#locale_format', + '*day of week* and *time of day* are similar to *%w* and *%H* directives', + 'applied in `tickformat`, see https://github.com/d3/d3-time-format#locale_format', 'for more info.', 'Examples:', - '- { pattern: \'day of week\', bounds: [6, 0], operation: \'[]\' }', + '- { pattern: \'day of week\', bounds: [6, 0] }', ' breaks from Saturday to Monday (i.e. skips the weekends).', - '- { pattern: \'time of day\', bounds: [17, 8] }', - ' breaks from 5pm to 8am (i.e. skips non-work hours).' + '- { pattern: \'time of day\', bounds: [16, 8] }', + ' breaks from 4pm to 8am (i.e. skips non-work hours).' ].join(' ') }, From d82db2e4e3d5c144fbc7ba68c5feece48a07ee5c Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 08:28:48 -0400 Subject: [PATCH 04/12] replace rangebrekas.pattern (time of day) with (hour) --- src/plots/cartesian/layout_attributes.js | 8 ++++---- src/plots/cartesian/set_convert.js | 8 ++++---- .../axes_breaks-night_autorange-reversed.json | 8 ++++---- test/image/mocks/axes_breaks-rangeslider.json | 6 +++--- .../axes_breaks-weekends-weeknights.json | 2 +- test/jasmine/tests/axes_test.js | 20 +++++++++---------- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index b5796ab65ea..d67e6292120 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -279,21 +279,21 @@ module.exports = { pattern: { valType: 'enumerated', // TODO could add '%H:%M:%S' - values: ['day of week', 'time of day', ''], + values: ['day of week', 'hour', ''], dflt: '', role: 'info', editType: 'calc', description: [ 'Determines a pattern on the time line that generates breaks.', 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', - 'If *time of day* - hour (24-hour clock) as a decimal number [0, 23].', - '*day of week* and *time of day* are similar to *%w* and *%H* directives', + 'If *hour* - hour (24-hour clock) as a decimal number [0, 23].', + '*day of week* and *hour* are similar to *%w* and *%H* directives', 'applied in `tickformat`, see https://github.com/d3/d3-time-format#locale_format', 'for more info.', 'Examples:', '- { pattern: \'day of week\', bounds: [6, 0] }', ' breaks from Saturday to Monday (i.e. skips the weekends).', - '- { pattern: \'time of day\', bounds: [16, 8] }', + '- { pattern: \'hour\', bounds: [16, 8] }', ' breaks from 4pm to 8am (i.e. skips non-work hours).' ].join(' ') }, diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 0ebd9605892..bf35af5a752 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -632,7 +632,7 @@ module.exports = function setConvert(ax, fullLayout) { vb = (new Date(v)).getUTCDay(); if(bnds[0] > bnds[1]) doesCrossPeriod = true; break; - case 'time of day': + case 'hour': bnds = Lib.simpleMap(brk.bounds, cleanNumber); b0 = bnds[0]; b1 = bnds[1]; @@ -699,8 +699,8 @@ module.exports = function setConvert(ax, fullLayout) { if(!ax.rangebreaks) return rangebreaksOut; var rangebreaksIn = ax.rangebreaks.slice().sort(function(a, b) { - if(a.pattern === 'day of week' && b.pattern === 'time of day') return -1; - else if(b.pattern === 'day of week' && a.pattern === 'time of day') return 1; + if(a.pattern === 'day of week' && b.pattern === 'hour') return -1; + else if(b.pattern === 'day of week' && a.pattern === 'hour') return 1; return 0; }); @@ -771,7 +771,7 @@ module.exports = function setConvert(ax, fullLayout) { r0Date.getUTCSeconds() * ONESEC - r0Date.getUTCMilliseconds(); break; - case 'time of day': + case 'hour': b0 = bnds[0]; b1 = bnds[1]; r0Pattern = r0Date.getUTCHours(); diff --git a/test/image/mocks/axes_breaks-night_autorange-reversed.json b/test/image/mocks/axes_breaks-night_autorange-reversed.json index 1c64e9a884b..fbc0dc878da 100644 --- a/test/image/mocks/axes_breaks-night_autorange-reversed.json +++ b/test/image/mocks/axes_breaks-night_autorange-reversed.json @@ -192,7 +192,7 @@ "xaxis": { "rangebreaks": [ { - "pattern": "time of day", + "pattern": "hour", "bounds": [ 18, 6 @@ -208,7 +208,7 @@ "xaxis2": { "rangebreaks": [ { - "pattern": "time of day", + "pattern": "hour", "bounds": [ 18, 6 @@ -253,7 +253,7 @@ "yaxis3": { "rangebreaks": [ { - "pattern": "time of day", + "pattern": "hour", "bounds": [ 18, 6 @@ -270,7 +270,7 @@ "yaxis4": { "rangebreaks": [ { - "pattern": "time of day", + "pattern": "hour", "bounds": [ 18, 6 diff --git a/test/image/mocks/axes_breaks-rangeslider.json b/test/image/mocks/axes_breaks-rangeslider.json index 368c3b81d19..a3c82646099 100644 --- a/test/image/mocks/axes_breaks-rangeslider.json +++ b/test/image/mocks/axes_breaks-rangeslider.json @@ -2659,17 +2659,17 @@ "operation": "[]" }, { - "pattern": "time of day", + "pattern": "hour", "bounds": [0, 9], "operation": "()" }, { - "pattern": "time of day", + "pattern": "hour", "bounds": [12, 13], "operation": "()" }, { - "pattern": "time of day", + "pattern": "hour", "bounds": [15, 21], "operation": "()" } diff --git a/test/image/mocks/axes_breaks-weekends-weeknights.json b/test/image/mocks/axes_breaks-weekends-weeknights.json index 8331593616d..a3513c42d75 100644 --- a/test/image/mocks/axes_breaks-weekends-weeknights.json +++ b/test/image/mocks/axes_breaks-weekends-weeknights.json @@ -20,7 +20,7 @@ "operation": "[]" }, { - "pattern": "time of day", + "pattern": "hour", "bounds": [ 16, 8 ], "operation": "()" } diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 524788639ab..c1f0eb4b401 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4166,7 +4166,7 @@ describe('Test axes', function() { _assert('(5,0]', noWeekend); }); - it('should discard coords within break bounds - date time of day case', function() { + it('should discard coords within break bounds - date hour case', function() { _calc({ x: [ '2020-01-02 08:00', '2020-01-02 20:00', @@ -4179,7 +4179,7 @@ describe('Test axes', function() { }, { xaxis: { rangebreaks: [ - {pattern: 'time of day', bounds: [17, 8], operation: '()'} + {pattern: 'hour', bounds: [17, 8], operation: '()'} ] } }); @@ -4193,7 +4193,7 @@ describe('Test axes', function() { ]); }); - it('should discard coords within break bounds - date time of day / high precision case', function() { + it('should discard coords within break bounds - date hour / high precision case', function() { _calc({ x: [ '2020-01-03 17:00', @@ -4207,7 +4207,7 @@ describe('Test axes', function() { }, { xaxis: { rangebreaks: [ - {pattern: 'time of day', bounds: [17, 8], operation: '()'} + {pattern: 'hour', bounds: [17, 8], operation: '()'} ] } }); @@ -4680,7 +4680,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: 'time of day', bounds: [17, 8], operation: '()'} + {pattern: 'hour', bounds: [17, 8], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4706,7 +4706,7 @@ describe('Test axes', function() { .then(function() { gd.layout.xaxis.rangebreaks = [ {pattern: 'day of week', bounds: [5, 1], operation: '()'}, - {pattern: 'time of day', bounds: [17, 8], operation: '()'} + {pattern: 'hour', bounds: [17, 8], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); }) @@ -4728,7 +4728,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: 'time of day', bounds: [17, 8], operation: '()'}, + {pattern: 'hour', bounds: [17, 8], operation: '()'}, {pattern: 'day of week', bounds: [5, 1], operation: '()'} ]; return Plotly.react(gd, gd.data, gd.layout); @@ -4751,7 +4751,7 @@ describe('Test axes', function() { }) .then(function() { gd.layout.xaxis.rangebreaks = [ - {pattern: 'time of day', bounds: [17, 8], operation: '()'} + {pattern: 'hour', bounds: [17, 8], operation: '()'} ]; // N.B. xaxis.range[0] falls within a break gd.layout.xaxis.autorange = false; @@ -4759,7 +4759,7 @@ describe('Test axes', function() { return Plotly.react(gd, gd.data, gd.layout); }) .then(function() { - _assert('when range[0] falls within a break pattern (time of day case)', 'x', { + _assert('when range[0] falls within a break pattern (hour case)', 'x', { rangebreaks: [ [1577908800000, Lib.dateTime2ms('2020-01-02 08:00:00')], ['2020-01-02 17:00:00', '2020-01-03 08:00:00'].map(Lib.dateTime2ms), @@ -4917,7 +4917,7 @@ describe('Test axes', function() { ] }], { xaxis: { - rangebreaks: [{pattern: 'time of day', bounds: [17, 8]}] + rangebreaks: [{pattern: 'hour', bounds: [17, 8]}] } }) .then(function() { From c0e41044ba14f95d23bd8a758ab377cb8e6044ae Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 09:11:48 -0400 Subject: [PATCH 05/12] remove refs to d3 format --- src/plots/cartesian/layout_attributes.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index d67e6292120..7d420ebf5bf 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -278,7 +278,6 @@ module.exports = { pattern: { valType: 'enumerated', - // TODO could add '%H:%M:%S' values: ['day of week', 'hour', ''], dflt: '', role: 'info', @@ -287,8 +286,6 @@ module.exports = { 'Determines a pattern on the time line that generates breaks.', 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', 'If *hour* - hour (24-hour clock) as a decimal number [0, 23].', - '*day of week* and *hour* are similar to *%w* and *%H* directives', - 'applied in `tickformat`, see https://github.com/d3/d3-time-format#locale_format', 'for more info.', 'Examples:', '- { pattern: \'day of week\', bounds: [6, 0] }', From 94f8ef86999f22e6cca10f4be3d7856507a5ff14 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 10:24:00 -0400 Subject: [PATCH 06/12] revert hour flag description - add operation fix for now --- src/plots/cartesian/layout_attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 7d420ebf5bf..7eb06c658fa 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -290,8 +290,8 @@ module.exports = { 'Examples:', '- { pattern: \'day of week\', bounds: [6, 0] }', ' breaks from Saturday to Monday (i.e. skips the weekends).', - '- { pattern: \'hour\', bounds: [16, 8] }', - ' breaks from 4pm to 8am (i.e. skips non-work hours).' + '- { pattern: \'hour\', bounds: [17, 8], operation: \'()\' }', // TODO: simplify after revise defaults + ' breaks from 5pm to 8am (i.e. skips non-work hours).' ].join(' ') }, From ee2d07af0ce5dd84242cd0738b21b056f296bf6e Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 14:16:46 -0400 Subject: [PATCH 07/12] define constants for *hour* and *day of week* flags --- src/plots/cartesian/constants.js | 3 +++ src/plots/cartesian/set_convert.js | 17 ++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/plots/cartesian/constants.js b/src/plots/cartesian/constants.js index a06eff59894..98ef0bc9f18 100644 --- a/src/plots/cartesian/constants.js +++ b/src/plots/cartesian/constants.js @@ -31,6 +31,9 @@ module.exports = { // and for 2D subplots SUBPLOT_PATTERN: /^x([0-9]*)y([0-9]*)$/, + HOUR_PATTERN: 'hour', + WEEKDAY_PATTERN: 'day of week', + // pixels to move mouse before you stop clamping to starting point MINDRAG: 8, diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index bf35af5a752..fe681244aa4 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -27,9 +27,12 @@ var ONEHOUR = numConstants.ONEHOUR; var ONEMIN = numConstants.ONEMIN; var ONESEC = numConstants.ONESEC; -var constants = require('./constants'); var axisIds = require('./axis_ids'); +var constants = require('./constants'); +var HOUR_PATTERN = constants.HOUR_PATTERN; +var WEEKDAY_PATTERN = constants.WEEKDAY_PATTERN; + function fromLog(v) { return Math.pow(10, v); } @@ -625,14 +628,14 @@ module.exports = function setConvert(ax, fullLayout) { var doesCrossPeriod = false; switch(brk.pattern) { - case 'day of week': + case WEEKDAY_PATTERN: bnds = Lib.simpleMap(brk.bounds, cleanNumber); b0 = bnds[0]; b1 = bnds[1]; vb = (new Date(v)).getUTCDay(); if(bnds[0] > bnds[1]) doesCrossPeriod = true; break; - case 'hour': + case HOUR_PATTERN: bnds = Lib.simpleMap(brk.bounds, cleanNumber); b0 = bnds[0]; b1 = bnds[1]; @@ -699,8 +702,8 @@ module.exports = function setConvert(ax, fullLayout) { if(!ax.rangebreaks) return rangebreaksOut; var rangebreaksIn = ax.rangebreaks.slice().sort(function(a, b) { - if(a.pattern === 'day of week' && b.pattern === 'hour') return -1; - else if(b.pattern === 'day of week' && a.pattern === 'hour') return 1; + if(a.pattern === WEEKDAY_PATTERN && b.pattern === HOUR_PATTERN) return -1; + if(b.pattern === WEEKDAY_PATTERN && a.pattern === HOUR_PATTERN) return 1; return 0; }); @@ -756,7 +759,7 @@ module.exports = function setConvert(ax, fullLayout) { var t; switch(brk.pattern) { - case 'day of week': + case WEEKDAY_PATTERN: b0 = bnds[0] + (op0 === '(' ? 1 : 0); b1 = bnds[1]; r0Pattern = r0Date.getUTCDay(); @@ -771,7 +774,7 @@ module.exports = function setConvert(ax, fullLayout) { r0Date.getUTCSeconds() * ONESEC - r0Date.getUTCMilliseconds(); break; - case 'hour': + case HOUR_PATTERN: b0 = bnds[0]; b1 = bnds[1]; r0Pattern = r0Date.getUTCHours(); From 8cc498ecd95a17b50967fd75913ddc86e1a47a37 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 15:03:33 -0400 Subject: [PATCH 08/12] add test for pattern integer hours over night --- test/jasmine/tests/axes_test.js | 117 ++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index c1f0eb4b401..c5c5093af80 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4222,6 +4222,123 @@ describe('Test axes', function() { ]); }); + it('should discard coords within break bounds - date hour case of [23, 1]', function() { + _calc({ + x: [ + '2020-01-01 22', + '2020-01-01 23', + '2020-01-01 23:30', + '2020-01-01 23:59', + '2020-01-01 23:59:30', + '2020-01-01 23:59:59', + '2020-01-02 00:00:00', + '2020-01-02 00:00:01', + '2020-01-02 00:00:30', + '2020-01-02 00:30', + '2020-01-02 01', + '2020-01-02 02' + ] + }, { + xaxis: { + rangebreaks: [ + {pattern: 'hour', bounds: [23, 1], operation: '()'} + ] + } + }); + _assert('with dflt operation', [ + Lib.dateTime2ms('2020-01-01 22'), + Lib.dateTime2ms('2020-01-01 23'), + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + Lib.dateTime2ms('2020-01-02 01'), + Lib.dateTime2ms('2020-01-02 02') + ]); + }); + + it('should discard coords within break bounds - date hour case of [23, 0]', function() { + _calc({ + x: [ + '2020-01-01 22', + '2020-01-01 23', + '2020-01-01 23:30', + '2020-01-01 23:59', + '2020-01-01 23:59:30', + '2020-01-01 23:59:59', + '2020-01-02 00:00:00', + '2020-01-02 00:00:01', + '2020-01-02 00:00:30', + '2020-01-02 00:30', + '2020-01-02 01', + '2020-01-02 02' + ] + }, { + xaxis: { + rangebreaks: [ + {pattern: 'hour', bounds: [23, 0], operation: '()'} + ] + } + }); + _assert('with dflt operation', [ + Lib.dateTime2ms('2020-01-01 22'), + Lib.dateTime2ms('2020-01-01 23'), + BADNUM, + BADNUM, + BADNUM, + BADNUM, + Lib.dateTime2ms('2020-01-02 00:00:00'), + Lib.dateTime2ms('2020-01-02 00:00:01'), + Lib.dateTime2ms('2020-01-02 00:00:30'), + Lib.dateTime2ms('2020-01-02 00:30'), + Lib.dateTime2ms('2020-01-02 01'), + Lib.dateTime2ms('2020-01-02 02') + ]); + }); + + it('should discard coords within break bounds - date hour case of [23, 24]', function() { + _calc({ + x: [ + '2020-01-01 22', + '2020-01-01 23', + '2020-01-01 23:30', + '2020-01-01 23:59', + '2020-01-01 23:59:30', + '2020-01-01 23:59:59', + '2020-01-02 00:00:00', + '2020-01-02 00:00:01', + '2020-01-02 00:00:30', + '2020-01-02 00:30', + '2020-01-02 01', + '2020-01-02 02' + ] + }, { + xaxis: { + rangebreaks: [ + {pattern: 'hour', bounds: [23, 24], operation: '()'} + ] + } + }); + _assert('with dflt operation', [ + Lib.dateTime2ms('2020-01-01 22'), + Lib.dateTime2ms('2020-01-01 23'), + BADNUM, + BADNUM, + BADNUM, + BADNUM, + Lib.dateTime2ms('2020-01-02 00:00:00'), + Lib.dateTime2ms('2020-01-02 00:00:01'), + Lib.dateTime2ms('2020-01-02 00:00:30'), + Lib.dateTime2ms('2020-01-02 00:30'), + Lib.dateTime2ms('2020-01-02 01'), + Lib.dateTime2ms('2020-01-02 02') + ]); + }); + it('should discard coords within [values[i], values[i] + dvalue] bounds', function() { var x = [ // Thursday From db38ce9d38ede3d4a99b1da3ecd73f631833894e Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 15:10:17 -0400 Subject: [PATCH 09/12] update description to mention integer hours - use constants for flags --- src/plots/cartesian/layout_attributes.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 7eb06c658fa..8bb41f1bfc5 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -18,6 +18,8 @@ var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK; var DATE_FORMAT_LINK = require('../../constants/docs').DATE_FORMAT_LINK; var ONEDAY = require('../../constants/numerical').ONEDAY; var constants = require('./constants'); +var HOUR = constants.HOUR_PATTERN; +var DAY_OF_WEEK = constants.WEEKDAY_PATTERN; module.exports = { visible: { @@ -278,19 +280,19 @@ module.exports = { pattern: { valType: 'enumerated', - values: ['day of week', 'hour', ''], + values: [DAY_OF_WEEK, HOUR, ''], dflt: '', role: 'info', editType: 'calc', description: [ 'Determines a pattern on the time line that generates breaks.', - 'If *day of week* - Sunday-based weekday as a decimal number [0, 6].', - 'If *hour* - hour (24-hour clock) as a decimal number [0, 23].', + 'If *' + DAY_OF_WEEK + '* - Sunday-based weekday as a decimal number [0, 6].', + 'If *' + HOUR + '* - hour (24-hour clock) as integer numbers [0, 24].', 'for more info.', 'Examples:', - '- { pattern: \'day of week\', bounds: [6, 0] }', + '- { pattern: \'' + DAY_OF_WEEK + '\', bounds: [6, 0] }', ' breaks from Saturday to Monday (i.e. skips the weekends).', - '- { pattern: \'hour\', bounds: [17, 8], operation: \'()\' }', // TODO: simplify after revise defaults + '- { pattern: \'' + HOUR + '\', bounds: [17, 8], operation: \'()\' }', // TODO: simplify after revise defaults ' breaks from 5pm to 8am (i.e. skips non-work hours).' ].join(' ') }, From 5e4ad3633babac37b5b3b05644ece3ef1e9de2af Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 16:45:38 -0400 Subject: [PATCH 10/12] simplify pattern logic in set_convert --- src/plots/cartesian/set_convert.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index fe681244aa4..5ea3bbbc58f 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -627,18 +627,19 @@ module.exports = function setConvert(ax, fullLayout) { if(brk.bounds) { var doesCrossPeriod = false; + bnds = Lib.simpleMap(brk.bounds, brk.pattern ? + cleanNumber : + ax.d2c // case of pattern: '' + ); + b0 = Math.min(bnds[0], bnds[1]); + b1 = Math.max(bnds[0], bnds[1]); + switch(brk.pattern) { case WEEKDAY_PATTERN: - bnds = Lib.simpleMap(brk.bounds, cleanNumber); - b0 = bnds[0]; - b1 = bnds[1]; vb = (new Date(v)).getUTCDay(); if(bnds[0] > bnds[1]) doesCrossPeriod = true; break; case HOUR_PATTERN: - bnds = Lib.simpleMap(brk.bounds, cleanNumber); - b0 = bnds[0]; - b1 = bnds[1]; var vDate = new Date(v); vb = vDate.getUTCHours() + ( vDate.getUTCMinutes() * ONEMIN + @@ -650,14 +651,6 @@ module.exports = function setConvert(ax, fullLayout) { case '': // N.B. should work on date axes as well! // e.g. { bounds: ['2020-01-04', '2020-01-05 23:59'] } - bnds = Lib.simpleMap(brk.bounds, ax.d2c); - if(bnds[0] <= bnds[1]) { - b0 = bnds[0]; - b1 = bnds[1]; - } else { - b0 = bnds[1]; - b1 = bnds[0]; - } // TODO should work with reversed-range axes vb = v; break; @@ -665,8 +658,8 @@ module.exports = function setConvert(ax, fullLayout) { if(doesCrossPeriod) { if( - (op0 === '(' ? vb > b0 : vb >= b0) || - (op1 === ')' ? vb < b1 : vb <= b1) + (op0 === '(' ? vb > b1 : vb >= b1) || + (op1 === ')' ? vb < b0 : vb <= b0) ) return BADNUM; } else { if( From 2d2e627011db82c38633a714bbf7521aedfdd3e3 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 17:04:17 -0400 Subject: [PATCH 11/12] refactor rangebreak handle pattern --- src/plots/cartesian/set_convert.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 5ea3bbbc58f..0d40287acef 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -614,7 +614,7 @@ module.exports = function setConvert(ax, fullLayout) { ax.maskBreaks = function(v) { var rangebreaksIn = ax.rangebreaks || []; - var bnds, b0, b1, vb; + var bnds, b0, b1, vb, vDate; for(var i = 0; i < rangebreaksIn.length; i++) { var brk = rangebreaksIn[i]; @@ -625,28 +625,27 @@ module.exports = function setConvert(ax, fullLayout) { var op1 = op.charAt(1); if(brk.bounds) { - var doesCrossPeriod = false; - - bnds = Lib.simpleMap(brk.bounds, brk.pattern ? + var pattern = brk.pattern; + bnds = Lib.simpleMap(brk.bounds, pattern ? cleanNumber : ax.d2c // case of pattern: '' ); b0 = Math.min(bnds[0], bnds[1]); b1 = Math.max(bnds[0], bnds[1]); + var doesCrossPeriod = !!(pattern && bnds[0] > bnds[1]); - switch(brk.pattern) { + switch(pattern) { case WEEKDAY_PATTERN: - vb = (new Date(v)).getUTCDay(); - if(bnds[0] > bnds[1]) doesCrossPeriod = true; + vDate = new Date(v); + vb = vDate.getUTCDay(); break; case HOUR_PATTERN: - var vDate = new Date(v); + vDate = new Date(v); vb = vDate.getUTCHours() + ( vDate.getUTCMinutes() * ONEMIN + vDate.getUTCSeconds() * ONESEC + vDate.getUTCMilliseconds() ) / ONEDAY; - if(bnds[0] > bnds[1]) doesCrossPeriod = true; break; case '': // N.B. should work on date axes as well! From a333acba5da962b1b442dd4e34a7203b1081616e Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 17 Mar 2020 18:00:10 -0400 Subject: [PATCH 12/12] handle decimal bounds and simplify cross period logic --- src/plots/cartesian/layout_attributes.js | 2 +- src/plots/cartesian/set_convert.js | 47 ++++++++++++++---------- test/jasmine/tests/axes_test.js | 39 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 8bb41f1bfc5..f2cef7d688a 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -287,7 +287,7 @@ module.exports = { description: [ 'Determines a pattern on the time line that generates breaks.', 'If *' + DAY_OF_WEEK + '* - Sunday-based weekday as a decimal number [0, 6].', - 'If *' + HOUR + '* - hour (24-hour clock) as integer numbers [0, 24].', + 'If *' + HOUR + '* - hour (24-hour clock) as decimal numbers between 0 and 24.', 'for more info.', 'Examples:', '- { pattern: \'' + DAY_OF_WEEK + '\', bounds: [6, 0] }', diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index 0d40287acef..b03d034187c 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -630,22 +630,38 @@ module.exports = function setConvert(ax, fullLayout) { cleanNumber : ax.d2c // case of pattern: '' ); - b0 = Math.min(bnds[0], bnds[1]); - b1 = Math.max(bnds[0], bnds[1]); - var doesCrossPeriod = !!(pattern && bnds[0] > bnds[1]); + b0 = bnds[0]; + b1 = bnds[1]; switch(pattern) { case WEEKDAY_PATTERN: vDate = new Date(v); vb = vDate.getUTCDay(); + + if(b0 > b1) { + b1 += 7; + if(vb < b0) vb += 7; + } + break; case HOUR_PATTERN: vDate = new Date(v); - vb = vDate.getUTCHours() + ( - vDate.getUTCMinutes() * ONEMIN + - vDate.getUTCSeconds() * ONESEC + - vDate.getUTCMilliseconds() - ) / ONEDAY; + var hours = vDate.getUTCHours(); + var minutes = vDate.getUTCMinutes(); + var seconds = vDate.getUTCSeconds(); + var milliseconds = vDate.getUTCMilliseconds(); + + vb = hours + ( + minutes / 60 + + seconds / 3600 + + milliseconds / 3600000 + ); + + if(b0 > b1) { + b1 += 24; + if(vb < b0) vb += 24; + } + break; case '': // N.B. should work on date axes as well! @@ -655,17 +671,10 @@ module.exports = function setConvert(ax, fullLayout) { break; } - if(doesCrossPeriod) { - if( - (op0 === '(' ? vb > b1 : vb >= b1) || - (op1 === ')' ? vb < b0 : vb <= b0) - ) return BADNUM; - } else { - if( - (op0 === '(' ? vb > b0 : vb >= b0) && - (op1 === ')' ? vb < b1 : vb <= b1) - ) return BADNUM; - } + if( + (op0 === '(' ? vb > b0 : vb >= b0) && + (op1 === ')' ? vb < b1 : vb <= b1) + ) return BADNUM; } else { var vals = Lib.simpleMap(brk.values, ax.d2c).sort(Lib.sorterAsc); var onOpenBound = false; diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index c5c5093af80..0f18c61353c 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4339,6 +4339,45 @@ describe('Test axes', function() { ]); }); + it('should discard coords within break bounds - date hour case of [23.75, 0.25]', function() { + _calc({ + x: [ + '2020-01-01 22', + '2020-01-01 23', + '2020-01-01 23:30', + '2020-01-01 23:59', + '2020-01-01 23:59:30', + '2020-01-01 23:59:59', + '2020-01-02 00:00:00', + '2020-01-02 00:00:01', + '2020-01-02 00:00:30', + '2020-01-02 00:30', + '2020-01-02 01', + '2020-01-02 02' + ] + }, { + xaxis: { + rangebreaks: [ + {pattern: 'hour', bounds: [23.75, 0.25]} + ] + } + }); + _assert('with dflt operation', [ + Lib.dateTime2ms('2020-01-01 22'), + Lib.dateTime2ms('2020-01-01 23'), + Lib.dateTime2ms('2020-01-01 23:30'), + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + BADNUM, + Lib.dateTime2ms('2020-01-02 00:30'), + Lib.dateTime2ms('2020-01-02 01'), + Lib.dateTime2ms('2020-01-02 02') + ]); + }); + it('should discard coords within [values[i], values[i] + dvalue] bounds', function() { var x = [ // Thursday