diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index d9d1c8384cd..612cd668815 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -90,7 +90,7 @@ module.exports = function setConvert(ax, fullLayout) { * - inserts a dummy arg so calendar is the 3rd arg (see notes below). * - defaults to ax.calendar */ - function dt2ms(v, _, calendar) { + function dt2ms(v, _, calendar, msUTC) { // NOTE: Changed this behavior: previously we took any numeric value // to be a ms, even if it was a string that could be a bare year. // Now we convert it as a date if at all possible, and only try @@ -99,6 +99,13 @@ module.exports = function setConvert(ax, fullLayout) { if(ms === BADNUM) { if(isNumeric(v)) { v = +v; + if(msUTC) { + // For now it is only used + // to fix bar length in milliseconds. + // It could be applied in other places in v2 + return v; + } + // keep track of tenths of ms, that `new Date` will drop // same logic as in Lib.ms2DateTime var msecTenths = Math.floor(Lib.mod(v + 0.05, 1) * 10); @@ -791,7 +798,7 @@ module.exports = function setConvert(ax, fullLayout) { // the first letter of ax._id?) // in case the expected data isn't there, make a list of // integers based on the opposite data - ax.makeCalcdata = function(trace, axLetter) { + ax.makeCalcdata = function(trace, axLetter, msUTC) { var arrayIn, arrayOut, i, len; var axType = ax.type; @@ -815,10 +822,10 @@ module.exports = function setConvert(ax, fullLayout) { arrayOut = new Array(len); for(i = 0; i < len; i++) { - arrayOut[i] = ax.d2c(arrayIn[i], 0, cal); + arrayOut[i] = ax.d2c(arrayIn[i], 0, cal, msUTC); } } else { - var v0 = ((axLetter + '0') in trace) ? ax.d2c(trace[axLetter + '0'], 0, cal) : 0; + var v0 = ((axLetter + '0') in trace) ? ax.d2c(trace[axLetter + '0'], 0, cal, false) : 0; var dv = (trace['d' + axLetter]) ? Number(trace['d' + axLetter]) : 1; // the opposing data, for size if we have x and dx etc diff --git a/src/traces/bar/calc.js b/src/traces/bar/calc.js index 44cb06ea147..e03d4799f24 100644 --- a/src/traces/bar/calc.js +++ b/src/traces/bar/calc.js @@ -19,11 +19,13 @@ module.exports = function calc(gd, trace) { var ya = Axes.getFromId(gd, trace.yaxis || 'y'); var size, pos; + var msUTC = !!(trace.base || trace.base === 0); + if(trace.orientation === 'h') { - size = xa.makeCalcdata(trace, 'x'); + size = xa.makeCalcdata(trace, 'x', msUTC); pos = ya.makeCalcdata(trace, 'y'); } else { - size = ya.makeCalcdata(trace, 'y'); + size = ya.makeCalcdata(trace, 'y', msUTC); pos = xa.makeCalcdata(trace, 'x'); } diff --git a/test/image/baselines/bar-with-milliseconds.png b/test/image/baselines/bar-with-milliseconds.png new file mode 100644 index 00000000000..60cd4f2448f Binary files /dev/null and b/test/image/baselines/bar-with-milliseconds.png differ diff --git a/test/image/baselines/bar_gantt-chart.png b/test/image/baselines/bar_gantt-chart.png new file mode 100644 index 00000000000..14e305ea815 Binary files /dev/null and b/test/image/baselines/bar_gantt-chart.png differ diff --git a/test/image/mocks/bar-with-milliseconds.json b/test/image/mocks/bar-with-milliseconds.json new file mode 100644 index 00000000000..09cd6f847cd --- /dev/null +++ b/test/image/mocks/bar-with-milliseconds.json @@ -0,0 +1,51 @@ +{ + "data": [ + { + "base": [ + "2020-02-02 00:00" + ], + "orientation": "h", + "type": "bar", + "x": [ + 86400000 + ], + "y": [ + 1 + ], + "yaxis": "y" + }, + { + "base": [ + "2020-02-02 00:00" + ], + "orientation": "h", + "type": "bar", + "x": [ + "1970-01-02 00:00" + ], + "y": [ + 1 + ], + "yaxis": "y2" + } + ], + "layout": { + "width": 800, + "height": 400, + "xaxis": { + "type": "date" + }, + "yaxis": { + "domain": [ + 0, + 0.45 + ] + }, + "yaxis2": { + "domain": [ + 0.55, + 1 + ] + } + } +} diff --git a/test/image/mocks/bar_gantt-chart.json b/test/image/mocks/bar_gantt-chart.json new file mode 100644 index 00000000000..4262c6e1bce --- /dev/null +++ b/test/image/mocks/bar_gantt-chart.json @@ -0,0 +1,90 @@ +{ + "data": [ + { + "base": [ + "2020-03-01", + "2020-03-05", + "2020-03-05", + "2020-03-01", + "2020-03-06", + "2020-03-01", + "2020-03-07", + "2020-03-08", + "2020-03-09" + ], + "orientation": "h", + "type": "bar", + "x": [ + 345600000, + 172800000, + 259200000, + 432000000, + 86400000, + 518400000, + 302400000, + 86400000, + 172800000 + ], + "marker": { + "colorscale": "Portland", + "color": [ + 1, + 0, + 1, + 0, + 0, + 0.9, + 0.3, + 1, + 1 + ] + }, + "y": [ + "Activity A", + "Activity B", + "Activity C", + "Activity D", + "Activity E", + "Activity F", + "Activity X", + "Activity Y", + "Activity Z" + ], + "text": [ + "4 days", + "2 days", + "3 days", + "5 days", + "1 day", + "6 days", + "3½ days", + "1 day", + "2 days" + ], + "textfont": { "size": 16 }, + "textposition": "inside", + "insidetextanchor": "middle", + "hovertemplate": "%{y}
start: %{base}
duration: %{text}
end: %{x}" + } + ], + "layout": { + "width": 1000, + "height": 500, + "title": { + "text": "Gantt chart using Plotly.js bar" + }, + "xaxis": { + "gridwidth": 5, + "tickwidth": 5, + "ticklen": 10, + "type": "date" + }, + "yaxis": { + "tickfont": { + "family": "Times New Roman", + "size": 16 + }, + "autorange": "reversed" + } + } +} diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 8fa264aa2eb..3ef5568c3c2 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -2600,6 +2600,26 @@ describe('bar hover', function() { }); }); }); + + describe('gantt chart using milliseconds from base', function() { + beforeAll(function(done) { + gd = createGraphDiv(); + + var mock = Lib.extendDeep({}, require('@mocks/bar-with-milliseconds.json')); + + Plotly.newPlot(gd, mock.data, mock.layout) + .catch(failTest) + .then(done); + }); + + it('should display the correct bar length passed in milliseconds from base', function() { + var out = _hover(gd, 0.5, 0.75, 'y'); + + var xEnd = out.style[2]; + expect(xEnd).not.toBe(1580670000000); + expect(xEnd).toBe(1580688000000); + }); + }); }); describe('Text templates on bar traces:', function() { diff --git a/test/jasmine/tests/mock_test.js b/test/jasmine/tests/mock_test.js index 17cd57d2cce..9b4280441dc 100644 --- a/test/jasmine/tests/mock_test.js +++ b/test/jasmine/tests/mock_test.js @@ -111,6 +111,7 @@ var list = [ 'bar_display_height_zero_no_line_width', 'bar_display_height_zero_only_line_width', 'bar_errorbars_inherit_color', + 'bar_gantt-chart', 'bar_group_percent', 'bar_hide_nulls', 'bar_line', @@ -137,6 +138,7 @@ var list = [ 'bar-like_traces_tozero', 'bar-marker-line-colorscales', 'bar-offsetgroups', + 'bar-with-milliseconds', 'basic_area', 'basic_bar', 'basic_error_bar', @@ -1150,6 +1152,7 @@ figs['bar_display_height_zero'] = require('@mocks/bar_display_height_zero'); figs['bar_display_height_zero_no_line_width'] = require('@mocks/bar_display_height_zero_no_line_width'); figs['bar_display_height_zero_only_line_width'] = require('@mocks/bar_display_height_zero_only_line_width'); figs['bar_errorbars_inherit_color'] = require('@mocks/bar_errorbars_inherit_color'); +figs['bar_gantt-chart'] = require('@mocks/bar_gantt-chart'); figs['bar_group_percent'] = require('@mocks/bar_group_percent'); figs['bar_hide_nulls'] = require('@mocks/bar_hide_nulls'); figs['bar_line'] = require('@mocks/bar_line'); @@ -1176,6 +1179,7 @@ figs['bar-like_traces_no-tozero_stack'] = require('@mocks/bar-like_traces_no-toz figs['bar-like_traces_tozero'] = require('@mocks/bar-like_traces_tozero'); figs['bar-marker-line-colorscales'] = require('@mocks/bar-marker-line-colorscales'); figs['bar-offsetgroups'] = require('@mocks/bar-offsetgroups'); +figs['bar-with-milliseconds'] = require('@mocks/bar-with-milliseconds'); figs['basic_area'] = require('@mocks/basic_area'); figs['basic_bar'] = require('@mocks/basic_bar'); figs['basic_error_bar'] = require('@mocks/basic_error_bar');