Skip to content

Commit c09d2e4

Browse files
authored
Merge pull request #2055 from plotly/arrayok-hoverinfo-fixups
ArrayOk hoverinfo fixups
2 parents a1a68fb + 3931273 commit c09d2e4

25 files changed

+731
-439
lines changed

src/components/drawing/index.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -443,12 +443,10 @@ drawing.tryColorscale = function(marker, prefix) {
443443
var TEXTOFFSETSIGN = {start: 1, end: -1, middle: 0, bottom: 1, top: -1};
444444
drawing.textPointStyle = function(s, trace, gd) {
445445
s.each(function(d) {
446-
var p = d3.select(this),
447-
text = d.tx || trace.text;
446+
var p = d3.select(this);
447+
var text = Lib.extractOption(d, trace, 'tx', 'text');
448448

449-
if(!text || Array.isArray(text)) {
450-
// isArray test handles the case of (intentionally) missing
451-
// or empty text within a text array
449+
if(!text) {
452450
p.remove();
453451
return;
454452
}
@@ -889,6 +887,9 @@ drawing.setTextPointsScale = function(selection, xScale, yScale) {
889887
var transforms;
890888
var el = d3.select(this);
891889
var text = el.select('text');
890+
891+
if(!text.node()) return;
892+
892893
var x = parseFloat(text.attr('x') || 0);
893894
var y = parseFloat(text.attr('y') || 0);
894895

src/components/fx/hover.js

+12-14
Original file line numberDiff line numberDiff line change
@@ -1028,24 +1028,22 @@ function alignHoverText(hoverLabels, rotateLabels) {
10281028
}
10291029

10301030
function cleanPoint(d, hovermode) {
1031+
var index = d.index;
10311032
var trace = d.trace || {};
10321033
var cd0 = d.cd[0];
1033-
var cd = d.cd[d.index] || {};
1034+
var cd = d.cd[index] || {};
1035+
1036+
var getVal = Array.isArray(index) ?
1037+
function(calcKey, traceKey) {
1038+
return Lib.castOption(cd0, index, calcKey) ||
1039+
Lib.extractOption({}, trace, '', traceKey);
1040+
} :
1041+
function(calcKey, traceKey) {
1042+
return Lib.extractOption(cd, trace, calcKey, traceKey);
1043+
};
10341044

10351045
function fill(key, calcKey, traceKey) {
1036-
var val;
1037-
1038-
if(cd[calcKey]) {
1039-
val = cd[calcKey];
1040-
} else if(cd0[calcKey]) {
1041-
var arr = cd0[calcKey];
1042-
if(Array.isArray(arr) && Array.isArray(arr[d.index[0]])) {
1043-
val = arr[d.index[0]][d.index[1]];
1044-
}
1045-
} else {
1046-
val = Lib.nestedProperty(trace, traceKey).get();
1047-
}
1048-
1046+
var val = getVal(calcKey, traceKey);
10491047
if(val) d[key] = val;
10501048
}
10511049

src/lib/index.js

+20
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,26 @@ lib.castOption = function(trace, ptNumber, astr, fn) {
437437
}
438438
};
439439

440+
/** Extract option from calcdata item, correctly falling back to
441+
* trace value if not found.
442+
*
443+
* @param {object} calcPt : calcdata[i][j] item
444+
* @param {object} trace : (full) trace object
445+
* @param {string} calcKey : calcdata key
446+
* @param {string} traceKey : aka trace attribute string
447+
* @return {any}
448+
*/
449+
lib.extractOption = function(calcPt, trace, calcKey, traceKey) {
450+
if(calcKey in calcPt) return calcPt[calcKey];
451+
452+
// fallback to trace value,
453+
// must check if value isn't itself an array
454+
// which means the trace attribute has a corresponding
455+
// calcdata key, but its value is falsy
456+
var traceVal = lib.nestedProperty(trace, traceKey).get();
457+
if(!Array.isArray(traceVal)) return traceVal;
458+
};
459+
440460
/** Returns target as set by 'target' transform attribute
441461
*
442462
* @param {object} trace : full trace object

src/traces/bar/hover.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
var Fx = require('../../components/fx');
1313
var ErrorBars = require('../../components/errorbars');
1414
var Color = require('../../components/color');
15-
15+
var fillHoverText = require('../scatter/fill_hover_text');
1616

1717
module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
1818
var cd = pointData.cd;
@@ -99,11 +99,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
9999
pointData.xLabelVal = di.p;
100100
}
101101

102-
if(di.htx) pointData.text = di.htx;
103-
else if(trace.hovertext) pointData.text = trace.hovertext;
104-
else if(di.tx) pointData.text = di.tx;
105-
else if(trace.text) pointData.text = trace.text;
106-
102+
fillHoverText(di, trace, pointData);
107103
ErrorBars.hoverInfo(di, trace, pointData);
108104

109105
return [pointData];

src/traces/choropleth/attributes.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,9 @@ module.exports = extendFlat({
3434
editType: 'calc',
3535
description: 'Sets the color values.'
3636
},
37-
text: {
38-
valType: 'data_array',
39-
editType: 'calc',
37+
text: extendFlat({}, ScatterGeoAttrs.text, {
4038
description: 'Sets the text elements associated with each location.'
41-
},
39+
}),
4240
marker: {
4341
line: {
4442
color: ScatterGeoMarkerLineAttrs.color,

src/traces/choropleth/hover.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
var Axes = require('../../plots/cartesian/axes');
1313
var attributes = require('./attributes');
14+
var fillHoverText = require('../scatter/fill_hover_text');
1415

1516
module.exports = function hoverPoints(pointData, xval, yval) {
1617
var cd = pointData.cd;
@@ -53,17 +54,17 @@ module.exports = function hoverPoints(pointData, xval, yval) {
5354
};
5455

5556
function makeHoverInfo(pointData, trace, pt, axis) {
56-
var hoverinfo = trace.hoverinfo;
57+
var hoverinfo = pt.hi || trace.hoverinfo;
5758

5859
var parts = (hoverinfo === 'all') ?
5960
attributes.hoverinfo.flags :
6061
hoverinfo.split('+');
6162

62-
var hasName = (parts.indexOf('name') !== -1),
63-
hasLocation = (parts.indexOf('location') !== -1),
64-
hasZ = (parts.indexOf('z') !== -1),
65-
hasText = (parts.indexOf('text') !== -1),
66-
hasIdAsNameLabel = !hasName && hasLocation;
63+
var hasName = (parts.indexOf('name') !== -1);
64+
var hasLocation = (parts.indexOf('location') !== -1);
65+
var hasZ = (parts.indexOf('z') !== -1);
66+
var hasText = (parts.indexOf('text') !== -1);
67+
var hasIdAsNameLabel = !hasName && hasLocation;
6768

6869
var text = [];
6970

@@ -79,7 +80,9 @@ function makeHoverInfo(pointData, trace, pt, axis) {
7980
}
8081

8182
if(hasZ) text.push(formatter(pt.z));
82-
if(hasText) text.push(pt.tx);
83+
if(hasText) {
84+
fillHoverText(pt, trace, text);
85+
}
8386

8487
pointData.extraText = text.join('<br>');
8588
}

src/traces/scatter/fill_hover_text.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright 2012-2017, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Lib = require('../../lib');
12+
13+
/** Fill hover 'pointData' container with 'correct' hover text value
14+
*
15+
* - If trace hoverinfo contains a 'text' flag and hovertext is not set,
16+
* the text elements will be seen in the hover labels.
17+
*
18+
* - If trace hoverinfo contains a 'text' flag and hovertext is set,
19+
* hovertext takes precedence over text
20+
* i.e. the hoverinfo elements will be seen in the hover labels
21+
*
22+
* @param {object} calcPt
23+
* @param {object} trace
24+
* @param {object || array} contOut (mutated here)
25+
*/
26+
module.exports = function fillHoverText(calcPt, trace, contOut) {
27+
var fill = Array.isArray(contOut) ?
28+
function(v) { contOut.push(v); } :
29+
function(v) { contOut.text = v; };
30+
31+
var htx = Lib.extractOption(calcPt, trace, 'htx', 'hovertext');
32+
if(isValid(htx)) return fill(htx);
33+
34+
var tx = Lib.extractOption(calcPt, trace, 'tx', 'text');
35+
if(isValid(tx)) return fill(tx);
36+
};
37+
38+
// accept all truthy values and 0 (which gets cast to '0' in the hover labels)
39+
function isValid(v) {
40+
return v || v === 0;
41+
}

src/traces/scatter/hover.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var Lib = require('../../lib');
1312
var Fx = require('../../components/fx');
1413
var ErrorBars = require('../../components/errorbars');
1514
var getTraceColor = require('./get_trace_color');
1615
var Color = require('../../components/color');
16+
var fillHoverText = require('./fill_hover_text');
1717

1818
var MAXDIST = Fx.constants.MAXDIST;
1919

@@ -73,11 +73,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
7373
yLabelVal: di.y
7474
});
7575

76-
if(di.htx) pointData.text = di.htx;
77-
else if(trace.hovertext) pointData.text = trace.hovertext;
78-
else if(di.tx) pointData.text = di.tx;
79-
else if(trace.text) pointData.text = trace.text;
80-
76+
fillHoverText(di, trace, pointData);
8177
ErrorBars.hoverInfo(di, trace, pointData);
8278

8379
return [pointData];

src/traces/scattercarpet/hover.js

+17-8
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,27 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
4646
newPointData.yLabelVal = undefined;
4747
// TODO: nice formatting, and label by axis title, for a, b, and c?
4848

49-
var trace = newPointData.trace,
50-
carpet = trace._carpet,
51-
hoverinfo = trace.hoverinfo.split('+'),
52-
text = [];
49+
var trace = newPointData.trace;
50+
var carpet = trace._carpet;
51+
var hoverinfo = cdi.hi || trace.hoverinfo;
52+
var parts = hoverinfo.split('+');
53+
var text = [];
5354

5455
function textPart(ax, val) {
55-
text.push(((ax.labelprefix && ax.labelprefix.length > 0) ? ax.labelprefix : (ax._hovertitle + ': ')) + val.toFixed(3) + ax.labelsuffix);
56+
var prefix;
57+
58+
if(ax.labelprefix && ax.labelprefix.length > 0) {
59+
prefix = ax.labelprefix.replace(/ = $/, '');
60+
} else {
61+
prefix = ax._hovertitle;
62+
}
63+
64+
text.push(prefix + ': ' + val.toFixed(3) + ax.labelsuffix);
5665
}
5766

58-
if(hoverinfo.indexOf('all') !== -1) hoverinfo = ['a', 'b'];
59-
if(hoverinfo.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a);
60-
if(hoverinfo.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b);
67+
if(parts.indexOf('all') !== -1) parts = ['a', 'b'];
68+
if(parts.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a);
69+
if(parts.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b);
6170

6271
var ij = carpet.ab2ij([cdi.a, cdi.b]);
6372
var i0 = Math.floor(ij[0]);

src/traces/scattergeo/hover.js

+15-20
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ var Axes = require('../../plots/cartesian/axes');
1414
var BADNUM = require('../../constants/numerical').BADNUM;
1515

1616
var getTraceColor = require('../scatter/get_trace_color');
17+
var fillHoverText = require('../scatter/fill_hover_text');
1718
var attributes = require('./attributes');
1819

19-
2020
module.exports = function hoverPoints(pointData, xval, yval) {
2121
var cd = pointData.cd;
2222
var trace = cd[0].trace;
@@ -71,39 +71,34 @@ module.exports = function hoverPoints(pointData, xval, yval) {
7171
};
7272

7373
function getExtraText(trace, pt, axis) {
74-
var hoverinfo = trace.hoverinfo;
74+
var hoverinfo = pt.hi || trace.hoverinfo;
7575

76-
var parts = (hoverinfo === 'all') ?
76+
var parts = hoverinfo === 'all' ?
7777
attributes.hoverinfo.flags :
7878
hoverinfo.split('+');
7979

80-
var hasLocation = parts.indexOf('location') !== -1 && Array.isArray(trace.locations),
81-
hasLon = (parts.indexOf('lon') !== -1),
82-
hasLat = (parts.indexOf('lat') !== -1),
83-
hasText = (parts.indexOf('text') !== -1);
84-
80+
var hasLocation = parts.indexOf('location') !== -1 && Array.isArray(trace.locations);
81+
var hasLon = (parts.indexOf('lon') !== -1);
82+
var hasLat = (parts.indexOf('lat') !== -1);
83+
var hasText = (parts.indexOf('text') !== -1);
8584
var text = [];
8685

8786
function format(val) {
8887
return Axes.tickText(axis, axis.c2l(val), 'hover').text + '\u00B0';
8988
}
9089

91-
if(hasLocation) text.push(pt.loc);
92-
else if(hasLon && hasLat) {
90+
if(hasLocation) {
91+
text.push(pt.loc);
92+
} else if(hasLon && hasLat) {
9393
text.push('(' + format(pt.lonlat[0]) + ', ' + format(pt.lonlat[1]) + ')');
94+
} else if(hasLon) {
95+
text.push('lon: ' + format(pt.lonlat[0]));
96+
} else if(hasLat) {
97+
text.push('lat: ' + format(pt.lonlat[1]));
9498
}
95-
else if(hasLon) text.push('lon: ' + format(pt.lonlat[0]));
96-
else if(hasLat) text.push('lat: ' + format(pt.lonlat[1]));
9799

98100
if(hasText) {
99-
var tx;
100-
101-
if(pt.htx) tx = pt.htx;
102-
else if(trace.hovertext) tx = trace.hovertext;
103-
else if(pt.tx) tx = pt.tx;
104-
else if(trace.text) tx = trace.text;
105-
106-
if(!Array.isArray(tx)) text.push(tx);
101+
fillHoverText(pt, trace, text);
107102
}
108103

109104
return text.join('<br>');

src/traces/scattermapbox/hover.js

+14-17
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
var Fx = require('../../components/fx');
1313
var getTraceColor = require('../scatter/get_trace_color');
14+
var fillHoverText = require('../scatter/fill_hover_text');
1415
var BADNUM = require('../../constants/numerical').BADNUM;
1516

1617
module.exports = function hoverPoints(pointData, xval, yval) {
@@ -66,13 +67,14 @@ module.exports = function hoverPoints(pointData, xval, yval) {
6667
};
6768

6869
function getExtraText(trace, di) {
69-
var hoverinfo = trace.hoverinfo.split('+'),
70-
isAll = (hoverinfo.indexOf('all') !== -1),
71-
hasLon = (hoverinfo.indexOf('lon') !== -1),
72-
hasLat = (hoverinfo.indexOf('lat') !== -1);
70+
var hoverinfo = di.hi || trace.hoverinfo;
71+
var parts = hoverinfo.split('+');
72+
var isAll = parts.indexOf('all') !== -1;
73+
var hasLon = parts.indexOf('lon') !== -1;
74+
var hasLat = parts.indexOf('lat') !== -1;
7375

74-
var lonlat = di.lonlat,
75-
text = [];
76+
var lonlat = di.lonlat;
77+
var text = [];
7678

7779
// TODO should we use a mock axis to format hover?
7880
// If so, we'll need to make precision be zoom-level dependent
@@ -82,19 +84,14 @@ function getExtraText(trace, di) {
8284

8385
if(isAll || (hasLon && hasLat)) {
8486
text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')');
87+
} else if(hasLon) {
88+
text.push('lon: ' + format(lonlat[0]));
89+
} else if(hasLat) {
90+
text.push('lat: ' + format(lonlat[1]));
8591
}
86-
else if(hasLon) text.push('lon: ' + format(lonlat[0]));
87-
else if(hasLat) text.push('lat: ' + format(lonlat[1]));
8892

89-
if(isAll || hoverinfo.indexOf('text') !== -1) {
90-
var tx;
91-
92-
if(di.htx) tx = di.htx;
93-
else if(trace.hovertext) tx = trace.hovertext;
94-
else if(di.tx) tx = di.tx;
95-
else if(trace.text) tx = trace.text;
96-
97-
if(!Array.isArray(tx)) text.push(tx);
93+
if(isAll || parts.indexOf('text') !== -1) {
94+
fillHoverText(di, trace, text);
9895
}
9996

10097
return text.join('<br>');

0 commit comments

Comments
 (0)