Skip to content

Commit aec4c95

Browse files
committed
make hoveron a flaglist
with both modes enabled by default when there are points and area fills
1 parent 1d1a0f7 commit aec4c95

File tree

6 files changed

+76
-67
lines changed

6 files changed

+76
-67
lines changed

Diff for: src/traces/scatter/attributes.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ module.exports = {
9393
].join(' ')
9494
},
9595
hoveron: {
96-
valType: 'enumerated',
97-
values: ['points', 'fills'],
96+
valType: 'flaglist',
97+
flags: ['points', 'fills'],
9898
role: 'info',
9999
description: [
100100
'Do the hover effects highlight individual points (markers or',

Diff for: src/traces/scatter/defaults.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
5353
handleTextDefaults(traceIn, traceOut, layout, coerce);
5454
}
5555

56-
var dfltHoverOn = '';
56+
var dfltHoverOn = [];
5757

5858
if(subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
5959
coerce('marker.maxdisplayed');
60-
dfltHoverOn = 'points';
60+
dfltHoverOn.push('points');
6161
}
6262

6363
coerce('fill');
@@ -66,10 +66,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
6666
if(!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
6767
}
6868

69-
if(!dfltHoverOn && (traceOut.fill === 'tonext' || traceOut.fill === 'toself')) {
70-
dfltHoverOn = 'fills';
69+
if(traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
70+
dfltHoverOn.push('fills');
7171
}
72-
coerce('hoveron', dfltHoverOn || 'points');
72+
coerce('hoveron', dfltHoverOn.join('+') || 'points');
7373

7474
errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'y'});
7575
errorBarsSupplyDefaults(traceIn, traceOut, defaultColor, {axis: 'x', inherit: 'y'});

Diff for: src/traces/scatter/hover.js

+56-52
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,63 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
2626
ypx = ya.c2p(yval),
2727
pt = [xpx, ypx];
2828

29+
// look for points to hover on first, then take fills only if we
30+
// didn't find a point
31+
if(trace.hoveron.indexOf('points') !== -1) {
32+
var dx = function(di) {
33+
// scatter points: d.mrc is the calculated marker radius
34+
// adjust the distance so if you're inside the marker it
35+
// always will show up regardless of point size, but
36+
// prioritize smaller points
37+
var rad = Math.max(3, di.mrc || 0);
38+
return Math.max(Math.abs(xa.c2p(di.x) - xpx) - rad, 1 - 3 / rad);
39+
},
40+
dy = function(di) {
41+
var rad = Math.max(3, di.mrc || 0);
42+
return Math.max(Math.abs(ya.c2p(di.y) - ypx) - rad, 1 - 3 / rad);
43+
},
44+
dxy = function(di) {
45+
var rad = Math.max(3, di.mrc || 0),
46+
dx = xa.c2p(di.x) - xpx,
47+
dy = ya.c2p(di.y) - ypx;
48+
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
49+
},
50+
distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
51+
52+
Fx.getClosest(cd, distfn, pointData);
53+
54+
// skip the rest (for this trace) if we didn't find a close point
55+
if(pointData.index !== false) {
56+
57+
// the closest data point
58+
var di = cd[pointData.index],
59+
xc = xa.c2p(di.x, true),
60+
yc = ya.c2p(di.y, true),
61+
rad = di.mrc || 1;
62+
63+
Lib.extendFlat(pointData, {
64+
color: getTraceColor(trace, di),
65+
66+
x0: xc - rad,
67+
x1: xc + rad,
68+
xLabelVal: di.x,
69+
70+
y0: yc - rad,
71+
y1: yc + rad,
72+
yLabelVal: di.y
73+
});
74+
75+
if(di.tx) pointData.text = di.tx;
76+
else if(trace.text) pointData.text = trace.text;
77+
78+
ErrorBars.hoverInfo(di, trace, pointData);
79+
80+
return [pointData];
81+
}
82+
}
83+
2984
// even if hoveron is 'fills', only use it if we have polygons too
30-
if(trace.hoveron === 'fills' && trace._polygons) {
85+
if(trace.hoveron.indexOf('fills') !== -1 && trace._polygons) {
3186
var polygons = trace._polygons,
3287
polygonsIn = [],
3388
inside = false,
@@ -100,55 +155,4 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
100155
return [pointData];
101156
}
102157
}
103-
else {
104-
var dx = function(di) {
105-
// scatter points: d.mrc is the calculated marker radius
106-
// adjust the distance so if you're inside the marker it
107-
// always will show up regardless of point size, but
108-
// prioritize smaller points
109-
var rad = Math.max(3, di.mrc || 0);
110-
return Math.max(Math.abs(xa.c2p(di.x) - xpx) - rad, 1 - 3 / rad);
111-
},
112-
dy = function(di) {
113-
var rad = Math.max(3, di.mrc || 0);
114-
return Math.max(Math.abs(ya.c2p(di.y) - ypx) - rad, 1 - 3 / rad);
115-
},
116-
dxy = function(di) {
117-
var rad = Math.max(3, di.mrc || 0),
118-
dx = xa.c2p(di.x) - xpx,
119-
dy = ya.c2p(di.y) - ypx;
120-
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
121-
},
122-
distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
123-
124-
Fx.getClosest(cd, distfn, pointData);
125-
126-
// skip the rest (for this trace) if we didn't find a close point
127-
if(pointData.index === false) return;
128-
129-
// the closest data point
130-
var di = cd[pointData.index],
131-
xc = xa.c2p(di.x, true),
132-
yc = ya.c2p(di.y, true),
133-
rad = di.mrc || 1;
134-
135-
Lib.extendFlat(pointData, {
136-
color: getTraceColor(trace, di),
137-
138-
x0: xc - rad,
139-
x1: xc + rad,
140-
xLabelVal: di.x,
141-
142-
y0: yc - rad,
143-
y1: yc + rad,
144-
yLabelVal: di.y
145-
});
146-
147-
if(di.tx) pointData.text = di.tx;
148-
else if(trace.text) pointData.text = trace.text;
149-
150-
ErrorBars.hoverInfo(di, trace, pointData);
151-
152-
return [pointData];
153-
}
154158
};

