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');