Skip to content

Commit 69d6af9

Browse files
committed
fix hover for funnel, waterfall, heatmap, contour, box, ohlc, candlestick and histograms
- and do not support violin for now
1 parent a90f95d commit 69d6af9

File tree

17 files changed

+216
-143
lines changed

17 files changed

+216
-143
lines changed

src/traces/bar/calc.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var calcSelection = require('../scatter/calc_selection');
1818
module.exports = function calc(gd, trace) {
1919
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
2020
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
21-
var size, pos, oPos;
21+
var size, pos, origPos;
2222

2323
var sizeOpts = {
2424
msUTC: !!(trace.base || trace.base === 0)
@@ -27,13 +27,13 @@ module.exports = function calc(gd, trace) {
2727
var hasPeriod;
2828
if(trace.orientation === 'h') {
2929
size = xa.makeCalcdata(trace, 'x', sizeOpts);
30-
oPos = ya.makeCalcdata(trace, 'y');
31-
pos = alignPeriod(trace, ya, 'y', oPos);
30+
origPos = ya.makeCalcdata(trace, 'y');
31+
pos = alignPeriod(trace, ya, 'y', origPos);
3232
hasPeriod = !!trace.yperiodalignment;
3333
} else {
3434
size = ya.makeCalcdata(trace, 'y', sizeOpts);
35-
oPos = xa.makeCalcdata(trace, 'x');
36-
pos = alignPeriod(trace, xa, 'x', oPos);
35+
origPos = xa.makeCalcdata(trace, 'x');
36+
pos = alignPeriod(trace, xa, 'x', origPos);
3737
hasPeriod = !!trace.xperiodalignment;
3838
}
3939

@@ -46,7 +46,7 @@ module.exports = function calc(gd, trace) {
4646
cd[i] = { p: pos[i], s: size[i] };
4747

4848
if(hasPeriod) {
49-
cd[i].orig_p = oPos[i]; // used by hover
49+
cd[i].orig_p = origPos[i]; // used by hover
5050
}
5151

5252
if(trace.ids) {

src/traces/box/calc.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,24 @@ module.exports = function calc(gd, trace) {
3030
var valAxis, valLetter;
3131
var posAxis, posLetter;
3232

33+
var hasPeriod;
3334
if(trace.orientation === 'h') {
3435
valAxis = xa;
3536
valLetter = 'x';
3637
posAxis = ya;
3738
posLetter = 'y';
39+
hasPeriod = !!trace.yperiodalignment;
3840
} else {
3941
valAxis = ya;
4042
valLetter = 'y';
4143
posAxis = xa;
4244
posLetter = 'x';
45+
hasPeriod = !!trace.xperiodalignment;
4346
}
4447

45-
var posArray = getPos(trace, posLetter, posAxis, fullLayout[numKey]);
48+
var allPosArrays = getPosArrays(trace, posLetter, posAxis, fullLayout[numKey]);
49+
var posArray = allPosArrays[0];
50+
var origPos = allPosArrays[1];
4651
var dv = Lib.distinctVals(posArray);
4752
var posDistinct = dv.vals;
4853
var dPos = dv.minDiff / 2;
@@ -78,6 +83,9 @@ module.exports = function calc(gd, trace) {
7883

7984
cdi = {};
8085
cdi.pos = cdi[posLetter] = posi;
86+
if(hasPeriod && origPos) {
87+
cdi.orig_p = origPos[i]; // used by hover
88+
}
8189

8290
cdi.q1 = d2c('q1');
8391
cdi.med = d2c('median');
@@ -304,15 +312,15 @@ module.exports = function calc(gd, trace) {
304312
// so if you want one box
305313
// per trace, set x0 (y0) to the x (y) value or category for this trace
306314
// (or set x (y) to a constant array matching y (x))
307-
function getPos(trace, posLetter, posAxis, num) {
315+
function getPosArrays(trace, posLetter, posAxis, num) {
308316
var hasPosArray = posLetter in trace;
309317
var hasPos0 = posLetter + '0' in trace;
310318
var hasPosStep = 'd' + posLetter in trace;
311319

312320
if(hasPosArray || (hasPos0 && hasPosStep)) {
313-
var pos = posAxis.makeCalcdata(trace, posLetter);
314-
pos = alignPeriod(trace, posAxis, posLetter, pos);
315-
return pos;
321+
var origPos = posAxis.makeCalcdata(trace, posLetter);
322+
var pos = alignPeriod(trace, posAxis, posLetter, origPos);
323+
return [pos, origPos];
316324
}
317325

318326
var pos0;
@@ -340,7 +348,7 @@ function getPos(trace, posLetter, posAxis, num) {
340348
var out = new Array(len);
341349
for(var i = 0; i < len; i++) out[i] = pos0c;
342350

343-
return out;
351+
return [out];
344352
}
345353

346354
function makeBins(x, dx) {

src/traces/box/hover.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) {
143143
pointData[pLetter + '0'] = pAxis.c2p(di.pos + t.bPos - boxDeltaNeg, true);
144144
pointData[pLetter + '1'] = pAxis.c2p(di.pos + t.bPos + boxDeltaPos, true);
145145

146-
pointData[pLetter + 'LabelVal'] = di.pos;
146+
pointData[pLetter + 'LabelVal'] = di.orig_p !== undefined ? di.orig_p : di.pos;
147147

148148
var spikePosAttr = pLetter + 'Spike';
149149
pointData.spikeDistance = dxy(di) * spikePseudoDistance / hoverPseudoDistance;
@@ -257,14 +257,16 @@ function hoverOnPoints(pointData, xval, yval) {
257257
hovertemplate: trace.hovertemplate
258258
});
259259

260+
var origPos = di.orig_p;
261+
var pos = origPos !== undefined ? origPos : di.pos;
260262
var pa;
261263
if(trace.orientation === 'h') {
262264
pa = ya;
263265
closePtData.xLabelVal = pt.x;
264-
closePtData.yLabelVal = di.pos;
266+
closePtData.yLabelVal = pos;
265267
} else {
266268
pa = xa;
267-
closePtData.xLabelVal = di.pos;
269+
closePtData.xLabelVal = pos;
268270
closePtData.yLabelVal = pt.y;
269271
}
270272

src/traces/candlestick/calc.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ module.exports = function(gd, trace) {
1919
var xa = Axes.getFromId(gd, trace.xaxis);
2020
var ya = Axes.getFromId(gd, trace.yaxis);
2121

22-
var x = xa.makeCalcdata(trace, 'x');
23-
x = alignPeriod(trace, xa, 'x', x);
22+
var origX = xa.makeCalcdata(trace, 'x');
23+
var x = alignPeriod(trace, xa, 'x', origX);
2424

25-
var cd = calcCommon(gd, trace, x, ya, ptFunc);
25+
var cd = calcCommon(gd, trace, origX, x, ya, ptFunc);
2626

2727
if(cd.length) {
2828
Lib.extendFlat(cd[0].t, {

src/traces/funnel/calc.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ var BADNUM = require('../../constants/numerical').BADNUM;
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, i, cdi;
20+
var size, pos, origPos, i, cdi;
2121

22+
var hasPeriod;
2223
if(trace.orientation === 'h') {
2324
size = xa.makeCalcdata(trace, 'x');
24-
pos = ya.makeCalcdata(trace, 'y');
25-
pos = alignPeriod(trace, ya, 'y', pos);
25+
origPos = ya.makeCalcdata(trace, 'y');
26+
pos = alignPeriod(trace, ya, 'y', origPos);
27+
hasPeriod = !!trace.yperiodalignment;
2628
} else {
2729
size = ya.makeCalcdata(trace, 'y');
28-
pos = xa.makeCalcdata(trace, 'x');
29-
pos = alignPeriod(trace, xa, 'x', pos);
30+
origPos = xa.makeCalcdata(trace, 'x');
31+
pos = alignPeriod(trace, xa, 'x', origPos);
32+
hasPeriod = !!trace.xperiodalignment;
3033
}
3134

3235
// create the "calculated data" to plot
@@ -58,6 +61,10 @@ module.exports = function calc(gd, trace) {
5861

5962
trace._base[i] = -0.5 * cdi.s;
6063

64+
if(hasPeriod) {
65+
cd[i].orig_p = origPos[i]; // used by hover
66+
}
67+
6168
if(trace.ids) {
6269
cdi.id = String(trace.ids[i]);
6370
}

src/traces/heatmap/calc.js

+18-13
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,26 @@ module.exports = function calc(gd, trace) {
3131
var isHist = Registry.traceIs(trace, 'histogram');
3232
var isGL2D = Registry.traceIs(trace, 'gl2d');
3333
var zsmooth = isContour ? 'best' : trace.zsmooth;
34-
var x;
35-
var x0;
36-
var dx;
37-
var y;
38-
var y0;
39-
var dy;
40-
var z;
41-
var i;
42-
var binned;
34+
var x, x0, dx, origX;
35+
var y, y0, dy, origY;
36+
var z, i, binned;
4337

4438
// cancel minimum tick spacings (only applies to bars and boxes)
4539
xa._minDtick = 0;
4640
ya._minDtick = 0;
4741

4842
if(isHist) {
4943
binned = histogram2dCalc(gd, trace);
44+
origX = binned.orig_x;
5045
x = binned.x;
5146
x0 = binned.x0;
5247
dx = binned.dx;
48+
49+
origY = binned.orig_y;
5350
y = binned.y;
5451
y0 = binned.y0;
5552
dy = binned.dy;
53+
5654
z = binned.z;
5755
} else {
5856
var zIn = trace.z;
@@ -62,10 +60,10 @@ module.exports = function calc(gd, trace) {
6260
y = trace._y;
6361
zIn = trace._z;
6462
} else {
65-
x = trace._x = trace.x ? xa.makeCalcdata(trace, 'x') : [];
66-
y = trace.y ? ya.makeCalcdata(trace, 'y') : [];
67-
x = alignPeriod(trace, xa, 'x', x);
68-
y = alignPeriod(trace, ya, 'y', y);
63+
origX = trace.x ? xa.makeCalcdata(trace, 'x') : [];
64+
origY = trace.y ? ya.makeCalcdata(trace, 'y') : [];
65+
x = alignPeriod(trace, xa, 'x', origX);
66+
y = alignPeriod(trace, ya, 'y', origY);
6967
trace._x = x;
7068
trace._y = y;
7169
}
@@ -149,6 +147,13 @@ module.exports = function calc(gd, trace) {
149147
hovertext: trace._hovertext || trace.hovertext
150148
};
151149

150+
if(trace.xperiodalignment && origX) {
151+
cd0.orig_x = origX;
152+
}
153+
if(trace.yperiodalignment && origY) {
154+
cd0.orig_y = origY;
155+
}
156+
152157
if(xIn && xIn.length === xArray.length - 1) cd0.xCenter = xIn;
153158
if(yIn && yIn.length === yArray.length - 1) cd0.yCenter = yIn;
154159

src/traces/heatmap/hover.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,21 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay
7070
var y0 = ya.c2p(y[ny]);
7171
var y1 = ya.c2p(y[ny + 1]);
7272

73+
var _x, _y;
7374
if(contour) {
75+
_x = cd0.orig_x || x;
76+
_y = cd0.orig_y || y;
77+
7478
x1 = x0;
75-
xl = x[nx];
79+
xl = _x[nx];
7680
y1 = y0;
77-
yl = y[ny];
81+
yl = _y[ny];
7882
} else {
79-
xl = xc ? xc[nx] : ((x[nx] + x[nx + 1]) / 2);
80-
yl = yc ? yc[ny] : ((y[ny] + y[ny + 1]) / 2);
83+
_x = cd0.orig_x || xc || x;
84+
_y = cd0.orig_y || yc || y;
85+
86+
xl = xc ? _x[nx] : ((_x[nx] + _x[nx + 1]) / 2);
87+
yl = yc ? _y[ny] : ((_y[ny] + _y[ny + 1]) / 2);
8188

8289
if(xa && xa.type === 'category') xl = x[nx];
8390
if(ya && ya.type === 'category') yl = y[ny];

src/traces/histogram/calc.js

+20-9
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,19 @@ var getBinSpanLabelRound = require('./bin_label_vals');
2424
function calc(gd, trace) {
2525
var pos = [];
2626
var size = [];
27-
var pa = Axes.getFromId(gd, trace.orientation === 'h' ? trace.yaxis : trace.xaxis);
28-
var mainData = trace.orientation === 'h' ? 'y' : 'x';
27+
var isHorizontal = trace.orientation === 'h';
28+
var pa = Axes.getFromId(gd, isHorizontal ? trace.yaxis : trace.xaxis);
29+
var mainData = isHorizontal ? 'y' : 'x';
2930
var counterData = {x: 'y', y: 'x'}[mainData];
3031
var calendar = trace[mainData + 'calendar'];
32+
var hasPeriod = trace[mainData + 'periodalignment'];
3133
var cumulativeSpec = trace.cumulative;
3234
var i;
3335

3436
var binsAndPos = calcAllAutoBins(gd, trace, pa, mainData);
3537
var binSpec = binsAndPos[0];
3638
var pos0 = binsAndPos[1];
39+
var origPos = binsAndPos[2];
3740

3841
var nonuniformBins = typeof binSpec.size === 'string';
3942
var binEdges = [];
@@ -186,13 +189,21 @@ function calc(gd, trace) {
186189
b: 0
187190
};
188191

192+
if(hasPeriod) {
193+
cdi.orig_p = origPos[i];
194+
}
195+
189196
// setup hover and event data fields,
190197
// N.B. pts and "hover" positions ph0/ph1 don't seem to make much sense
191198
// for cumulative distributions
192199
if(!cumulativeSpec.enabled) {
193200
cdi.pts = inputPoints[i];
194201
if(uniqueValsPerBin) {
195-
cdi.ph0 = cdi.ph1 = (inputPoints[i].length) ? pos0[inputPoints[i][0]] : pos[i];
202+
if(hasPeriod) {
203+
cdi.ph0 = cdi.ph1 = cdi.pts.length ? origPos[cdi.pts[0]] : cdi.orig_p;
204+
} else {
205+
cdi.ph0 = cdi.ph1 = cdi.pts.length ? pos0[cdi.pts[0]] : cdi.p;
206+
}
196207
} else {
197208
// Defer evaluation of ph(0|1) in crossTraceCalc
198209
trace._computePh = true;
@@ -234,7 +245,7 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
234245
var groupName = trace['_' + mainData + 'bingroup'];
235246
var binOpts = fullLayout._histogramBinOpts[groupName];
236247
var isOverlay = fullLayout.barmode === 'overlay';
237-
var i, traces, tracei, calendar, pos0, autoVals, cumulativeSpec;
248+
var i, traces, tracei, calendar, pos0, origPos, autoVals, cumulativeSpec;
238249

239250
var r2c = function(v) { return pa.r2c(v, 0, calendar); };
240251
var c2r = function(v) { return pa.c2r(v, 0, calendar); };
@@ -273,8 +284,8 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
273284

274285
if(tracei.visible) {
275286
var mainDatai = binOpts.dirs[i];
276-
pos0 = pa.makeCalcdata(tracei, mainDatai);
277-
pos0 = alignPeriod(trace, pa, mainData, pos0);
287+
origPos = pa.makeCalcdata(tracei, mainDatai);
288+
pos0 = alignPeriod(trace, pa, mainData, origPos);
278289
tracei['_' + mainDatai + 'pos0'] = pos0;
279290

280291
allPos = Lib.concat(allPos, pos0);
@@ -323,7 +334,7 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
323334
// Several single-valued histograms! Stop infinite recursion,
324335
// just return an extra flag that tells handleSingleValueOverlays
325336
// to sort out this trace too
326-
if(_overlayEdgeCase) return [newBinSpec, pos0, true];
337+
if(_overlayEdgeCase) return [newBinSpec, pos0, origPos, true];
327338

328339
newBinSpec = handleSingleValueOverlays(gd, trace, pa, mainData, binAttr);
329340
}
@@ -410,7 +421,7 @@ function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
410421
delete trace[autoBinAttr];
411422
}
412423

413-
return [traceBinOptsCalc, pos0];
424+
return [traceBinOptsCalc, pos0, origPos, false];
414425
}
415426

416427
/*
@@ -444,7 +455,7 @@ function handleSingleValueOverlays(gd, trace, pa, mainData, binAttr) {
444455
} else {
445456
var resulti = calcAllAutoBins(gd, tracei, pa, mainData, true);
446457
var binSpeci = resulti[0];
447-
var isSingleValued = resulti[2];
458+
var isSingleValued = resulti[3];
448459

449460
// so we can use this result when we get to tracei in the normal
450461
// course of events, mark it as done and put _pos0 back

0 commit comments

Comments
 (0)