Skip to content

Commit 129fc2a

Browse files
authored
Merge pull request #5864 from plotly/period-hover-timezone
Fix period positioned hover to work in different time zones as well as on grouped bars
2 parents 51eded4 + 1890e77 commit 129fc2a

File tree

11 files changed

+125
-37
lines changed

11 files changed

+125
-37
lines changed

.circleci/config.yml

+32
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,35 @@ jobs:
3131
paths:
3232
- plotly.js
3333

34+
timezone-jasmine:
35+
docker:
36+
# need '-browsers' version to test in real (xvfb-wrapped) browsers
37+
- image: circleci/node:12.22.1-browsers
38+
working_directory: ~/plotly.js
39+
steps:
40+
- attach_workspace:
41+
at: ~/
42+
- run:
43+
name: Run hover_label test in UTC timezone
44+
environment:
45+
TZ: "UTC"
46+
command: date && npm run test-jasmine hover_label
47+
- run:
48+
name: Run hover_label test in Europe/Berlin timezone
49+
environment:
50+
TZ: "Europe/Berlin"
51+
command: date && npm run test-jasmine hover_label
52+
- run:
53+
name: Run hover_label test in Asia/Tokyo timezone
54+
environment:
55+
TZ: "Asia/Tokyo"
56+
command: date && npm run test-jasmine hover_label
57+
- run:
58+
name: Run hover_label test in America/Toronto timezone
59+
environment:
60+
TZ: "America/Toronto"
61+
command: date && npm run test-jasmine hover_label
62+
3463
no-gl-jasmine:
3564
docker:
3665
# need '-browsers' version to test in real (xvfb-wrapped) browsers
@@ -258,6 +287,9 @@ workflows:
258287
build-and-test:
259288
jobs:
260289
- install-and-cibuild
290+
- timezone-jasmine:
291+
requires:
292+
- install-and-cibuild
261293
- bundle-jasmine:
262294
requires:
263295
- install-and-cibuild

