Skip to content

Commit c5bdee9

Browse files
authored
Merge pull request #3530 from plotly/hovertemplate-more
More hovertemplates!
2 parents 4eaad9b + 2d57601 commit c5bdee9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+454
-94
lines changed

src/components/fx/hover.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ function createHoverText(hoverData, opts, gd) {
945945
text = d[(hovermode === 'x' ? 'y' : 'x') + 'Label'] || '';
946946
}
947947
else if(d.xLabel === undefined) {
948-
if(d.yLabel !== undefined) text = d.yLabel;
948+
if(d.yLabel !== undefined && d.trace.type !== 'scattercarpet') text = d.yLabel;
949949
}
950950
else if(d.yLabel === undefined) text = d.xLabel;
951951
else text = '(' + d.xLabel + ', ' + d.yLabel + ')';

src/components/fx/hovertemplate_attributes.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ module.exports = function(opts, extra) {
3131
valType: 'string',
3232
role: 'info',
3333
dflt: '',
34-
arrayOk: true,
35-
editType: 'none',
34+
editType: opts.editType || 'none',
3635
description: [
3736
'Template string used for rendering the information that appear on hover box.',
3837
'Note that this will override `hoverinfo`.',
@@ -46,5 +45,9 @@ module.exports = function(opts, extra) {
4645
].join(' ')
4746
};
4847

48+
if(opts.arrayOk !== false) {
49+
hovertemplate.arrayOk = true;
50+
}
51+
4952
return hovertemplate;
5053
};

src/plots/gl3d/scene.js

