diff --git a/src/traces/bar/arrays_to_calcdata.js b/src/traces/bar/arrays_to_calcdata.js
index 15ecc601d72..675364e9920 100644
--- a/src/traces/bar/arrays_to_calcdata.js
+++ b/src/traces/bar/arrays_to_calcdata.js
@@ -15,6 +15,7 @@ var mergeArray = require('../../lib').mergeArray;
// arrayOk attributes, merge them into calcdata array
module.exports = function arraysToCalcdata(cd, trace) {
mergeArray(trace.text, cd, 'tx');
+ mergeArray(trace.hovertext, cd, 'htx');
var marker = trace.marker;
if(marker) {
diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js
index 95141454624..9fa333fdf05 100644
--- a/src/traces/bar/attributes.js
+++ b/src/traces/bar/attributes.js
@@ -49,6 +49,7 @@ module.exports = {
dy: scatterAttrs.dy,
text: scatterAttrs.text,
+ hovertext: scatterAttrs.hovertext,
textposition: {
valType: 'enumerated',
diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js
index 614176cfc68..6436dffb9d4 100644
--- a/src/traces/bar/defaults.js
+++ b/src/traces/bar/defaults.js
@@ -37,6 +37,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('width');
coerce('text');
+ coerce('hovertext');
var textPosition = coerce('textposition');
diff --git a/src/traces/bar/hover.js b/src/traces/bar/hover.js
index 48c5596bd5e..377cf4fa0a0 100644
--- a/src/traces/bar/hover.js
+++ b/src/traces/bar/hover.js
@@ -99,7 +99,10 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
pointData.xLabelVal = di.p;
}
- if(di.tx) pointData.text = di.tx;
+ if(di.htx) pointData.text = di.htx;
+ else if(trace.hovertext) pointData.text = trace.hovertext;
+ else if(di.tx) pointData.text = di.tx;
+ else if(trace.text) pointData.text = trace.text;
ErrorBars.hoverInfo(di, trace, pointData);
diff --git a/src/traces/pie/attributes.js b/src/traces/pie/attributes.js
index ed2a8641fe3..f1ca7b6426c 100644
--- a/src/traces/pie/attributes.js
+++ b/src/traces/pie/attributes.js
@@ -79,7 +79,27 @@ module.exports = {
text: {
valType: 'data_array',
- description: 'Sets text elements associated with each sector.'
+ description: [
+ 'Sets text elements associated with each sector.',
+ 'If trace `textinfo` contains a *text* flag, these elements will seen',
+ 'on the chart.',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
+ ].join(' ')
+ },
+ hovertext: {
+ valType: 'string',
+ role: 'info',
+ dflt: '',
+ arrayOk: true,
+ description: [
+ 'Sets hover text elements associated with each sector.',
+ 'If a single string, the same string appears for',
+ 'all data points.',
+ 'If an array of string, the items are mapped in order of',
+ 'this trace\'s sectors.',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
+ ].join(' ')
},
// 'see eg:'
diff --git a/src/traces/pie/defaults.js b/src/traces/pie/defaults.js
index 9a21628aca9..26f68f03d0a 100644
--- a/src/traces/pie/defaults.js
+++ b/src/traces/pie/defaults.js
@@ -45,6 +45,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
var textData = coerce('text');
var textInfo = coerce('textinfo', Array.isArray(textData) ? 'text+percent' : 'percent');
+ coerce('hovertext');
coerce('hoverinfo', (layout._dataLength === 1) ? 'label+text+value+percent' : undefined);
diff --git a/src/traces/pie/plot.js b/src/traces/pie/plot.js
index 8539093101f..124e96368e3 100644
--- a/src/traces/pie/plot.js
+++ b/src/traces/pie/plot.js
@@ -110,8 +110,16 @@ module.exports = function plot(gd, cdpie) {
thisText = [];
if(hoverinfo.indexOf('label') !== -1) thisText.push(pt.label);
- if(trace2.text && trace2.text[pt.i] && hoverinfo.indexOf('text') !== -1) {
- thisText.push(trace2.text[pt.i]);
+ if(hoverinfo.indexOf('text') !== -1) {
+ if(trace2.hovertext) {
+ thisText.push(
+ Array.isArray(trace2.hovertext) ?
+ trace2.hovertext[pt.i] :
+ trace2.hovertext
+ );
+ } else if(trace2.text && trace2.text[pt.i]) {
+ thisText.push(trace2.text[pt.i]);
+ }
}
if(hoverinfo.indexOf('value') !== -1) thisText.push(helpers.formatPieValue(pt.v, separators));
if(hoverinfo.indexOf('percent') !== -1) thisText.push(helpers.formatPiePercent(pt.v / cd0.vTotal, separators));
diff --git a/src/traces/scatter/arrays_to_calcdata.js b/src/traces/scatter/arrays_to_calcdata.js
index 8b81c42bcb7..378fc7613f0 100644
--- a/src/traces/scatter/arrays_to_calcdata.js
+++ b/src/traces/scatter/arrays_to_calcdata.js
@@ -16,6 +16,7 @@ var Lib = require('../../lib');
module.exports = function arraysToCalcdata(cd, trace) {
Lib.mergeArray(trace.text, cd, 'tx');
+ Lib.mergeArray(trace.hovertext, cd, 'htx');
Lib.mergeArray(trace.customdata, cd, 'data');
Lib.mergeArray(trace.textposition, cd, 'tp');
if(trace.textfont) {
diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js
index fc1412e9f05..38b3015a4bb 100644
--- a/src/traces/scatter/attributes.js
+++ b/src/traces/scatter/attributes.js
@@ -83,7 +83,23 @@ module.exports = {
'If a single string, the same string appears over',
'all the data points.',
'If an array of string, the items are mapped in order to the',
- 'this trace\'s (x,y) coordinates.'
+ 'this trace\'s (x,y) coordinates.',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
+ ].join(' ')
+ },
+ hovertext: {
+ valType: 'string',
+ role: 'info',
+ dflt: '',
+ arrayOk: true,
+ description: [
+ 'Sets hover text elements associated with each (x,y) pair.',
+ 'If a single string, the same string appears over',
+ 'all the data points.',
+ 'If an array of string, the items are mapped in order to the',
+ 'this trace\'s (x,y) coordinates.',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
].join(' ')
},
mode: {
diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js
index c0115bb2ab7..c6c97850b98 100644
--- a/src/traces/scatter/defaults.js
+++ b/src/traces/scatter/defaults.js
@@ -38,6 +38,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('customdata');
coerce('text');
+ coerce('hovertext');
coerce('mode', defaultMode);
coerce('ids');
diff --git a/src/traces/scatter/hover.js b/src/traces/scatter/hover.js
index 2392a23bb4f..caba649e550 100644
--- a/src/traces/scatter/hover.js
+++ b/src/traces/scatter/hover.js
@@ -72,7 +72,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
yLabelVal: di.y
});
- if(di.tx) pointData.text = di.tx;
+ if(di.htx) pointData.text = di.htx;
+ else if(trace.hovertext) pointData.text = trace.hovertext;
+ else if(di.tx) pointData.text = di.tx;
else if(trace.text) pointData.text = trace.text;
ErrorBars.hoverInfo(di, trace, pointData);
diff --git a/src/traces/scatter3d/attributes.js b/src/traces/scatter3d/attributes.js
index 7c5278c25c9..ac0b957be63 100644
--- a/src/traces/scatter3d/attributes.js
+++ b/src/traces/scatter3d/attributes.js
@@ -72,9 +72,22 @@ module.exports = {
'If a single string, the same string appears over',
'all the data points.',
'If an array of string, the items are mapped in order to the',
- 'this trace\'s (x,y,z) coordinates.'
+ 'this trace\'s (x,y,z) coordinates.',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
].join(' ')
}),
+ hovertext: extendFlat({}, scatterAttrs.hovertext, {
+ description: [
+ 'Sets text elements associated with each (x,y,z) triplet.',
+ 'If a single string, the same string appears over',
+ 'all the data points.',
+ 'If an array of string, the items are mapped in order to the',
+ 'this trace\'s (x,y,z) coordinates.',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
+ ].join(' ')
+ }),
+
mode: extendFlat({}, scatterAttrs.mode, // shouldn't this be on-par with 2D?
{dflt: 'lines+markers'}),
surfaceaxis: {
diff --git a/src/traces/scatter3d/convert.js b/src/traces/scatter3d/convert.js
index 0b45b090f3b..f491d2b057f 100644
--- a/src/traces/scatter3d/convert.js
+++ b/src/traces/scatter3d/convert.js
@@ -58,8 +58,12 @@ proto.handlePick = function(selection) {
selection.object = this.scatterPlot;
this.scatterPlot.highlight(selection.data);
}
- if(this.textLabels && this.textLabels[selection.data.index] !== undefined) {
- selection.textLabel = this.textLabels[selection.data.index];
+ if(this.textLabels) {
+ if(this.textLabels[selection.data.index] !== undefined) {
+ selection.textLabel = this.textLabels[selection.data.index];
+ } else {
+ selection.textLabel = this.textLabels;
+ }
}
else selection.textLabel = '';
@@ -371,7 +375,7 @@ proto.update = function(data) {
opacity: data.opacity
};
- this.textLabels = options.text;
+ this.textLabels = data.hovertext || data.text;
if(this.mode.indexOf('text') !== -1) {
if(this.textMarkers) this.textMarkers.update(textOptions);
diff --git a/src/traces/scatter3d/defaults.js b/src/traces/scatter3d/defaults.js
index 4f62fd3c1d8..89e0985709f 100644
--- a/src/traces/scatter3d/defaults.js
+++ b/src/traces/scatter3d/defaults.js
@@ -34,6 +34,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}
coerce('text');
+ coerce('hovertext');
coerce('mode');
if(subTypes.hasLines(traceOut)) {
diff --git a/src/traces/scattergeo/attributes.js b/src/traces/scattergeo/attributes.js
index 464354e35b0..1b5ddeffc19 100644
--- a/src/traces/scattergeo/attributes.js
+++ b/src/traces/scattergeo/attributes.js
@@ -56,9 +56,23 @@ module.exports = {
'If a single string, the same string appears over',
'all the data points.',
'If an array of string, the items are mapped in order to the',
- 'this trace\'s (lon,lat) or `locations` coordinates.'
+ 'this trace\'s (lon,lat) or `locations` coordinates.',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
].join(' ')
}),
+ hovertext: extendFlat({}, scatterAttrs.hovertext, {
+ description: [
+ 'Sets hover text elements associated with each (lon,lat) pair',
+ 'or item in `locations`.',
+ 'If a single string, the same string appears over',
+ 'all the data points.',
+ 'If an array of string, the items are mapped in order to the',
+ 'this trace\'s (lon,lat) or `locations` coordinates.',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
+ ].join(' ')
+ }),
+
textfont: scatterAttrs.textfont,
textposition: scatterAttrs.textposition,
diff --git a/src/traces/scattergeo/defaults.js b/src/traces/scattergeo/defaults.js
index aa0bbdd5f45..61551c3f66f 100644
--- a/src/traces/scattergeo/defaults.js
+++ b/src/traces/scattergeo/defaults.js
@@ -32,6 +32,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}
coerce('text');
+ coerce('hovertext');
coerce('mode');
if(subTypes.hasLines(traceOut)) {
diff --git a/src/traces/scattergeo/hover.js b/src/traces/scattergeo/hover.js
index dd609047e99..44928b875e8 100644
--- a/src/traces/scattergeo/hover.js
+++ b/src/traces/scattergeo/hover.js
@@ -101,7 +101,13 @@ function getExtraText(trace, pt, axis) {
else if(hasLat) text.push('lat: ' + format(pt.lonlat[1]));
if(hasText) {
- var tx = pt.tx || trace.text;
+ var tx;
+
+ if(pt.htx) tx = pt.htx;
+ else if(trace.hovertext) tx = trace.hovertext;
+ else if(pt.tx) tx = pt.tx;
+ else if(trace.text) tx = trace.text;
+
if(!Array.isArray(tx)) text.push(tx);
}
diff --git a/src/traces/scattermapbox/attributes.js b/src/traces/scattermapbox/attributes.js
index 034f85a0b43..1518093db19 100644
--- a/src/traces/scattermapbox/attributes.js
+++ b/src/traces/scattermapbox/attributes.js
@@ -27,19 +27,15 @@ module.exports = {
// locations
// locationmode
- mode: {
- valType: 'flaglist',
- flags: ['lines', 'markers', 'text'],
+ mode: extendFlat({}, scatterAttrs.mode, {
dflt: 'markers',
- extras: ['none'],
- role: 'info',
description: [
'Determines the drawing mode for this scatter trace.',
'If the provided `mode` includes *text* then the `text` elements',
'appear at the coordinates. Otherwise, the `text` elements',
'appear on hover.'
].join(' ')
- },
+ }),
text: extendFlat({}, scatterAttrs.text, {
description: [
@@ -47,7 +43,19 @@ module.exports = {
'If a single string, the same string appears over',
'all the data points.',
'If an array of string, the items are mapped in order to the',
- 'this trace\'s (lon,lat) coordinates.'
+ 'this trace\'s (lon,lat) coordinates.',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
+ ].join(' ')
+ }),
+ hovertext: extendFlat({}, scatterAttrs.hovertext, {
+ description: [
+ 'Sets hover text elements associated with each (lon,lat) pair',
+ 'If a single string, the same string appears over',
+ 'all the data points.',
+ 'If an array of string, the items are mapped in order to the',
+ 'this trace\'s (lon,lat) coordinates.',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
].join(' ')
}),
diff --git a/src/traces/scattermapbox/defaults.js b/src/traces/scattermapbox/defaults.js
index 3de5641b76a..ad884eb7f32 100644
--- a/src/traces/scattermapbox/defaults.js
+++ b/src/traces/scattermapbox/defaults.js
@@ -42,6 +42,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}
coerce('text');
+ coerce('hovertext');
coerce('mode');
if(subTypes.hasLines(traceOut)) {
diff --git a/src/traces/scattermapbox/hover.js b/src/traces/scattermapbox/hover.js
index 2bbc77e3ec1..011425a3ebc 100644
--- a/src/traces/scattermapbox/hover.js
+++ b/src/traces/scattermapbox/hover.js
@@ -87,7 +87,13 @@ function getExtraText(trace, di) {
else if(hasLat) text.push('lat: ' + format(lonlat[1]));
if(isAll || hoverinfo.indexOf('text') !== -1) {
- var tx = di.tx || trace.text;
+ var tx;
+
+ if(di.htx) tx = di.htx;
+ else if(trace.hovertext) tx = trace.hovertext;
+ else if(di.tx) tx = di.tx;
+ else if(trace.text) tx = trace.text;
+
if(!Array.isArray(tx)) text.push(tx);
}
diff --git a/src/traces/scatterternary/attributes.js b/src/traces/scatterternary/attributes.js
index 847cc8436fe..b0c0d4a2acf 100644
--- a/src/traces/scatterternary/attributes.js
+++ b/src/traces/scatterternary/attributes.js
@@ -70,7 +70,19 @@ module.exports = {
'If a single string, the same string appears over',
'all the data points.',
'If an array of strings, the items are mapped in order to the',
- 'the data points in (a,b,c).'
+ 'the data points in (a,b,c).',
+ 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,',
+ 'these elements will be seen in the hover labels.'
+ ].join(' ')
+ }),
+ hovertext: extendFlat({}, scatterAttrs.hovertext, {
+ description: [
+ 'Sets hover text elements associated with each (a,b,c) point.',
+ 'If a single string, the same string appears over',
+ 'all the data points.',
+ 'If an array of strings, the items are mapped in order to the',
+ 'the data points in (a,b,c).',
+ 'To be seen, trace `hoverinfo` must contain a *text* flag.'
].join(' ')
}),
line: {
diff --git a/src/traces/scatterternary/defaults.js b/src/traces/scatterternary/defaults.js
index 5095345e929..7e7cadc8d44 100644
--- a/src/traces/scatterternary/defaults.js
+++ b/src/traces/scatterternary/defaults.js
@@ -63,6 +63,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('sum');
coerce('text');
+ coerce('hovertext');
var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';
coerce('mode', defaultMode);
diff --git a/test/image/mocks/text_chart_arrays.json b/test/image/mocks/text_chart_arrays.json
index 90af525162c..ae614d0c267 100644
--- a/test/image/mocks/text_chart_arrays.json
+++ b/test/image/mocks/text_chart_arrays.json
@@ -40,6 +40,11 @@
"top left",
"top left"
],
+ "hovertext": [
+ "Hover text\nA",
+ "Hover text\rB",
+ "Hover text\r\nC"
+ ],
"type": "scatter",
"uid": "459c77"
},
@@ -83,6 +88,11 @@
"bottom left",
"bottom left"
],
+ "hovertext": [
+ "Hover text G",
+ "Hover text H",
+ "Hover text I"
+ ],
"type": "scatter",
"uid": "f8361c"
},
@@ -103,6 +113,11 @@
"a",
"",
"b"
+ ],
+ "hovertext": [
+ "a (hover)",
+ "",
+ "b (hover)"
]
}
],
diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js
index 3092ab3baa6..1104ddff8fd 100644
--- a/test/jasmine/tests/bar_test.js
+++ b/test/jasmine/tests/bar_test.js
@@ -9,6 +9,7 @@ var Axes = PlotlyInternal.Axes;
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var fail = require('../assets/fail_test');
var customMatchers = require('../assets/custom_matchers');
var failTest = require('../assets/fail_test');
@@ -1217,7 +1218,8 @@ describe('bar hover', function() {
return {
style: [pt.index, pt.color, pt.xLabelVal, pt.yLabelVal],
- pos: [pt.x0, pt.x1, pt.y0, pt.y1]
+ pos: [pt.x0, pt.x1, pt.y0, pt.y1],
+ text: pt.text
};
}
@@ -1294,6 +1296,41 @@ describe('bar hover', function() {
});
});
+ describe('text labels', function() {
+
+ it('should show \'hovertext\' items when present, \'text\' if not', function(done) {
+ gd = createGraphDiv();
+
+ var mock = Lib.extendDeep({}, require('@mocks/text_chart_arrays'));
+ mock.data.forEach(function(t) { t.type = 'bar'; });
+
+ Plotly.plot(gd, mock).then(function() {
+ var out = _hover(gd, -0.25, 0.5, 'closest');
+ expect(out.text).toEqual('Hover text\nA', 'hover text');
+
+ return Plotly.restyle(gd, 'hovertext', null);
+ })
+ .then(function() {
+ var out = _hover(gd, -0.25, 0.5, 'closest');
+ expect(out.text).toEqual('Text\nA', 'hover text');
+
+ return Plotly.restyle(gd, 'text', ['APPLE', 'BANANA', 'ORANGE']);
+ })
+ .then(function() {
+ var out = _hover(gd, -0.25, 0.5, 'closest');
+ expect(out.text).toEqual('APPLE', 'hover text');
+
+ return Plotly.restyle(gd, 'hovertext', ['apple', 'banana', 'orange']);
+ })
+ .then(function() {
+ var out = _hover(gd, -0.25, 0.5, 'closest');
+ expect(out.text).toEqual('apple', 'hover text');
+ })
+ .catch(fail)
+ .then(done);
+ });
+ });
+
describe('with special width/offset combinations', function() {
beforeEach(function() {
@@ -1380,9 +1417,7 @@ describe('bar hover', function() {
.catch(failTest)
.then(done);
});
-
});
-
});
function mockBarPlot(dataWithoutTraceType, layout) {
diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js
index d0b5ac0e199..850abcc3cf0 100644
--- a/test/jasmine/tests/gl_plot_interact_test.js
+++ b/test/jasmine/tests/gl_plot_interact_test.js
@@ -46,7 +46,7 @@ describe('Test gl3d plots', function() {
mouseEvent(type, 605, 271, opts);
}
- function assertHoverText(xLabel, yLabel, zLabel) {
+ function assertHoverText(xLabel, yLabel, zLabel, textLabel) {
var node = d3.selectAll('g.hovertext');
expect(node.size()).toEqual(1, 'hover text group');
@@ -54,6 +54,10 @@ describe('Test gl3d plots', function() {
expect(tspan[0].innerHTML).toEqual(xLabel, 'x val');
expect(tspan[1].innerHTML).toEqual(yLabel, 'y val');
expect(tspan[2].innerHTML).toEqual(zLabel, 'z val');
+
+ if(textLabel) {
+ expect(tspan[3].innerHTML).toEqual(textLabel, 'text label');
+ }
}
function assertEventData(x, y, z, curveNumber, pointNumber) {
@@ -132,6 +136,18 @@ describe('Test gl3d plots', function() {
.then(_hover)
.then(function() {
assertHoverText('x: 二 6, 2017', 'y: c', 'z: 100k');
+
+ return Plotly.restyle(gd, 'text', [['A', 'B', 'C', 'D']]);
+ })
+ .then(_hover)
+ .then(function() {
+ assertHoverText('x: 二 6, 2017', 'y: c', 'z: 100k', 'C');
+
+ return Plotly.restyle(gd, 'hovertext', [['Apple', 'Banana', 'Clementine', 'Dragon fruit']]);
+ })
+ .then(_hover)
+ .then(function() {
+ assertHoverText('x: 二 6, 2017', 'y: c', 'z: 100k', 'Clementine');
})
.then(done);
diff --git a/test/jasmine/tests/hover_pie_test.js b/test/jasmine/tests/hover_pie_test.js
index 2891dd31ea0..b12b9194c54 100644
--- a/test/jasmine/tests/hover_pie_test.js
+++ b/test/jasmine/tests/hover_pie_test.js
@@ -6,6 +6,7 @@ var customMatchers = require('../assets/custom_matchers');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var d3 = require('d3');
var click = require('../assets/click');
var getClientPosition = require('../assets/get_client_position');
var mouseEvent = require('../assets/mouse_event');
@@ -175,9 +176,7 @@ describe('pie hovering', function() {
});
describe('labels', function() {
-
- var gd,
- mockCopy;
+ var gd, mockCopy;
beforeEach(function() {
gd = createGraphDiv();
@@ -186,44 +185,60 @@ describe('pie hovering', function() {
afterEach(destroyGraphDiv);
- it('should show the default selected values', function(done) {
-
- var expected = ['4', '5', '33.3%'];
-
- Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
+ function _hover() {
+ mouseEvent('mouseover', 223, 143);
+ }
- mouseEvent('mouseover', 223, 143);
+ function assertLabel(expected) {
+ var labels = d3.selectAll('.hovertext .nums .line');
- var labels = Plotly.d3.selectAll('.hovertext .nums .line');
+ expect(labels.size()).toBe(expected.length);
- expect(labels[0].length).toBe(3);
+ labels.each(function(_, i) {
+ expect(d3.select(this).text()).toBe(expected[i]);
+ });
+ }
- labels.each(function(_, i) {
- expect(Plotly.d3.select(this).text()).toBe(expected[i]);
- });
- }).then(done);
+ it('should show the default selected values', function(done) {
+ Plotly.plot(gd, mockCopy.data, mockCopy.layout)
+ .then(_hover)
+ .then(function() {
+ assertLabel(['4', '5', '33.3%']);
+
+ return Plotly.restyle(gd, 'text', [['A', 'B', 'C', 'D', 'E']]);
+ })
+ .then(_hover)
+ .then(function() {
+ assertLabel(['4', 'E', '5', '33.3%']);
+
+ return Plotly.restyle(gd, 'hovertext', [[
+ 'Apple', 'Banana', 'Clementine', 'Dragon Fruit', 'Eggplant'
+ ]]);
+ })
+ .then(_hover)
+ .then(function() {
+ assertLabel(['4', 'Eggplant', '5', '33.3%']);
+
+ return Plotly.restyle(gd, 'hovertext', 'SUP');
+ })
+ .then(_hover)
+ .then(function() {
+ assertLabel(['4', 'SUP', '5', '33.3%']);
+ })
+ .then(done);
});
it('should show the correct separators for values', function(done) {
-
- var expected = ['0', '12|345|678@91', '99@9%'];
-
mockCopy.layout.separators = '@|';
mockCopy.data[0].values[0] = 12345678.912;
mockCopy.data[0].values[1] = 10000;
- Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() {
-
- mouseEvent('mouseover', 223, 143);
-
- var labels = Plotly.d3.selectAll('.hovertext .nums .line');
-
- expect(labels[0].length).toBe(3);
-
- labels.each(function(_, i) {
- expect(Plotly.d3.select(this).text()).toBe(expected[i]);
- });
- }).then(done);
+ Plotly.plot(gd, mockCopy.data, mockCopy.layout)
+ .then(_hover)
+ .then(function() {
+ assertLabel(['0', '12|345|678@91', '99@9%']);
+ })
+ .then(done);
});
});
});
diff --git a/test/jasmine/tests/scatter_test.js b/test/jasmine/tests/scatter_test.js
index 210c418341e..7a137ce9761 100644
--- a/test/jasmine/tests/scatter_test.js
+++ b/test/jasmine/tests/scatter_test.js
@@ -7,6 +7,7 @@ var Lib = require('@src/lib');
var Plotly = require('@lib/index');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var customMatchers = require('../assets/custom_matchers');
var fail = require('../assets/fail_test');
describe('Test scatter', function() {
@@ -372,3 +373,76 @@ describe('end-to-end scatter tests', function() {
}).catch(fail).then(done);
});
});
+
+describe('scatter hoverPoints', function() {
+
+ beforeAll(function() {
+ jasmine.addMatchers(customMatchers);
+ });
+
+ afterEach(destroyGraphDiv);
+
+ function _hover(gd, xval, yval, hovermode) {
+ return gd._fullData.map(function(trace, i) {
+ var cd = gd.calcdata[i];
+ var subplot = gd._fullLayout._plots.xy;
+
+ var out = Scatter.hoverPoints({
+ index: false,
+ distance: 20,
+ cd: cd,
+ trace: trace,
+ xa: subplot.xaxis,
+ ya: subplot.yaxis
+ }, xval, yval, hovermode);
+
+ return Array.isArray(out) ? out[0] : null;
+ });
+ }
+
+ it('should show \'hovertext\' items when present, \'text\' if not', function(done) {
+ var gd = createGraphDiv();
+ var mock = Lib.extendDeep({}, require('@mocks/text_chart_arrays'));
+
+ Plotly.plot(gd, mock).then(function() {
+ var pts = _hover(gd, 0, 1, 'x');
+
+ // as in 'hovertext' arrays
+ expect(pts[0].text).toEqual('Hover text\nA', 'hover text');
+ expect(pts[1].text).toEqual('Hover text G', 'hover text');
+ expect(pts[2].text).toEqual('a (hover)', 'hover text');
+
+ return Plotly.restyle(gd, 'hovertext', null);
+ })
+ .then(function() {
+ var pts = _hover(gd, 0, 1, 'x');
+
+ // as in 'text' arrays
+ expect(pts[0].text).toEqual('Text\nA', 'hover text');
+ expect(pts[1].text).toEqual('Text G', 'hover text');
+ expect(pts[2].text).toEqual('a', 'hover text');
+
+ return Plotly.restyle(gd, 'text', ['APPLE', 'BANANA', 'ORANGE']);
+ })
+ .then(function() {
+ var pts = _hover(gd, 1, 1, 'x');
+
+ // as in 'text' values
+ expect(pts[0].text).toEqual('APPLE', 'hover text');
+ expect(pts[1].text).toEqual('BANANA', 'hover text');
+ expect(pts[2].text).toEqual('ORANGE', 'hover text');
+
+ return Plotly.restyle(gd, 'hovertext', ['apple', 'banana', 'orange']);
+ })
+ .then(function() {
+ var pts = _hover(gd, 1, 1, 'x');
+
+ // as in 'hovertext' values
+ expect(pts[0].text).toEqual('apple', 'hover text');
+ expect(pts[1].text).toEqual('banana', 'hover text');
+ expect(pts[2].text).toEqual('orange', 'hover text');
+ })
+ .catch(fail)
+ .then(done);
+ });
+});
diff --git a/test/jasmine/tests/scattergeo_test.js b/test/jasmine/tests/scattergeo_test.js
index 33581c718bd..b95c06898cf 100644
--- a/test/jasmine/tests/scattergeo_test.js
+++ b/test/jasmine/tests/scattergeo_test.js
@@ -1,9 +1,15 @@
+var Plotly = require('@lib');
var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var BADNUM = require('@src/constants/numerical').BADNUM;
var ScatterGeo = require('@src/traces/scattergeo');
+var d3 = require('d3');
+var createGraphDiv = require('../assets/create_graph_div');
+var destroyGraphDiv = require('../assets/destroy_graph_div');
+var customMatchers = require('../assets/custom_matchers');
+var mouseEvent = require('../assets/mouse_event');
describe('Test scattergeo defaults', function() {
var traceIn,
@@ -221,3 +227,66 @@ describe('Test scattergeo calc', function() {
]);
});
});
+
+describe('Test scattergeo hover', function() {
+ var gd;
+
+ // we can't mock ScatterGeo.hoverPoints
+ // because geo hover relies on mouse event
+ // to set the c2p conversion functions
+
+ beforeAll(function() {
+ jasmine.addMatchers(customMatchers);
+ });
+
+ beforeEach(function(done) {
+ gd = createGraphDiv();
+
+ Plotly.plot(gd, [{
+ type: 'scattergeo',
+ lon: [10, 20, 30],
+ lat: [10, 20, 30],
+ text: ['A', 'B', 'C']
+ }])
+ .then(done);
+ });
+
+ afterEach(destroyGraphDiv);
+
+ function assertHoverLabels(expected) {
+ var hoverText = d3.selectAll('g.hovertext').selectAll('tspan');
+
+ hoverText.each(function(_, i) {
+ expect(this.innerHTML).toEqual(expected[i]);
+ });
+ }
+
+ it('should generate hover label info (base case)', function() {
+ mouseEvent('mousemove', 381, 221);
+ assertHoverLabels(['(10°, 10°)', 'A']);
+ });
+
+ it('should generate hover label info (\'text\' single value case)', function(done) {
+ Plotly.restyle(gd, 'text', 'text').then(function() {
+ mouseEvent('mousemove', 381, 221);
+ assertHoverLabels(['(10°, 10°)', 'text']);
+ })
+ .then(done);
+ });
+
+ it('should generate hover label info (\'hovertext\' single value case)', function(done) {
+ Plotly.restyle(gd, 'hovertext', 'hovertext').then(function() {
+ mouseEvent('mousemove', 381, 221);
+ assertHoverLabels(['(10°, 10°)', 'hovertext']);
+ })
+ .then(done);
+ });
+
+ it('should generate hover label info (\'hovertext\' array case)', function(done) {
+ Plotly.restyle(gd, 'hovertext', ['Apple', 'Banana', 'Orange']).then(function() {
+ mouseEvent('mousemove', 381, 221);
+ assertHoverLabels(['(10°, 10°)', 'Apple']);
+ })
+ .then(done);
+ });
+});
diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js
index ac2c8503648..1a2b84d05e5 100644
--- a/test/jasmine/tests/scattermapbox_test.js
+++ b/test/jasmine/tests/scattermapbox_test.js
@@ -468,7 +468,7 @@ describe('@noCI scattermapbox hover', function() {
});
});
- it('should generate hover label info (hoverinfo: \'text\' case)', function(done) {
+ it('should generate hover label info (hoverinfo: \'text\' + \'text\' array case)', function(done) {
Plotly.restyle(gd, 'hoverinfo', 'text').then(function() {
var xval = 11,
yval = 11;
@@ -479,6 +479,18 @@ describe('@noCI scattermapbox hover', function() {
done();
});
});
+
+ it('should generate hover label info (hoverinfo: \'text\' + \'hovertext\' array case)', function(done) {
+ Plotly.restyle(gd, 'hovertext', ['Apple', 'Banana', 'Orange']).then(function() {
+ var xval = 11,
+ yval = 11;
+
+ var out = hoverPoints(getPointData(gd), xval, yval)[0];
+
+ expect(out.extraText).toEqual('Apple');
+ done();
+ });
+ });
});
diff --git a/test/jasmine/tests/scatterternary_test.js b/test/jasmine/tests/scatterternary_test.js
index 21da09876f0..14c3a0ecd69 100644
--- a/test/jasmine/tests/scatterternary_test.js
+++ b/test/jasmine/tests/scatterternary_test.js
@@ -299,9 +299,7 @@ describe('scatterternary plot and hover', function() {
describe('scatterternary hover', function() {
'use strict';
- var hoverPoints = ScatterTernary.hoverPoints;
-
- var gd, pointData;
+ var gd;
beforeAll(function(done) {
gd = createGraphDiv();
@@ -310,17 +308,20 @@ describe('scatterternary hover', function() {
type: 'scatterternary',
a: [0.1, 0.2, 0.3],
b: [0.3, 0.2, 0.1],
- c: [0.1, 0.4, 0.5]
+ c: [0.1, 0.4, 0.5],
+ text: ['A', 'B', 'C']
}];
Plotly.plot(gd, data).then(done);
});
- beforeEach(function() {
- var cd = gd.calcdata,
- ternary = gd._fullLayout.ternary._subplot;
+ afterAll(destroyGraphDiv);
+
+ function _hover(gd, xval, yval, hovermode) {
+ var cd = gd.calcdata;
+ var ternary = gd._fullLayout.ternary._subplot;
- pointData = {
+ var pointData = {
index: false,
distance: 20,
cd: cd[0],
@@ -329,16 +330,16 @@ describe('scatterternary hover', function() {
ya: ternary.yaxis
};
- });
-
- afterAll(destroyGraphDiv);
+ return ScatterTernary.hoverPoints(pointData, xval, yval, hovermode);
+ }
- it('should generate extra text field on hover', function() {
- var xval = 0.42,
- yval = 0.37,
- hovermode = 'closest';
+ it('should generate extra text field on hover', function(done) {
+ var xval = 0.42;
+ var yval = 0.37;
+ var hovermode = 'closest';
+ var scatterPointData;
- var scatterPointData = hoverPoints(pointData, xval, yval, hovermode);
+ scatterPointData = _hover(gd, xval, yval, hovermode);
expect(scatterPointData[0].extraText).toEqual(
'Component A: 0.3333333
Component B: 0.1111111
Component C: 0.5555556'
@@ -346,6 +347,24 @@ describe('scatterternary hover', function() {
expect(scatterPointData[0].xLabelVal).toBeUndefined();
expect(scatterPointData[0].yLabelVal).toBeUndefined();
+ expect(scatterPointData[0].text).toEqual('C');
+
+ Plotly.restyle(gd, {
+ text: null,
+ hovertext: [['apple', 'banana', 'orange']]
+ })
+ .then(function() {
+ scatterPointData = _hover(gd, xval, yval, hovermode);
+
+ expect(scatterPointData[0].extraText).toEqual(
+ 'Component A: 0.3333333
Component B: 0.1111111
Component C: 0.5555556'
+ );
+
+ expect(scatterPointData[0].xLabelVal).toBeUndefined();
+ expect(scatterPointData[0].yLabelVal).toBeUndefined();
+ expect(scatterPointData[0].text).toEqual('orange');
+ })
+ .then(done);
});
});