draftlogs/5864_fix.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix period positioned hover to work in different time zones as well as on grouped bars [[#5864](https://github.com/plotly/plotly.js/pull/5864)]

src/components/fx/hover.js

+22-3
Original file line numberDiff line numberDiff line change
@@ -1993,13 +1993,32 @@ function getCoord(axLetter, winningPoint, fullLayout) {
19931993
var ax = winningPoint[axLetter + 'a'];
19941994
var val = winningPoint[axLetter + 'Val'];
19951995

1996+
var cd0 = winningPoint.cd[0];
1997+
19961998
if(ax.type === 'category') val = ax._categoriesMap[val];
19971999
else if(ax.type === 'date') {
1998-
var period = winningPoint[axLetter + 'Period'];
1999-
val = ax.d2c(period !== undefined ? period : val);
2000+
var periodalignment = winningPoint.trace[axLetter + 'periodalignment'];
2001+
if(periodalignment) {
2002+
var d = winningPoint.cd[winningPoint.index];
2003+
2004+
var start = d[axLetter + 'Start'];
2005+
if(start === undefined) start = d[axLetter];
2006+
2007+
var end = d[axLetter + 'End'];
2008+
if(end === undefined) end = d[axLetter];
2009+
2010+
var diff = end - start;
2011+
2012+
if(periodalignment === 'end') {
2013+
val += diff;
2014+
} else if(periodalignment === 'middle') {
2015+
val += diff / 2;
2016+
}
2017+
}
2018+
2019+
val = ax.d2c(val);
20002020
}
20012021

2002-
var cd0 = winningPoint.cd[winningPoint.index];
20032022
if(cd0 && cd0.t && cd0.t.posLetter === ax._id) {
20042023
if(
20052024
fullLayout.boxmode === 'group' ||

src/traces/bar/calc.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var calcSelection = require('../scatter/calc_selection');
1010
module.exports = function calc(gd, trace) {
1111
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
1212
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
13-
var size, pos, origPos, pObj, hasPeriod;
13+
var size, pos, origPos, pObj, hasPeriod, pLetter;
1414

1515
var sizeOpts = {
1616
msUTC: !!(trace.base || trace.base === 0)
@@ -21,11 +21,13 @@ module.exports = function calc(gd, trace) {
2121
origPos = ya.makeCalcdata(trace, 'y');
2222
pObj = alignPeriod(trace, ya, 'y', origPos);
2323
hasPeriod = !!trace.yperiodalignment;
24+
pLetter = 'y';
2425
} else {
2526
size = ya.makeCalcdata(trace, 'y', sizeOpts);
2627
origPos = xa.makeCalcdata(trace, 'x');
2728
pObj = alignPeriod(trace, xa, 'x', origPos);
2829
hasPeriod = !!trace.xperiodalignment;
30+
pLetter = 'x';
2931
}
3032
pos = pObj.vals;
3133

@@ -39,8 +41,8 @@ module.exports = function calc(gd, trace) {
3941

4042
if(hasPeriod) {
4143
cd[i].orig_p = origPos[i]; // used by hover
42-
cd[i].pEnd = pObj.ends[i];
43-
cd[i].pStart = pObj.starts[i];
44+
cd[i][pLetter + 'End'] = pObj.ends[i];
45+
cd[i][pLetter + 'Start'] = pObj.starts[i];
4446
}
4547

4648
if(trace.ids) {

src/traces/bar/cross_trace_calc.js

-8
Original file line numberDiff line numberDiff line change
@@ -436,20 +436,12 @@ function setBarCenterAndWidth(pa, sieve) {
436436
var barwidth = t.barwidth;
437437
var barwidthIsArray = Array.isArray(barwidth);
438438

439-
var trace = calcTrace[0].trace;
440-
var isPeriod = !!trace[pLetter + 'periodalignment'];
441-
442439
for(var j = 0; j < calcTrace.length; j++) {
443440
var calcBar = calcTrace[j];
444441

445442
// store the actual bar width and position, for use by hover
446443
var width = calcBar.w = barwidthIsArray ? barwidth[j] : barwidth;
447444
calcBar[pLetter] = calcBar.p + (poffsetIsArray ? poffset[j] : poffset) + width / 2;
448-
449-
if(isPeriod) {
450-
calcBar.wPeriod =
451-
calcBar.pEnd - calcBar.pStart;
452-
}
453445
}
454446
}
455447
}

src/traces/bar/hover.js

+17-9
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,26 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {
5252
}
5353

5454
var period = trace[posLetter + 'period'];
55+
var isClosestOrPeriod = isClosest || period;
5556

5657
function thisBarMinPos(di) { return thisBarExtPos(di, -1); }
5758
function thisBarMaxPos(di) { return thisBarExtPos(di, 1); }
5859

5960
function thisBarExtPos(di, sgn) {
60-
var w = (period) ? di.wPeriod : di.w;
61+
var w = di.w;
6162

6263
return di[posLetter] + sgn * w / 2;
6364
}
6465

65-
var minPos = isClosest || period ?
66-
thisBarMinPos :
66+
function periodLength(di) {
67+
return di[posLetter + 'End'] - di[posLetter + 'Start'];
68+
}
69+
70+
var minPos = isClosest ?
71+
thisBarMinPos : period ?
72+
function(di) {
73+
return di.p - periodLength(di) / 2;
74+
} :
6775
function(di) {
6876
/*
6977
* In compare mode, accept a bar if you're on it *or* its group.
@@ -80,8 +88,11 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {
8088
return Math.min(thisBarMinPos(di), di.p - t.bardelta / 2);
8189
};
8290

83-
var maxPos = isClosest || period ?
84-
thisBarMaxPos :
91+
var maxPos = isClosest ?
92+
thisBarMaxPos : period ?
93+
function(di) {
94+
return di.p + periodLength(di) / 2;
95+
} :
8596
function(di) {
8697
return Math.max(thisBarMaxPos(di), di.p + t.bardelta / 2);
8798
};
@@ -156,7 +167,7 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {
156167
// if we get here and we're not in 'closest' mode, push min/max pos back
157168
// onto the group - even though that means occasionally the mouse will be
158169
// over the hover label.
159-
if(!isClosest) {
170+
if(!isClosestOrPeriod) {
160171
minPos = function(di) {
161172
return Math.min(thisBarMinPos(di), di.p - t.bargroupwidth / 2);
162173
};
@@ -179,9 +190,6 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {
179190

180191
var hasPeriod = di.orig_p !== undefined;
181192
pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p;
182-
if(hasPeriod) {
183-
pointData[posLetter + 'Period'] = di.p;
184-
}
185193

186194
pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal'], trace[posLetter + 'hoverformat']);
187195
pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal'], trace[sizeLetter + 'hoverformat']);

src/traces/funnel/calc.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,20 @@ var BADNUM = require('../../constants/numerical').BADNUM;
99
module.exports = function calc(gd, trace) {
1010
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
1111
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
12-
var size, pos, origPos, pObj, hasPeriod, i, cdi;
12+
var size, pos, origPos, pObj, hasPeriod, pLetter, i, cdi;
1313

1414
if(trace.orientation === 'h') {
1515
size = xa.makeCalcdata(trace, 'x');
1616
origPos = ya.makeCalcdata(trace, 'y');
1717
pObj = alignPeriod(trace, ya, 'y', origPos);
1818
hasPeriod = !!trace.yperiodalignment;
19+
pLetter = 'y';
1920
} else {
2021
size = ya.makeCalcdata(trace, 'y');
2122
origPos = xa.makeCalcdata(trace, 'x');
2223
pObj = alignPeriod(trace, xa, 'x', origPos);
2324
hasPeriod = !!trace.xperiodalignment;
25+
pLetter = 'x';
2426
}
2527
pos = pObj.vals;
2628

@@ -55,8 +57,8 @@ module.exports = function calc(gd, trace) {
5557

5658
if(hasPeriod) {
5759
cd[i].orig_p = origPos[i]; // used by hover
58-
cd[i].pEnd = pObj.ends[i];
59-
cd[i].pStart = pObj.starts[i];
60+
cd[i][pLetter + 'End'] = pObj.ends[i];
61+
cd[i][pLetter + 'Start'] = pObj.starts[i];
6062
}
6163

6264
if(trace.ids) {

src/traces/scatter/hover.js

-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,6 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
112112
hovertemplate: trace.hovertemplate
113113
});
114114

115-
if(trace.xperiodalignment === 'end') pointData.xPeriod = di.x;
116-
if(trace.yperiodalignment === 'end') pointData.yPeriod = di.y;
117-
118115
fillText(di, trace, pointData);
119116
Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData);
120117

src/traces/scattergl/hover.js

-3
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,6 @@ function calcHover(pointData, x, y, trace) {
202202
hovertemplate: di.ht
203203
});
204204

205-
if(trace.xperiodalignment === 'end') pointData2.xPeriod = di.x;
206-
if(trace.yperiodalignment === 'end') pointData2.yPeriod = di.y;
207-
208205
if(di.htx) pointData2.text = di.htx;
209206
else if(di.tx) pointData2.text = di.tx;
210207
else if(trace.text) pointData2.text = trace.text;

src/traces/waterfall/calc.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@ function isTotal(a) {
1717
module.exports = function calc(gd, trace) {
1818
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
1919
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
20-
var size, pos, origPos, pObj, hasPeriod;
20+
var size, pos, origPos, pObj, hasPeriod, pLetter;
2121

2222
if(trace.orientation === 'h') {
2323
size = xa.makeCalcdata(trace, 'x');
2424
origPos = ya.makeCalcdata(trace, 'y');
2525
pObj = alignPeriod(trace, ya, 'y', origPos);
2626
hasPeriod = !!trace.yperiodalignment;
27+
pLetter = 'y';
2728
} else {
2829
size = ya.makeCalcdata(trace, 'y');
2930
origPos = xa.makeCalcdata(trace, 'x');
3031
pObj = alignPeriod(trace, xa, 'x', origPos);
3132
hasPeriod = !!trace.xperiodalignment;
33+
pLetter = 'x';
3234
}
3335
pos = pObj.vals;
3436

@@ -85,8 +87,8 @@ module.exports = function calc(gd, trace) {
8587

8688
if(hasPeriod) {
8789
cd[i].orig_p = origPos[i]; // used by hover
88-
cd[i].pEnd = pObj.ends[i];
89-
cd[i].pStart = pObj.starts[i];
90+
cd[i][pLetter + 'End'] = pObj.ends[i];
91+
cd[i][pLetter + 'Start'] = pObj.starts[i];
9092
}
9193

9294
if(trace.ids) {

test/jasmine/tests/hover_label_test.js

+38-2
Original file line numberDiff line numberDiff line change
@@ -5433,14 +5433,14 @@ describe('hovermode: (x|y)unified', function() {
54335433
}
54345434
})
54355435
.then(function(gd) {
5436-
_hover(gd, { xpx: 50, ypx: 200 });
5436+
_hover(gd, { xpx: 100, ypx: 200 });
54375437
assertLabel({title: 'Jan', items: [
54385438
'bar : 1',
54395439
'one : 1',
54405440
'two : 1',
54415441
]});
54425442

5443-
_hover(gd, { xpx: 350, ypx: 200 });
5443+
_hover(gd, { xpx: 300, ypx: 200 });
54445444
assertLabel({title: 'Feb', items: [
54455445
'bar : 2',
54465446
'one : 2',
@@ -5581,12 +5581,48 @@ describe('hovermode: (x|y)unified', function() {
55815581

55825582
Plotly.newPlot(gd, fig)
55835583
.then(function(gd) {
5584+
_hover(gd, { xpx: 50, ypx: 200 });
5585+
assertLabel({title: 'Jan 1, 1970', items: [
5586+
'trace 0 : 11',
5587+
'trace 1 : 1'
5588+
]});
5589+
55845590
_hover(gd, { xpx: 100, ypx: 200 });
55855591
assertLabel({title: 'Jan 1, 1970', items: [
55865592
'trace 0 : 11',
55875593
'trace 1 : 1'
55885594
]});
55895595

5596+
_hover(gd, { xpx: 150, ypx: 200 });
5597+
assertLabel({title: 'Jul 1, 1970', items: [
5598+
'trace 0 : 12',
5599+
'trace 1 : 2'
5600+
]});
5601+
5602+
_hover(gd, { xpx: 200, ypx: 200 });
5603+
assertLabel({title: 'Jul 1, 1970', items: [
5604+
'trace 0 : 12',
5605+
'trace 1 : 2'
5606+
]});
5607+
5608+
_hover(gd, { xpx: 250, ypx: 200 });
5609+
assertLabel({title: 'Jul 1, 1970', items: [
5610+
'trace 0 : 12',
5611+
'trace 1 : 2'
5612+
]});
5613+
5614+
_hover(gd, { xpx: 300, ypx: 200 });
5615+
assertLabel({title: 'Jan 1, 1971', items: [
5616+
'trace 0 : 13',
5617+
'trace 1 : 3'
5618+
]});
5619+
5620+
_hover(gd, { xpx: 350, ypx: 200 });
5621+
assertLabel({title: 'Jan 1, 1971', items: [
5622+
'trace 0 : 13',
5623+
'trace 1 : 3'
5624+
]});
5625+
55905626
_hover(gd, { xpx: 400, ypx: 200 });
55915627
assertLabel({title: 'Jan 1, 1971', items: [
55925628
'trace 0 : 13',

0 commit comments

Comments
 (0)