Skip to content

Fix hover with period alignment points and improve positioning of spikes and unified hover label #5846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b4bdec3
fix scattergl test
archmoj Jul 20, 2021
53fea8e
fix hover on scatter and scattergl with periods
archmoj Jul 20, 2021
2933803
fix hover on bars with period
archmoj Jul 21, 2021
775a8e0
improve and adjust jasmine tests
archmoj Jul 21, 2021
168bc75
draft log for PR 5846
archmoj Jul 21, 2021
3deca0d
drop unused line
archmoj Jul 21, 2021
7c37e98
fix typo and adjust test
archmoj Jul 21, 2021
e5a4057
scatters with period ranges
archmoj Jul 21, 2021
bd528a2
adjust scatter and bar test titles
archmoj Jul 21, 2021
85821d1
fit -> it
archmoj Jul 21, 2021
9fbd186
refactor: enter long lines
archmoj Jul 22, 2021
8a36d8f
position hover labels in respect to max and min of hoverset not the w…
archmoj Jul 22, 2021
f128cf9
for end alignment of unified hover label use minimum to avoid overlap…
archmoj Jul 22, 2021
b26fcbb
similar positioning of hover box for y unified
archmoj Jul 22, 2021
5a80515
refactor
archmoj Jul 22, 2021
9716ef0
improve unified hover box positioning
archmoj Jul 22, 2021
c62d520
edit PR log
archmoj Jul 22, 2021
21a1a93
simplify logic and handle the case of not fitting inside the subplot
archmoj Jul 22, 2021
16f4554
when the scatter point wins, OK to occlude bar & other points
archmoj Jul 22, 2021
8ed847a
fix syntax
archmoj Jul 22, 2021
30f61c8
drop out of range pixel from the end
archmoj Jul 22, 2021
dca5b1e
for x|y hovermodes display spikeline on the winning point
archmoj Jul 22, 2021
df6353d
adjust vertical and horizontal alignment of unified hover label
archmoj Jul 23, 2021
9217db4
handle end edge case
archmoj Jul 23, 2021
1c7a69d
adjustment also for winning types e.g. heatmap use scatter logic
archmoj Jul 23, 2021
f0ef7db
choose the side of the paper which is closest if unified hover did no…
archmoj Jul 23, 2021
4a0a504
update PR log
archmoj Jul 23, 2021
cd0b469
move unified hover by one pixel better help adjustment tested with pe…
archmoj Jul 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/5846_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix misplaced hover with period positioning [[#5846](https://github.com/plotly/plotly.js/pull/5846)]
5 changes: 4 additions & 1 deletion src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -1934,7 +1934,10 @@ function getCoord(axLetter, winningPoint, fullLayout) {
var val = winningPoint[axLetter + 'Val'];

if(ax.type === 'category') val = ax._categoriesMap[val];
else if(ax.type === 'date') val = ax.d2c(val);
else if(ax.type === 'date') {
var period = winningPoint[axLetter + 'Period'];
val = ax.d2c(period !== undefined ? period : val);
}

var cd0 = winningPoint.cd[winningPoint.index];
if(cd0 && cd0.t && cd0.t.posLetter === ax._id) {
Expand Down
21 changes: 16 additions & 5 deletions src/plots/cartesian/align_period.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ var constants = require('../../constants/numerical');
var ONEAVGMONTH = constants.ONEAVGMONTH;

module.exports = function alignPeriod(trace, ax, axLetter, vals) {
if(ax.type !== 'date') return vals;
if(ax.type !== 'date') return {vals: vals};

var alignment = trace[axLetter + 'periodalignment'];
if(!alignment) return vals;
if(!alignment) return {vals: vals};

var period = trace[axLetter + 'period'];
var mPeriod;
if(isNumeric(period)) {
period = +period;
if(period <= 0) return vals;
if(period <= 0) return {vals: vals};
} else if(typeof period === 'string' && period.charAt(0) === 'M') {
var n = +(period.substring(1));
if(n > 0 && Math.round(n) === n) {
mPeriod = n;
} else return vals;
} else return {vals: vals};
}

var calendar = ax.calendar;
Expand All @@ -35,6 +35,9 @@ module.exports = function alignPeriod(trace, ax, axLetter, vals) {
var base = dateTime2ms(period0, calendar) || 0;

var newVals = [];
var starts = [];
var ends = [];

var len = vals.length;
for(var i = 0; i < len; i++) {
var v = vals[i];
Expand Down Expand Up @@ -77,6 +80,14 @@ module.exports = function alignPeriod(trace, ax, axLetter, vals) {
isEnd ? endTime :
(startTime + endTime) / 2
);

starts[i] = startTime;
ends[i] = endTime;
}
return newVals;

return {
vals: newVals,
starts: starts,
ends: ends
};
};
10 changes: 6 additions & 4 deletions src/traces/bar/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ var calcSelection = require('../scatter/calc_selection');
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos;
var size, pos, origPos, pObj, hasPeriod;

var sizeOpts = {
msUTC: !!(trace.base || trace.base === 0)
};

var hasPeriod;
if(trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x', sizeOpts);
origPos = ya.makeCalcdata(trace, 'y');
pos = alignPeriod(trace, ya, 'y', origPos);
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
} else {
size = ya.makeCalcdata(trace, 'y', sizeOpts);
origPos = xa.makeCalcdata(trace, 'x');
pos = alignPeriod(trace, xa, 'x', origPos);
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
}
pos = pObj.vals;

// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
Expand All @@ -39,6 +39,8 @@ module.exports = function calc(gd, trace) {

if(hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i].pEnd = pObj.ends[i];
cd[i].pStart = pObj.starts[i];
}

if(trace.ids) {
Expand Down
8 changes: 8 additions & 0 deletions src/traces/bar/cross_trace_calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,20 @@ function setBarCenterAndWidth(pa, sieve) {
var barwidth = t.barwidth;
var barwidthIsArray = Array.isArray(barwidth);

var trace = calcTrace[0].trace;
var isPeriod = !!trace[pLetter + 'periodalignment'];

for(var j = 0; j < calcTrace.length; j++) {
var calcBar = calcTrace[j];

// store the actual bar width and position, for use by hover
var width = calcBar.w = barwidthIsArray ? barwidth[j] : barwidth;
calcBar[pLetter] = calcBar.p + (poffsetIsArray ? poffset[j] : poffset) + width / 2;

if(isPeriod) {
calcBar.wPeriod =
calcBar.pEnd - calcBar.pStart;
}
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/traces/bar/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {
function thisBarMaxPos(di) { return thisBarExtPos(di, 1); }

function thisBarExtPos(di, sgn) {
if(period) {
return di.p + sgn * Math.abs(di.p - di.orig_p);
}
return di[posLetter] + sgn * di.w / 2;
var w = (period) ? di.wPeriod : di.w;

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

var minPos = isClosest || period ?
Expand Down Expand Up @@ -180,6 +179,9 @@ function hoverOnBars(pointData, xval, yval, hovermode, opts) {

var hasPeriod = di.orig_p !== undefined;
pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p;
if(hasPeriod) {
pointData[posLetter + 'Period'] = di.p;
}

pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal'], trace[posLetter + 'hoverformat']);
pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal'], trace[sizeLetter + 'hoverformat']);
Expand Down
2 changes: 1 addition & 1 deletion src/traces/box/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ function getPosArrays(trace, posLetter, posAxis, num) {

if(hasPosArray || (hasPos0 && hasPosStep)) {
var origPos = posAxis.makeCalcdata(trace, posLetter);
var pos = alignPeriod(trace, posAxis, posLetter, origPos);
var pos = alignPeriod(trace, posAxis, posLetter, origPos).vals;
return [pos, origPos];
}

Expand Down
2 changes: 1 addition & 1 deletion src/traces/candlestick/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = function(gd, trace) {
var ya = Axes.getFromId(gd, trace.yaxis);

var origX = xa.makeCalcdata(trace, 'x');
var x = alignPeriod(trace, xa, 'x', origX);
var x = alignPeriod(trace, xa, 'x', origX).vals;

var cd = calcCommon(gd, trace, origX, x, ya, ptFunc);

Expand Down
10 changes: 6 additions & 4 deletions src/traces/funnel/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ var BADNUM = require('../../constants/numerical').BADNUM;
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos, i, cdi;
var size, pos, origPos, pObj, hasPeriod, i, cdi;

var hasPeriod;
if(trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x');
origPos = ya.makeCalcdata(trace, 'y');
pos = alignPeriod(trace, ya, 'y', origPos);
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
} else {
size = ya.makeCalcdata(trace, 'y');
origPos = xa.makeCalcdata(trace, 'x');
pos = alignPeriod(trace, xa, 'x', origPos);
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
}
pos = pObj.vals;

// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
Expand Down Expand Up @@ -55,6 +55,8 @@ module.exports = function calc(gd, trace) {

if(hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i].pEnd = pObj.ends[i];
cd[i].pStart = pObj.starts[i];
}

if(trace.ids) {
Expand Down
4 changes: 2 additions & 2 deletions src/traces/heatmap/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ module.exports = function calc(gd, trace) {
} else {
origX = trace.x ? xa.makeCalcdata(trace, 'x') : [];
origY = trace.y ? ya.makeCalcdata(trace, 'y') : [];
x = alignPeriod(trace, xa, 'x', origX);
y = alignPeriod(trace, ya, 'y', origY);
x = alignPeriod(trace, xa, 'x', origX).vals;
y = alignPeriod(trace, ya, 'y', origY).vals;
trace._x = x;
trace._y = y;
}
Expand Down
4 changes: 2 additions & 2 deletions src/traces/heatmap/convert_column_xyz.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name,
var colLen = trace._length;
var col1 = ax1.makeCalcdata(trace, var1Name);
var col2 = ax2.makeCalcdata(trace, var2Name);
col1 = alignPeriod(trace, ax1, var1Name, col1);
col2 = alignPeriod(trace, ax2, var2Name, col2);
col1 = alignPeriod(trace, ax1, var1Name, col1).vals;
col2 = alignPeriod(trace, ax2, var2Name, col2).vals;

var textCol = trace.text;
var hasColumnText = (textCol !== undefined && Lib.isArray1D(textCol));
Expand Down
2 changes: 1 addition & 1 deletion src/traces/ohlc/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function convertTickWidth(gd, xa, trace) {
var origX = xa.makeCalcdata(tracei, 'x');
tracei._origX = origX;

var xcalc = alignPeriod(trace, xa, 'x', origX);
var xcalc = alignPeriod(trace, xa, 'x', origX).vals;
tracei._xcalc = xcalc;

var _minDiff = Lib.distinctVals(xcalc).minDiff;
Expand Down
4 changes: 2 additions & 2 deletions src/traces/scatter/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ function calc(gd, trace) {
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var origX = xa.makeCalcdata(trace, 'x');
var origY = ya.makeCalcdata(trace, 'y');
var x = alignPeriod(trace, xa, 'x', origX);
var y = alignPeriod(trace, ya, 'y', origY);
var x = alignPeriod(trace, xa, 'x', origX).vals;
var y = alignPeriod(trace, ya, 'y', origY).vals;

var serieslen = trace._length;
var cd = new Array(serieslen);
Expand Down
5 changes: 3 additions & 2 deletions src/traces/scatter/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var rad = Math.max(3, di.mrc || 0);
var kink = 1 - 1 / rad;
var dxRaw = Math.abs(xa.c2p(di.x) - xpx);
if(di.orig_x !== undefined) dxRaw += xa.c2p(di.orig_x) - xa.c2p(di.x);
return (dxRaw < rad) ? (kink * dxRaw / rad) : (dxRaw - rad + kink);
};
var dy = function(di) {
var rad = Math.max(3, di.mrc || 0);
var kink = 1 - 1 / rad;
var dyRaw = Math.abs(ya.c2p(di.y) - ypx);
if(di.orig_y !== undefined) dyRaw += ya.c2p(di.orig_y) - ya.c2p(di.y);
return (dyRaw < rad) ? (kink * dyRaw / rad) : (dyRaw - rad + kink);
};
var dxy = function(di) {
Expand Down Expand Up @@ -89,6 +87,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
hovertemplate: trace.hovertemplate
});

if(di.orig_x !== undefined) pointData.xPeriod = di.x;
if(di.orig_y !== undefined) pointData.yPeriod = di.y;

fillText(di, trace, pointData);
Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData);

Expand Down
4 changes: 2 additions & 2 deletions src/traces/scattergl/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ module.exports = function calc(gd, trace) {

var origX = xa.makeCalcdata(trace, 'x');
var origY = ya.makeCalcdata(trace, 'y');
var x = alignPeriod(trace, xa, 'x', origX);
var y = alignPeriod(trace, ya, 'y', origY);
var x = alignPeriod(trace, xa, 'x', origX).vals;
var y = alignPeriod(trace, ya, 'y', origY).vals;
trace._x = x;
trace._y = y;

Expand Down
26 changes: 15 additions & 11 deletions src/traces/scattergl/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,42 +41,43 @@ function hoverPoints(pointData, xval, yval, hovermode) {

// pick the id closest to the point
// note that point possibly may not be found
var id, ptx, pty, i, dx, dy, dist, dxy;
var k, closestId, ptx, pty, i, dx, dy, dist, dxy;

var minDist = maxDistance;
if(hovermode === 'x') {
for(i = 0; i < ids.length; i++) {
ptx = x[ids[i]];
k = ids[i];
ptx = x[k];
dx = Math.abs(xa.c2p(ptx) - xpx);
if(trace._origX && trace._origX[i] !== undefined) dx += xa.c2p(trace._origX[i]) - xa.c2p(ptx);
if(dx < minDist) {
minDist = dx;
dy = ya.c2p(y[ids[i]]) - ypx;
if(trace._origY && trace._origY[i] !== undefined) dy += ya.c2p(trace._origY[i]) - ya.c2p(pty);
pty = y[k];
dy = ya.c2p(pty) - ypx;
dxy = Math.sqrt(dx * dx + dy * dy);
id = ids[i];
closestId = ids[i];
}
}
} else {
for(i = ids.length - 1; i > -1; i--) {
ptx = x[ids[i]];
pty = y[ids[i]];
k = ids[i];
ptx = x[k];
pty = y[k];
dx = xa.c2p(ptx) - xpx;
dy = ya.c2p(pty) - ypx;

dist = Math.sqrt(dx * dx + dy * dy);
if(dist < minDist) {
minDist = dxy = dist;
id = ids[i];
closestId = k;
}
}
}

pointData.index = id;
pointData.index = closestId;
pointData.distance = minDist;
pointData.dxy = dxy;

if(id === undefined) return [pointData];
if(closestId === undefined) return [pointData];

return [calcHover(pointData, x, y, trace)];
}
Expand Down Expand Up @@ -176,6 +177,9 @@ function calcHover(pointData, x, y, trace) {
hovertemplate: di.ht
});

if(origX) pointData2.xPeriod = di.x;
if(origY) pointData2.yPeriod = di.y;

if(di.htx) pointData2.text = di.htx;
else if(di.tx) pointData2.text = di.tx;
else if(trace.text) pointData2.text = trace.text;
Expand Down
10 changes: 6 additions & 4 deletions src/traces/waterfall/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ function isTotal(a) {
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos;
var size, pos, origPos, pObj, hasPeriod;

var hasPeriod;
if(trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x');
origPos = ya.makeCalcdata(trace, 'y');
pos = alignPeriod(trace, ya, 'y', origPos);
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
} else {
size = ya.makeCalcdata(trace, 'y');
origPos = xa.makeCalcdata(trace, 'x');
pos = alignPeriod(trace, xa, 'x', origPos);
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
}
pos = pObj.vals;

// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
Expand Down Expand Up @@ -85,6 +85,8 @@ module.exports = function calc(gd, trace) {

if(hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i].pEnd = pObj.ends[i];
cd[i].pStart = pObj.starts[i];
}

if(trace.ids) {
Expand Down
Loading