Diff for: src/traces/scatterternary/defaults.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
8181
handleTextDefaults(traceIn, traceOut, layout, coerce);
8282
}
8383

84-
var dfltHoverOn = '';
84+
var dfltHoverOn = [];
8585

8686
if(subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
8787
coerce('marker.maxdisplayed');
88-
dfltHoverOn = 'points';
88+
dfltHoverOn.push('points');
8989
}
9090

9191
coerce('fill');
@@ -96,8 +96,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
9696

9797
coerce('hoverinfo', (layout._dataLength === 1) ? 'a+b+c+text' : undefined);
9898

99-
if(!dfltHoverOn && (traceOut.fill === 'tonext' || traceOut.fill === 'toself')) {
100-
dfltHoverOn = 'fills';
99+
if(traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
100+
dfltHoverOn.push('fills');
101101
}
102-
coerce('hoveron', dfltHoverOn || 'points');
102+
coerce('hoveron', dfltHoverOn.join('+') || 'points');
103103
};

Diff for: src/traces/scatterternary/hover.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
1717
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
1818
if(!scatterPointData || scatterPointData[0].index === false) return;
1919

20-
// if hoveron='fills', we don't show any point data so the label is
20+
// if hovering on a fill, we don't show any point data so the label is
2121
// unchanged from what scatter gives us.
2222
if(scatterPointData[0].index === undefined) return scatterPointData;
2323

Diff for: test/jasmine/tests/hover_label_test.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -693,10 +693,15 @@ describe('hover on fill', function() {
693693

694694
it('should work for scatterternary too', function(done) {
695695
var mock = Lib.extendDeep({}, require('@mocks/ternary_fill.json'));
696-
mock.data.forEach(function(trace) { trace.hoveron = 'fills'; });
697696

698697
Plotly.plot(createGraphDiv(), mock.data, mock.layout).then(function() {
699-
return assertLabelsCorrect([237, 163], [247.7, 166], 'trace 2');
698+
// hover over a point when that's closest, even if you're over
699+
// a fill, because by default we have hoveron='points+fills'
700+
return assertLabelsCorrect([237, 150], [240.0, 144],
701+
'trace 2Component A: 0.8Component B: 0.1Component C: 0.1');
702+
}).then(function() {
703+
// the rest are hovers over fills
704+
return assertLabelsCorrect([237, 170], [247.7, 166], 'trace 2');
700705
}).then(function() {
701706
return assertLabelsCorrect([237, 218], [266.75, 265], 'trace 1');
702707
}).then(function() {

0 commit comments

Comments
 (0)