+58-42
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,21 @@ function render(scene) {
7171
var pdata = project(scene.glplot.cameraParams, selection.dataCoordinate);
7272
trace = lastPicked.data;
7373
var ptNumber = selection.index;
74-
var hoverinfo = Fx.castHoverinfo(trace, scene.fullLayout, ptNumber);
75-
var hoverinfoParts = hoverinfo.split('+');
76-
var isHoverinfoAll = hoverinfo === 'all';
7774

78-
var xVal = formatter('xaxis', selection.traceCoordinate[0]);
79-
var yVal = formatter('yaxis', selection.traceCoordinate[1]);
80-
var zVal = formatter('zaxis', selection.traceCoordinate[2]);
75+
var labels = {
76+
xLabel: formatter('xaxis', selection.traceCoordinate[0]),
77+
yLabel: formatter('yaxis', selection.traceCoordinate[1]),
78+
zLabel: formatter('zaxis', selection.traceCoordinate[2])
79+
};
80+
81+
var hoverinfo = Fx.castHoverinfo(trace, scene.fullLayout, ptNumber);
82+
var hoverinfoParts = (hoverinfo || '').split('+');
83+
var isHoverinfoAll = hoverinfo && hoverinfo === 'all';
8184

82-
if(!isHoverinfoAll) {
83-
if(hoverinfoParts.indexOf('x') === -1) xVal = undefined;
84-
if(hoverinfoParts.indexOf('y') === -1) yVal = undefined;
85-
if(hoverinfoParts.indexOf('z') === -1) zVal = undefined;
85+
if(!trace.hovertemplate && !isHoverinfoAll) {
86+
if(hoverinfoParts.indexOf('x') === -1) labels.xLabel = undefined;
87+
if(hoverinfoParts.indexOf('y') === -1) labels.yLabel = undefined;
88+
if(hoverinfoParts.indexOf('z') === -1) labels.zLabel = undefined;
8689
if(hoverinfoParts.indexOf('text') === -1) selection.textLabel = undefined;
8790
if(hoverinfoParts.indexOf('name') === -1) lastPicked.name = undefined;
8891
}
@@ -91,27 +94,38 @@ function render(scene) {
9194
var vectorTx = [];
9295

9396
if(trace.type === 'cone' || trace.type === 'streamtube') {
97+
labels.uLabel = formatter('xaxis', selection.traceCoordinate[3]);
9498
if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) {
95-
vectorTx.push('u: ' + formatter('xaxis', selection.traceCoordinate[3]));
99+
vectorTx.push('u: ' + labels.uLabel);
96100
}
101+
102+
labels.vLabel = formatter('yaxis', selection.traceCoordinate[4]);
97103
if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) {
98-
vectorTx.push('v: ' + formatter('yaxis', selection.traceCoordinate[4]));
104+
vectorTx.push('v: ' + labels.vLabel);
99105
}
106+
107+
labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]);
100108
if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
101-
vectorTx.push('w: ' + formatter('zaxis', selection.traceCoordinate[5]));
109+
vectorTx.push('w: ' + labels.wLabel);
102110
}
111+
112+
labels.normLabel = selection.traceCoordinate[6].toPrecision(3);
103113
if(isHoverinfoAll || hoverinfoParts.indexOf('norm') !== -1) {
104-
vectorTx.push('norm: ' + selection.traceCoordinate[6].toPrecision(3));
114+
vectorTx.push('norm: ' + labels.normLabel);
105115
}
106-
if(trace.type === 'streamtube' && (isHoverinfoAll || hoverinfoParts.indexOf('divergence') !== -1)) {
107-
vectorTx.push('divergence: ' + selection.traceCoordinate[7].toPrecision(3));
116+
if(trace.type === 'streamtube') {
117+
labels.divergenceLabel = selection.traceCoordinate[7].toPrecision(3);
118+
if(isHoverinfoAll || hoverinfoParts.indexOf('divergence') !== -1) {
119+
vectorTx.push('divergence: ' + labels.divergenceLabel);
120+
}
108121
}
109122
if(selection.textLabel) {
110123
vectorTx.push(selection.textLabel);
111124
}
112125
tx = vectorTx.join('<br>');
113126
} else if(trace.type === 'isosurface') {
114-
vectorTx.push('value: ' + Axes.tickText(scene.mockAxis, scene.mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text);
127+
labels.valueLabel = Axes.tickText(scene.mockAxis, scene.mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text;
128+
vectorTx.push('value: ' + labels.valueLabel);
115129
if(selection.textLabel) {
116130
vectorTx.push(selection.textLabel);
117131
}
@@ -120,27 +134,6 @@ function render(scene) {
120134
tx = selection.textLabel;
121135
}
122136

123-
if(scene.fullSceneLayout.hovermode) {
124-
Fx.loneHover({
125-
x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
126-
y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
127-
xLabel: xVal,
128-
yLabel: yVal,
129-
zLabel: zVal,
130-
text: tx,
131-
name: lastPicked.name,
132-
color: Fx.castHoverOption(trace, ptNumber, 'bgcolor') || lastPicked.color,
133-
borderColor: Fx.castHoverOption(trace, ptNumber, 'bordercolor'),
134-
fontFamily: Fx.castHoverOption(trace, ptNumber, 'font.family'),
135-
fontSize: Fx.castHoverOption(trace, ptNumber, 'font.size'),
136-
fontColor: Fx.castHoverOption(trace, ptNumber, 'font.color')
137-
}, {
138-
container: svgContainer,
139-
gd: scene.graphDiv
140-
});
141-
}
142-
143-
// TODO not sure if streamtube x/y/z should be emitted as x/y/z
144137
var pointData = {
145138
x: selection.traceCoordinate[0],
146139
y: selection.traceCoordinate[1],
@@ -151,18 +144,41 @@ function render(scene) {
151144
pointNumber: ptNumber
152145
};
153146

147+
Fx.appendArrayPointValue(pointData, trace, ptNumber);
148+
154149
if(trace._module.eventData) {
155150
pointData = trace._module.eventData(pointData, selection, trace, {}, ptNumber);
156151
}
157152

158-
Fx.appendArrayPointValue(pointData, trace, ptNumber);
159-
160153
var eventData = {points: [pointData]};
161154

155+
if(scene.fullSceneLayout.hovermode) {
156+
Fx.loneHover({
157+
trace: trace,
158+
x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
159+
y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
160+
xLabel: labels.xLabel,
161+
yLabel: labels.yLabel,
162+
zLabel: labels.zLabel,
163+
text: tx,
164+
name: lastPicked.name,
165+
color: Fx.castHoverOption(trace, ptNumber, 'bgcolor') || lastPicked.color,
166+
borderColor: Fx.castHoverOption(trace, ptNumber, 'bordercolor'),
167+
fontFamily: Fx.castHoverOption(trace, ptNumber, 'font.family'),
168+
fontSize: Fx.castHoverOption(trace, ptNumber, 'font.size'),
169+
fontColor: Fx.castHoverOption(trace, ptNumber, 'font.color'),
170+
hovertemplate: Lib.castOption(trace, ptNumber, 'hovertemplate'),
171+
hovertemplateLabels: Lib.extendFlat({}, pointData, labels),
172+
eventData: [pointData]
173+
}, {
174+
container: svgContainer,
175+
gd: scene.graphDiv
176+
});
177+
}
178+
162179
if(selection.buttons && selection.distance < 5) {
163180
scene.graphDiv.emit('plotly_click', eventData);
164-
}
165-
else {
181+
} else {
166182
scene.graphDiv.emit('plotly_hover', eventData);
167183
}
168184

src/traces/cone/attributes.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
var colorscaleAttrs = require('../../components/colorscale/attributes');
1212
var colorbarAttrs = require('../../components/colorbar/attributes');
13+
var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
1314
var mesh3dAttrs = require('../mesh3d/attributes');
1415
var baseAttrs = require('../../plots/attributes');
1516

@@ -157,7 +158,8 @@ var attrs = {
157158
'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
158159
'these elements will be seen in the hover labels.'
159160
].join(' ')
160-
}
161+
},
162+
hovertemplate: hovertemplateAttrs({editType: 'calc'}, {keys: ['norm']})
161163
};
162164

163165
extendFlat(attrs, colorscaleAttrs('', {

src/traces/cone/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
5252
colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'c'});
5353

5454
coerce('text');
55+
coerce('hovertemplate');
5556

5657
// disable 1D transforms (for now)
5758
traceOut._length = null;

src/traces/cone/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ module.exports = {
2222
},
2323
calc: require('./calc'),
2424
plot: require('./convert'),
25+
eventData: function(out, pt) {
26+
out.norm = pt.traceCoordinate[6];
27+
return out;
28+
},
2529

2630
meta: {
2731
description: [

src/traces/contour/attributes.js

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ module.exports = extendFlat({
3535
xtype: heatmapAttrs.xtype,
3636
ytype: heatmapAttrs.ytype,
3737
zhoverformat: heatmapAttrs.zhoverformat,
38+
hovertemplate: heatmapAttrs.hovertemplate,
3839

3940
connectgaps: heatmapAttrs.connectgaps,
4041

src/traces/contour/defaults.js

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

9-
109
'use strict';
1110

1211
var Lib = require('../../lib');
@@ -34,6 +33,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
3433
}
3534

3635
coerce('text');
36+
coerce('hovertemplate');
37+
3738
var isConstraint = (coerce('contours.type') === 'constraint');
3839
coerce('connectgaps', Lib.isArray1D(traceOut.z));
3940

src/traces/heatmap/attributes.js

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var scatterAttrs = require('../scatter/attributes');
12+
var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
1213
var colorscaleAttrs = require('../../components/colorscale/attributes');
1314
var colorbarAttrs = require('../../components/colorbar/attributes');
1415

@@ -111,6 +112,8 @@ module.exports = extendFlat({
111112
'https://github.com/d3/d3-format/blob/master/README.md#locale_format'
112113
].join(' ')
113114
},
115+
hovertemplate: hovertemplateAttrs()
116+
}, {
114117
transforms: undefined
115118
},
116119
colorscaleAttrs('', {

src/traces/heatmap/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
2929
}
3030

3131
coerce('text');
32+
coerce('hovertemplate');
3233

3334
handleStyleDefaults(traceIn, traceOut, coerce, layout);
3435

src/traces/histogram/event_data.js

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ module.exports = function eventData(out, pt, trace, cd, pointNumber) {
1313
out.x = 'xVal' in pt ? pt.xVal : pt.x;
1414
out.y = 'yVal' in pt ? pt.yVal : pt.y;
1515

16+
// for 2d histograms
17+
if('zLabelVal' in pt) out.z = pt.zLabelVal;
18+
1619
if(pt.xa) out.xaxis = pt.xa;
1720
if(pt.ya) out.yaxis = pt.ya;
1821

src/traces/histogram2d/attributes.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
var histogramAttrs = require('../histogram/attributes');
1212
var makeBinAttrs = require('../histogram/bin_attributes');
1313
var heatmapAttrs = require('../heatmap/attributes');
14+
var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
1415
var colorscaleAttrs = require('../../components/colorscale/attributes');
1516
var colorbarAttrs = require('../../components/colorbar/attributes');
1617

@@ -47,7 +48,8 @@ module.exports = extendFlat(
4748
xgap: heatmapAttrs.xgap,
4849
ygap: heatmapAttrs.ygap,
4950
zsmooth: heatmapAttrs.zsmooth,
50-
zhoverformat: heatmapAttrs.zhoverformat
51+
zhoverformat: heatmapAttrs.zhoverformat,
52+
hovertemplate: hovertemplateAttrs({}, {keys: 'z'})
5153
},
5254
colorscaleAttrs('', {
5355
cLetter: 'z',

src/traces/histogram2d/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
2929
colorscaleDefaults(
3030
traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'z'}
3131
);
32+
coerce('hovertemplate');
3233
};

src/traces/histogram2dcontour/attributes.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ module.exports = extendFlat({
3434
ncontours: contourAttrs.ncontours,
3535
contours: contourAttrs.contours,
3636
line: contourAttrs.line,
37-
zhoverformat: histogram2dAttrs.zhoverformat
37+
zhoverformat: histogram2dAttrs.zhoverformat,
38+
hovertemplate: histogram2dAttrs.hovertemplate
3839
},
3940
colorscaleAttrs('', {
4041
cLetter: 'z',

src/traces/histogram2dcontour/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
3131

3232
handleContoursDefaults(traceIn, traceOut, coerce, coerce2);
3333
handleStyleDefaults(traceIn, traceOut, coerce, layout);
34+
coerce('hovertemplate');
3435
};

src/traces/isosurface/attributes.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
var colorscaleAttrs = require('../../components/colorscale/attributes');
1212
var colorbarAttrs = require('../../components/colorbar/attributes');
13+
var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
1314
var meshAttrs = require('../mesh3d/attributes');
1415
var baseAttrs = require('../../plots/attributes');
1516

@@ -224,7 +225,8 @@ var attrs = module.exports = overrideAll(extendFlat({
224225
'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
225226
'these elements will be seen in the hover labels.'
226227
].join(' ')
227-
}
228+
},
229+
hovertemplate: hovertemplateAttrs()
228230
},
229231

230232
colorscaleAttrs('', {

src/traces/isosurface/defaults.js

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

9-
109
'use strict';
1110

1211
var Registry = require('../../registry');
@@ -85,6 +84,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
8584
// Coerce remaining properties
8685
[
8786
'text',
87+
'hovertemplate',
8888
'lighting.ambient',
8989
'lighting.diffuse',
9090
'lighting.specular',

src/traces/mesh3d/attributes.js

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
var colorscaleAttrs = require('../../components/colorscale/attributes');
1212
var colorbarAttrs = require('../../components/colorbar/attributes');
13+
var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
1314
var surfaceAtts = require('../surface/attributes');
1415
var baseAttrs = require('../../plots/attributes');
1516

@@ -89,6 +90,7 @@ module.exports = extendFlat({
8990
'these elements will be seen in the hover labels.'
9091
].join(' ')
9192
},
93+
hovertemplate: hovertemplateAttrs({editType: 'calc'}),
9294

9395
delaunayaxis: {
9496
valType: 'enumerated',

src/traces/mesh3d/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
8888
}
8989

9090
coerce('text');
91+
coerce('hovertemplate');
9192

9293
// disable 1D transforms
9394
// x/y/z should match lengths, and i/j/k should match as well, but

0 commit comments

Comments
 (0)