diff --git a/src/traces/barpolar/attributes.js b/src/traces/barpolar/attributes.js index 0bc594a2878..e6540f1a6c6 100644 --- a/src/traces/barpolar/attributes.js +++ b/src/traces/barpolar/attributes.js @@ -58,7 +58,9 @@ module.exports = { 'this trace\'s coordinates.' ].join(' ') }), - // hovertext: barAttrs.hovertext, + hovertext: extendFlat({}, barAttrs.hovertext, { + description: 'Same as `text`.' + }), // textposition: {}, // textfont: {}, diff --git a/src/traces/barpolar/defaults.js b/src/traces/barpolar/defaults.js index 6619d60056c..4265f46d7ab 100644 --- a/src/traces/barpolar/defaults.js +++ b/src/traces/barpolar/defaults.js @@ -33,8 +33,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('width'); coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); - // coerce('hovertext'); // var textPosition = coerce('textposition'); // var hasBoth = Array.isArray(textPosition) || textPosition === 'auto'; diff --git a/src/traces/box/attributes.js b/src/traces/box/attributes.js index 7bfd9bce3ce..136e064b78c 100644 --- a/src/traces/box/attributes.js +++ b/src/traces/box/attributes.js @@ -72,6 +72,9 @@ module.exports = { 'To be seen, trace `hoverinfo` must contain a *text* flag.' ].join(' ') }), + hovertext: extendFlat({}, scatterAttrs.hovertext, { + description: 'Same as `text`.' + }), whiskerwidth: { valType: 'number', min: 0, diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js index 02fa7a15d0e..0e424c5223d 100644 --- a/src/traces/box/calc.js +++ b/src/traces/box/calc.js @@ -212,7 +212,8 @@ function initNestedArray(len) { function arraysToCalcdata(pt, trace, i) { var trace2calc = { - text: 'tx' + text: 'tx', + hovertext: 'htx' }; for(var k in trace2calc) { diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index b3d6500e5d4..9051230526c 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -100,6 +100,7 @@ function handlePointsDefaults(traceIn, traceOut, coerce, opts) { coerce('unselected.marker.size'); coerce('text'); + coerce('hovertext'); } else { delete traceOut.marker; } diff --git a/src/traces/candlestick/attributes.js b/src/traces/candlestick/attributes.js index 1f39192eb20..4b3fede5f3e 100644 --- a/src/traces/candlestick/attributes.js +++ b/src/traces/candlestick/attributes.js @@ -50,6 +50,7 @@ module.exports = { decreasing: directionAttrs(OHLCattrs.decreasing.line.color.dflt), text: OHLCattrs.text, + hovertext: OHLCattrs.hovertext, whiskerwidth: extendFlat({}, boxAttrs.whiskerwidth, { dflt: 0 }), hoverlabel: OHLCattrs.hoverlabel, diff --git a/src/traces/candlestick/defaults.js b/src/traces/candlestick/defaults.js index 6f21faead45..f4e2f6d64a4 100644 --- a/src/traces/candlestick/defaults.js +++ b/src/traces/candlestick/defaults.js @@ -31,6 +31,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleDirection(traceIn, traceOut, coerce, 'decreasing'); coerce('text'); + coerce('hovertext'); coerce('whiskerwidth'); layout._requestRangeslider[traceOut.xaxis] = true; diff --git a/src/traces/choropleth/attributes.js b/src/traces/choropleth/attributes.js index 07548ef5c6d..5e68b2b7f71 100644 --- a/src/traces/choropleth/attributes.js +++ b/src/traces/choropleth/attributes.js @@ -36,6 +36,9 @@ module.exports = extendFlat({ text: extendFlat({}, scatterGeoAttrs.text, { description: 'Sets the text elements associated with each location.' }), + hovertext: extendFlat({}, scatterGeoAttrs.hovertext, { + description: 'Same as `text`.' + }), marker: { line: { color: scatterGeoMarkerLineAttrs.color, diff --git a/src/traces/choropleth/defaults.js b/src/traces/choropleth/defaults.js index 952e0f9aaa6..47d84b91ae0 100644 --- a/src/traces/choropleth/defaults.js +++ b/src/traces/choropleth/defaults.js @@ -30,6 +30,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('locationmode'); coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); coerce('marker.line.color'); diff --git a/src/traces/cone/attributes.js b/src/traces/cone/attributes.js index e2a2f062fe2..0df3c8d9964 100644 --- a/src/traces/cone/attributes.js +++ b/src/traces/cone/attributes.js @@ -159,6 +159,14 @@ var attrs = { 'these elements will be seen in the hover labels.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + editType: 'calc', + description: 'Same as `text`.' + }, hovertemplate: hovertemplateAttrs({editType: 'calc'}, {keys: ['norm']}) }; diff --git a/src/traces/cone/convert.js b/src/traces/cone/convert.js index ee74707a413..dcdfcb9d5f1 100644 --- a/src/traces/cone/convert.js +++ b/src/traces/cone/convert.js @@ -40,7 +40,7 @@ proto.handlePick = function(selection) { Math.sqrt(uu * uu + vv * vv + ww * ww) ]; - var text = this.data.text; + var text = this.data.hovertext || this.data.text; if(Array.isArray(text) && text[selectIndex] !== undefined) { selection.textLabel = text[selectIndex]; } else if(text) { diff --git a/src/traces/cone/defaults.js b/src/traces/cone/defaults.js index 7237edba166..3b6f1d5fc91 100644 --- a/src/traces/cone/defaults.js +++ b/src/traces/cone/defaults.js @@ -52,6 +52,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'c'}); coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); // disable 1D transforms (for now) diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index 82055b84201..4e48ff14beb 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -31,6 +31,7 @@ module.exports = extendFlat({ y0: heatmapAttrs.y0, dy: heatmapAttrs.dy, text: heatmapAttrs.text, + hovertext: heatmapAttrs.hovertext, transpose: heatmapAttrs.transpose, xtype: heatmapAttrs.xtype, ytype: heatmapAttrs.ytype, diff --git a/src/traces/contour/defaults.js b/src/traces/contour/defaults.js index aa6cb7c8842..1dddb34d561 100644 --- a/src/traces/contour/defaults.js +++ b/src/traces/contour/defaults.js @@ -33,6 +33,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); var isConstraint = (coerce('contours.type') === 'constraint'); diff --git a/src/traces/contourcarpet/attributes.js b/src/traces/contourcarpet/attributes.js index 680ccec80cd..6bcec99d63f 100644 --- a/src/traces/contourcarpet/attributes.js +++ b/src/traces/contourcarpet/attributes.js @@ -36,6 +36,7 @@ module.exports = extendFlat({ b0: heatmapAttrs.y0, db: heatmapAttrs.dy, text: heatmapAttrs.text, + hovertext: heatmapAttrs.hovertext, transpose: heatmapAttrs.transpose, atype: heatmapAttrs.xtype, btype: heatmapAttrs.ytype, diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 9bf083d8098..89cc79bf02c 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -33,6 +33,11 @@ module.exports = extendFlat({ editType: 'calc', description: 'Sets the text elements associated with each z value.' }, + hovertext: { + valType: 'data_array', + editType: 'calc', + description: 'Same as `text`.' + }, transpose: { valType: 'boolean', dflt: false, diff --git a/src/traces/heatmap/calc.js b/src/traces/heatmap/calc.js index 13b4fdb61d4..32a82f76d3c 100644 --- a/src/traces/heatmap/calc.js +++ b/src/traces/heatmap/calc.js @@ -131,7 +131,8 @@ module.exports = function calc(gd, trace) { x: xArray, y: yArray, z: z, - text: trace._text || trace.text + text: trace._text || trace.text, + hovertext: trace._hovertext || trace.hovertext }; if(xIn && xIn.length === xArray.length - 1) cd0.xCenter = xIn; diff --git a/src/traces/heatmap/convert_column_xyz.js b/src/traces/heatmap/convert_column_xyz.js index cbc70c57a9e..ace8224f877 100644 --- a/src/traces/heatmap/convert_column_xyz.js +++ b/src/traces/heatmap/convert_column_xyz.js @@ -18,6 +18,8 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, var col2 = ax2.makeCalcdata(trace, var2Name); var textCol = trace.text; var hasColumnText = (textCol !== undefined && Lib.isArray1D(textCol)); + var hoverTextCol = trace.hovertext; + var hasColumnHoverText = (hoverTextCol !== undefined && Lib.isArray1D(hoverTextCol)); var i, j; var col1dv = Lib.distinctVals(col1); @@ -26,6 +28,7 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, var col2vals = col2dv.vals; var newArrays = []; var text; + var hovertext; for(i = 0; i < arrayVarNames.length; i++) { newArrays[i] = Lib.init2dArray(col2vals.length, col1vals.length); @@ -34,6 +37,9 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, if(hasColumnText) { text = Lib.init2dArray(col2vals.length, col1vals.length); } + if(hasColumnHoverText) { + hovertext = Lib.init2dArray(col2vals.length, col1vals.length); + } for(i = 0; i < colLen; i++) { if(col1[i] !== BADNUM && col2[i] !== BADNUM) { @@ -48,6 +54,7 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, } if(hasColumnText) text[i2][i1] = textCol[i]; + if(hasColumnHoverText) hovertext[i2][i1] = hoverTextCol[i]; } } @@ -57,4 +64,5 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, trace['_' + arrayVarNames[j]] = newArrays[j]; } if(hasColumnText) trace._text = text; + if(hasColumnHoverText) trace._hovertext = hovertext; }; diff --git a/src/traces/heatmap/defaults.js b/src/traces/heatmap/defaults.js index 6e2933cbc91..a245af88d95 100644 --- a/src/traces/heatmap/defaults.js +++ b/src/traces/heatmap/defaults.js @@ -29,6 +29,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); handleStyleDefaults(traceIn, traceOut, coerce, layout); diff --git a/src/traces/heatmap/hover.js b/src/traces/heatmap/hover.js index df7873aaa5b..0105156f1ca 100644 --- a/src/traces/heatmap/hover.js +++ b/src/traces/heatmap/hover.js @@ -93,7 +93,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay if(zmask && !zmask[ny][nx]) zVal = undefined; var text; - if(Array.isArray(cd0.text) && Array.isArray(cd0.text[ny])) { + if(Array.isArray(cd0.hovertext) && Array.isArray(cd0.hovertext[ny])) { + text = cd0.hovertext[ny][nx]; + } else if(Array.isArray(cd0.text) && Array.isArray(cd0.text[ny])) { text = cd0.text[ny][nx]; } diff --git a/src/traces/histogram/attributes.js b/src/traces/histogram/attributes.js index 5391922a702..d9e3136fff7 100644 --- a/src/traces/histogram/attributes.js +++ b/src/traces/histogram/attributes.js @@ -12,6 +12,7 @@ var barAttrs = require('../bar/attributes'); var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes'); var makeBinAttrs = require('./bin_attributes'); var constants = require('./constants'); +var extendFlat = require('../../lib/extend').extendFlat; module.exports = { x: { @@ -29,7 +30,17 @@ module.exports = { ].join(' ') }, - text: barAttrs.text, + text: extendFlat({}, barAttrs.text, { + description: [ + 'Sets hover text elements associated with each bar.', + 'If a single string, the same string appears over all bars.', + 'If an array of string, the items are mapped in order to the', + 'this trace\'s coordinates.' + ].join(' ') + }), + hovertext: extendFlat({}, barAttrs.hovertext, { + description: 'Same as `text`.' + }), orientation: barAttrs.orientation, histfunc: { diff --git a/src/traces/histogram/defaults.js b/src/traces/histogram/defaults.js index 747559f352a..51fbb8ce4f9 100644 --- a/src/traces/histogram/defaults.js +++ b/src/traces/histogram/defaults.js @@ -31,6 +31,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('text'); + coerce('hovertext'); + coerce('hovertemplate'); var orientation = coerce('orientation', (y && !x) ? 'h' : 'v'); var sampleLetter = orientation === 'v' ? 'x' : 'y'; @@ -58,8 +60,6 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout // autobin(x|y) are only included here to appease Plotly.validate coerce('autobin' + sampleLetter); - coerce('hovertemplate'); - handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout); Lib.coerceSelectionMarkerOpacity(traceOut, coerce); diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index c6af7cc065a..fd170ae05b1 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -226,6 +226,13 @@ var attrs = module.exports = overrideAll(extendFlat({ 'these elements will be seen in the hover labels.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + description: 'Same as `text`.' + }, hovertemplate: hovertemplateAttrs() }, diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index f636d5be583..5272cd0187b 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -73,7 +73,7 @@ proto.handlePick = function(selection) { this.data.value[selectIndex] ]; - var text = this.data.text; + var text = this.data.hovertext || this.data.text; if(Array.isArray(text) && text[selectIndex] !== undefined) { selection.textLabel = text[selectIndex]; } else if(text) { diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index 5fcb750081b..48b19dffa44 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -84,6 +84,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout // Coerce remaining properties [ 'text', + 'hovertext', 'hovertemplate', 'lighting.ambient', 'lighting.diffuse', diff --git a/src/traces/mesh3d/attributes.js b/src/traces/mesh3d/attributes.js index dea5596c3c0..bd90dfb8e86 100644 --- a/src/traces/mesh3d/attributes.js +++ b/src/traces/mesh3d/attributes.js @@ -90,6 +90,14 @@ module.exports = extendFlat({ 'these elements will be seen in the hover labels.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + editType: 'calc', + description: 'Same as `text`.' + }, hovertemplate: hovertemplateAttrs({editType: 'calc'}), delaunayaxis: { diff --git a/src/traces/mesh3d/convert.js b/src/traces/mesh3d/convert.js index 250c480b44e..7c2cc23d651 100644 --- a/src/traces/mesh3d/convert.js +++ b/src/traces/mesh3d/convert.js @@ -40,7 +40,7 @@ proto.handlePick = function(selection) { this.data.z[selectIndex] ]; - var text = this.data.text; + var text = this.data.hovertext || this.data.text; if(Array.isArray(text) && text[selectIndex] !== undefined) { selection.textLabel = text[selectIndex]; } else if(text) { diff --git a/src/traces/mesh3d/defaults.js b/src/traces/mesh3d/defaults.js index c46204a11c2..d4b5c6fcb89 100644 --- a/src/traces/mesh3d/defaults.js +++ b/src/traces/mesh3d/defaults.js @@ -88,6 +88,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); // disable 1D transforms diff --git a/src/traces/ohlc/attributes.js b/src/traces/ohlc/attributes.js index 317212cbd0b..c2051f24a2c 100644 --- a/src/traces/ohlc/attributes.js +++ b/src/traces/ohlc/attributes.js @@ -104,6 +104,14 @@ module.exports = { 'this trace\'s sample points.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + editType: 'calc', + description: 'Same as `text`.' + }, tickwidth: { valType: 'number', diff --git a/src/traces/ohlc/calc.js b/src/traces/ohlc/calc.js index ea8545e0d56..094e7384b40 100644 --- a/src/traces/ohlc/calc.js +++ b/src/traces/ohlc/calc.js @@ -56,6 +56,7 @@ function calcCommon(gd, trace, x, ya, ptFunc) { var c = ya.makeCalcdata(trace, 'close'); var hasTextArray = Array.isArray(trace.text); + var hasHovertextArray = Array.isArray(trace.hovertext); // we're optimists - before we have any changing data, assume increasing var increasing = true; @@ -87,6 +88,7 @@ function calcCommon(gd, trace, x, ya, ptFunc) { pt.dir = increasing ? 'increasing' : 'decreasing'; if(hasTextArray) pt.tx = trace.text[i]; + if(hasHovertextArray) pt.htx = trace.hovertext[i]; cd.push(pt); } else { diff --git a/src/traces/ohlc/defaults.js b/src/traces/ohlc/defaults.js index 3e5675dfd5e..32723023ba4 100644 --- a/src/traces/ohlc/defaults.js +++ b/src/traces/ohlc/defaults.js @@ -31,6 +31,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleDirection(traceIn, traceOut, coerce, 'decreasing'); coerce('text'); + coerce('hovertext'); coerce('tickwidth'); layout._requestRangeslider[traceOut.xaxis] = true; diff --git a/src/traces/scattercarpet/attributes.js b/src/traces/scattercarpet/attributes.js index 594b8407d05..c263e3b333a 100644 --- a/src/traces/scattercarpet/attributes.js +++ b/src/traces/scattercarpet/attributes.js @@ -34,33 +34,33 @@ module.exports = { a: { valType: 'data_array', editType: 'calc', - description: [ - 'Sets the quantity of component `a` in each data point.', - 'If `a`, `b`, and `c` are all provided, they need not be', - 'normalized, only the relative values matter. If only two', - 'arrays are provided they must be normalized to match', - '`ternary.sum`.' - ].join(' ') + description: 'Sets the a-axis coordinates.' }, b: { valType: 'data_array', editType: 'calc', - description: [ - 'Sets the quantity of component `a` in each data point.', - 'If `a`, `b`, and `c` are all provided, they need not be', - 'normalized, only the relative values matter. If only two', - 'arrays are provided they must be normalized to match', - '`ternary.sum`.' - ].join(' ') + description: 'Sets the b-axis coordinates.' }, mode: extendFlat({}, scatterAttrs.mode, {dflt: 'markers'}), text: extendFlat({}, scatterAttrs.text, { description: [ - 'Sets text elements associated with each (a,b,c) point.', + 'Sets text elements associated with each (a,b) 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).', + '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) 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).' + 'the data points in (a,b).', + 'To be seen, trace `hoverinfo` must contain a *text* flag.' ].join(' ') }), line: { diff --git a/src/traces/scattercarpet/defaults.js b/src/traces/scattercarpet/defaults.js index 61d28ba75b5..cea51be903d 100644 --- a/src/traces/scattercarpet/defaults.js +++ b/src/traces/scattercarpet/defaults.js @@ -44,6 +44,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout traceOut._length = len; coerce('text'); + coerce('hovertext'); var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines'; coerce('mode', defaultMode); diff --git a/src/traces/scattercarpet/hover.js b/src/traces/scattercarpet/hover.js index 16882588ca8..3f71bd0fbaf 100644 --- a/src/traces/scattercarpet/hover.js +++ b/src/traces/scattercarpet/hover.js @@ -6,10 +6,10 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var scatterHover = require('../scatter/hover'); +var fillHoverText = require('../scatter/fill_hover_text'); module.exports = function hoverPoints(pointData, xval, yval, hovermode) { var scatterPointData = scatterHover(pointData, xval, yval, hovermode); @@ -57,6 +57,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { var xy = carpet.evalxy([], i0, j0, ti, tj); newPointData.yLabel = xy[1].toFixed(3); + delete newPointData.text; var text = []; function textPart(ax, val) { @@ -76,12 +77,16 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { var hoverinfo = cdi.hi || trace.hoverinfo; var parts = hoverinfo.split('+'); - if(parts.indexOf('all') !== -1) parts = ['a', 'b']; + if(parts.indexOf('all') !== -1) parts = ['a', 'b', 'text']; if(parts.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a); if(parts.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b); text.push('y: ' + newPointData.yLabel); + if(parts.indexOf('text') !== -1) { + fillHoverText(cdi, trace, text); + } + newPointData.extraText = text.join('
'); } diff --git a/src/traces/splom/attributes.js b/src/traces/splom/attributes.js index 79dff01442a..a850bacfca6 100644 --- a/src/traces/splom/attributes.js +++ b/src/traces/splom/attributes.js @@ -124,6 +124,10 @@ module.exports = { 'this trace\'s (x,y) coordinates.' ].join(' ') }), + hovertext: extendFlat({}, scatterGlAttrs.hovertext, { + description: 'Same as `text`.' + }), + hovertemplate: hovertemplateAttrs(), marker: markerAttrs, diff --git a/src/traces/splom/defaults.js b/src/traces/splom/defaults.js index 1a268cef365..c27536ee0f8 100644 --- a/src/traces/splom/defaults.js +++ b/src/traces/splom/defaults.js @@ -39,6 +39,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce); diff --git a/src/traces/streamtube/attributes.js b/src/traces/streamtube/attributes.js index 4dfbd303912..c1a4c08810e 100644 --- a/src/traces/streamtube/attributes.js +++ b/src/traces/streamtube/attributes.js @@ -132,6 +132,13 @@ var attrs = { 'Note that streamtube traces do not support array `text` values.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + editType: 'calc', + description: 'Same as `text`.' + }, hovertemplate: hovertemplateAttrs({editType: 'calc'}, { keys: [ 'tubex', 'tubey', 'tubez', diff --git a/src/traces/streamtube/convert.js b/src/traces/streamtube/convert.js index d663c262fb5..ced5c0b1508 100644 --- a/src/traces/streamtube/convert.js +++ b/src/traces/streamtube/convert.js @@ -55,7 +55,7 @@ proto.handlePick = function(selection) { selection.data.divergence ]; - selection.textLabel = this.data.text; + selection.textLabel = this.data.hovertext || this.data.text; return true; } diff --git a/src/traces/streamtube/defaults.js b/src/traces/streamtube/defaults.js index e8bae6160d5..f118a41f665 100644 --- a/src/traces/streamtube/defaults.js +++ b/src/traces/streamtube/defaults.js @@ -53,6 +53,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'c'}); coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); // disable 1D transforms (for now) diff --git a/src/traces/surface/attributes.js b/src/traces/surface/attributes.js index 5a573dc9f23..cf34be68e7e 100644 --- a/src/traces/surface/attributes.js +++ b/src/traces/surface/attributes.js @@ -124,6 +124,13 @@ var attrs = module.exports = overrideAll(extendFlat({ 'these elements will be seen in the hover labels.' ].join(' ') }, + hovertext: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + description: 'Same as `text`.' + }, hovertemplate: hovertemplateAttrs(), surfacecolor: { diff --git a/src/traces/surface/convert.js b/src/traces/surface/convert.js index 74397d78ae5..488d55419ae 100644 --- a/src/traces/surface/convert.js +++ b/src/traces/surface/convert.js @@ -96,7 +96,7 @@ proto.handlePick = function(selection) { } } - var text = this.data.text; + var text = this.data.hovertext || this.data.text; if(Array.isArray(text) && text[k] && text[k][j] !== undefined) { selection.textLabel = text[k][j]; } else if(text) { diff --git a/src/traces/surface/defaults.js b/src/traces/surface/defaults.js index 3ca1cf856db..0e83b883fce 100644 --- a/src/traces/surface/defaults.js +++ b/src/traces/surface/defaults.js @@ -42,6 +42,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout); coerce('text'); + coerce('hovertext'); coerce('hovertemplate'); // Coerce remaining properties diff --git a/src/traces/violin/attributes.js b/src/traces/violin/attributes.js index ba71026aadf..bd26d9afc41 100644 --- a/src/traces/violin/attributes.js +++ b/src/traces/violin/attributes.js @@ -146,6 +146,7 @@ module.exports = { marker: boxAttrs.marker, text: boxAttrs.text, + hovertext: boxAttrs.hovertext, box: { visible: { diff --git a/test/image/baselines/scattercarpet-text.png b/test/image/baselines/scattercarpet-text.png new file mode 100644 index 00000000000..fb67389676b Binary files /dev/null and b/test/image/baselines/scattercarpet-text.png differ diff --git a/test/image/mocks/scattercarpet-text.json b/test/image/mocks/scattercarpet-text.json new file mode 100644 index 00000000000..0e419094786 --- /dev/null +++ b/test/image/mocks/scattercarpet-text.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "type": "carpet", + "a": [0.1, 0.2, 0.3], + "b": [1, 2, 3], + "y": [ + [1, 2.2, 3], + [1.5, 2.7, 3.5], + [1.7, 2.9, 3.7] + ], + "cheaterslope": 1, + "aaxis": { + "title": "a", + "tickmode": "linear", + "dtick": 0.05 + }, + "baxis": { + "title": "b", + "tickmode": "linear", + "dtick": 0.5 + } + }, + { + "type": "scattercarpet", + "name": "b = 1.5", + "mode": "markers+text", + "a": [0.05, 0.15, 0.25, 0.35], + "b": [1.5, 1.5, 1.5, 1.5], + "text": ["a", "b", "c", "d"] + }, + { + "type": "scattercarpet", + "name": "b = 2", + "mode": "markers+lines+text", + "a": [0.05, 0.15, 0.25, 0.35], + "b": [2, 2, 2, 2], + "text": ["a", "b", "c", "d"] + }, + { + "type": "scattercarpet", + "name": "b = 2.5", + "mode": "text", + "a": [0.05, 0.15, 0.25, 0.35], + "b": [2.5, 2.5, 2.5, 2.5], + "text": ["a", "b", "c", "d"] + } + ], + "layout": { + "title": "scattercarpet with text", + "hovermode": "closest" + } +} diff --git a/test/jasmine/tests/barpolar_test.js b/test/jasmine/tests/barpolar_test.js index 76bf9bc943d..8de6bd291fc 100644 --- a/test/jasmine/tests/barpolar_test.js +++ b/test/jasmine/tests/barpolar_test.js @@ -163,6 +163,40 @@ describe('Test barpolar hover:', function() { extraText: 'r: 1
θ: 0°
A', color: '#1f77b4' } + }, { + desc: 'with custom hovertext scalar', + traces: [{ + r: [1, 2, 3], + theta: [0, 90, 180], + hovertext: 'TEXT', + text: 'nop!' + }], + xval: 1, + yval: 0, + exp: { + index: 0, + x: 263.33, + y: 200, + extraText: 'r: 1
θ: 0°
TEXT', + color: '#1f77b4' + } + }, { + desc: 'with custom hovertext array', + traces: [{ + r: [1, 2, 3], + theta: [0, 90, 180], + hovertext: ['A', 'B', 'C'], + text: ['n', 'o', 'p'] + }], + xval: 1, + yval: 0, + exp: { + index: 0, + x: 263.33, + y: 200, + extraText: 'r: 1
θ: 0°
A', + color: '#1f77b4' + } }, { desc: 'works with bars with offsets', traces: [{ diff --git a/test/jasmine/tests/box_test.js b/test/jasmine/tests/box_test.js index 694735de757..ab8d0f1294e 100644 --- a/test/jasmine/tests/box_test.js +++ b/test/jasmine/tests/box_test.js @@ -317,6 +317,22 @@ describe('Test box hover:', function() { }, nums: 'look:0.7', name: '' + }, { + desc: 'only hovertext items on hover', + patch: function(fig) { + fig.data.forEach(function(trace) { + trace.boxpoints = 'all'; + trace.hoveron = 'points'; + trace.text = trace.y.map(function(v) { return 'NOT THIS:' + v; }); + trace.hovertext = trace.y.map(function(v) { return 'look:' + v; }); + trace.hoverinfo = 'text'; + }); + fig.layout.hovermode = 'closest'; + fig.layout.xaxis = {range: [-0.565, 1.5]}; + return fig; + }, + nums: 'look:0.7', + name: '' }, { desc: 'orientation:h | hovermode:y', mock: require('@mocks/box_grouped_horz.json'), diff --git a/test/jasmine/tests/carpet_test.js b/test/jasmine/tests/carpet_test.js index ffc385f940c..3fada7b2e71 100644 --- a/test/jasmine/tests/carpet_test.js +++ b/test/jasmine/tests/carpet_test.js @@ -657,6 +657,18 @@ describe('scattercarpet hover labels', function() { .then(done); }); + it('should generate hover label (with hovertext array)', function(done) { + var fig = Lib.extendDeep({}, require('@mocks/scattercarpet.json')); + fig.data[5].hovertext = ['A', 'B', 'C', 'D']; + fig.data[5].text = ['N', 'O', 'P', '!']; + + run( + [200, 200], fig, + [['a: 0.200', 'b: 3.500', 'y: 2.900', 'D'], 'a = 0.2'] + ) + .then(done); + }); + it('should generate hover label with \'hoverinfo\' set', function(done) { var fig = Lib.extendDeep({}, require('@mocks/scattercarpet.json')); fig.data[5].hoverinfo = 'a+y'; diff --git a/test/jasmine/tests/choropleth_test.js b/test/jasmine/tests/choropleth_test.js index 6d1985ec70d..ba745b55d2c 100644 --- a/test/jasmine/tests/choropleth_test.js +++ b/test/jasmine/tests/choropleth_test.js @@ -152,6 +152,20 @@ describe('Test choropleth hover:', function() { .then(done); }); + it('should generate hover labels from `hovertext`', function(done) { + var fig = Lib.extendDeep({}, require('@mocks/geo_first.json')); + fig.data[1].hovertext = ['tExT', 'TeXt', '-text-']; + fig.data[1].text = ['N', 'O', 'P']; + fig.data[1].hoverinfo = 'text'; + + run( + [400, 160], + fig, + ['-text-', null] + ) + .then(done); + }); + it('should generate hover label with custom styling', function(done) { var fig = Lib.extendDeep({}, require('@mocks/geo_first.json')); fig.data[1].hoverlabel = { diff --git a/test/jasmine/tests/cone_test.js b/test/jasmine/tests/cone_test.js index f43b106666b..80e11ae16bd 100644 --- a/test/jasmine/tests/cone_test.js +++ b/test/jasmine/tests/cone_test.js @@ -298,6 +298,21 @@ describe('Test cone interactions', function() { ].join('\n') }); + return Plotly.restyle(gd, 'hovertext', 'look'); + }) + .then(delay(20)) + .then(_hover) + .then(function() { + assertHoverLabelContent({ + name: 'trace 0', + nums: [ + 'x: 2', 'y: 2', 'z: 2', + 'u: 0', 'v: 3', 'w: 0', + 'norm: 3.00', + 'look' + ].join('\n') + }); + return Plotly.restyle(gd, 'hovertemplate', 'NORM : %{norm}
at %{x},%{y},%{z}LOOKOUT'); }) .then(delay(20)) diff --git a/test/jasmine/tests/finance_test.js b/test/jasmine/tests/finance_test.js index 52ce663fb57..2fee00f27dd 100644 --- a/test/jasmine/tests/finance_test.js +++ b/test/jasmine/tests/finance_test.js @@ -1217,6 +1217,20 @@ describe('finance trace hover:', function() { exp: { extraText: 'A' } + }, { + type: type, + desc: 'just scalar hovertext', + traces: [{hoverinfo: 'text', hovertext: 'SCALAR', text: 'NOP'}], + exp: { + extraText: 'SCALAR' + } + }, { + type: type, + desc: 'just array hovertext', + traces: [{hoverinfo: 'text', hovertext: ['A', 'B'], text: ['N', 'O', 'P']}], + exp: { + extraText: 'A' + } }, { type: type, desc: 'just array text with array hoverinfo', diff --git a/test/jasmine/tests/gl3d_plot_interact_test.js b/test/jasmine/tests/gl3d_plot_interact_test.js index 91c881f5faf..ba520930978 100644 --- a/test/jasmine/tests/gl3d_plot_interact_test.js +++ b/test/jasmine/tests/gl3d_plot_interact_test.js @@ -342,9 +342,15 @@ describe('Test gl3d plots', function() { return Plotly.restyle(gd, 'text', 'yo!'); }) + .then(_hover) .then(function() { assertHoverText(null, null, null, 'yo!'); + return Plotly.restyle(gd, 'hovertext', 'ONE TWO'); + }) + .then(function() { + assertHoverText(null, null, null, 'ONE TWO'); + return Plotly.restyle(gd, 'hovertemplate', '!!! %{z} !!!'); }) .then(function() { @@ -428,6 +434,14 @@ describe('Test gl3d plots', function() { .then(function() { assertHoverText(null, null, null, 'yo!'); }) + .then(function() { + return Plotly.restyle(gd, 'hovertext', [ + text.map(function(tx) { return tx + ' !!'; }) + ]); + }) + .then(function() { + assertHoverText(null, null, null, 'ts: 3\nhz: 4\nftt:5 !!'); + }) .then(function() { return Plotly.restyle(gd, 'hovertemplate', '%{x}-%{y}-%{z}'); }) diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index b5ff4bc0e9f..c8178a78fe2 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -655,6 +655,18 @@ describe('hover info', function() { name: 'one' }); }) + .then(function() { + return Plotly.restyle(gd, 'hovertext', [ + [['A', 'B', 'C'], ['X', 'Y', 'Z']] + ], [1]); + }) + .then(function() { + _hover(gd, 250, 100); + assertHoverLabelContent({ + nums: 'x: 1\ny: 3\nz: 2\nY', + name: 'two' + }); + }) .catch(failTest) .then(done); }); @@ -766,6 +778,18 @@ describe('hover info', function() { name: 'one' }); }) + .then(function() { + return Plotly.restyle(gd, 'hovertext', [ + [['A', 'B', 'C'], ['X', 'Y', 'Z']] + ]); + }) + .then(function() { + _hover(gd, 250, 50); + assertHoverLabelContent({ + nums: 'x: 1\ny: 3\nz: 2\nY', + name: 'two' + }); + }) .then(function() { return Plotly.restyle(gd, 'hovertemplate', '(%{x},%{y}) -- %{z}trace %{data.name}'); }) @@ -1071,6 +1095,14 @@ describe('hover info', function() { axis: '3.3' }); }) + .then(function() { return Plotly.restyle(gd, 'hovertext', 'LOOK'); }) + .then(function() { + _hover(gd, 250, 200); + assertHoverLabelContent({ + nums: '3\nLOOK', + axis: '3.3' + }); + }) .catch(failTest) .then(done); }); diff --git a/test/jasmine/tests/isosurface_test.js b/test/jasmine/tests/isosurface_test.js index 3b821063aa8..b55b235fc12 100644 --- a/test/jasmine/tests/isosurface_test.js +++ b/test/jasmine/tests/isosurface_test.js @@ -398,6 +398,24 @@ describe('Test isosurface', function() { ].join('\n') }); }) + .then(function() { + return Plotly.restyle(gd, 'hovertext', [ + fig.data[0].value.map(function(v) { return '!! ' + v + ' !!'; }) + ]); + }) + .then(delay(20)) + .then(_hover4) + .then(function() { + assertHoverLabelContent({ + nums: [ + 'x: 0.4', + 'y: 100μ', + 'z: −4', + 'value: −1.3', + '!! -1.3 !!' + ].join('\n') + }); + }) .then(function() { return Plotly.restyle(gd, 'hovertemplate', '%{value}
(%{x},%{y},%{z})!!'); }) diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js index 815671aa976..e1058a3224a 100644 --- a/test/jasmine/tests/splom_test.js +++ b/test/jasmine/tests/splom_test.js @@ -1360,6 +1360,19 @@ describe('Test splom hover:', function() { nums: 'Apr 2003', axis: 'Jan 2000', evtPts: [{x: '2000-01-01', y: '2003-04-21', pointNumber: 0}] + }, { + desc: 'with hovertext', + patch: function(fig) { + fig.data.forEach(function(t) { + t.hovertext = 'LOOK'; + t.text = 'NOP'; + }); + fig.layout.hovermode = 'closest'; + return fig; + }, + nums: '(2.6, 7.7)\nLOOK', + name: 'Virginica', + evtPts: [{x: 2.6, y: 7.7, pointNumber: 18, curveNumber: 2}] }, { desc: 'with a hovertemplate', patch: function(fig) { diff --git a/test/jasmine/tests/streamtube_test.js b/test/jasmine/tests/streamtube_test.js index 1316e90c92e..43528a8df9a 100644 --- a/test/jasmine/tests/streamtube_test.js +++ b/test/jasmine/tests/streamtube_test.js @@ -359,6 +359,12 @@ describe('@noCI Test streamtube hover', function() { .then(_hover) .then(function() { assertHoverLabelContent({nums: '!SCALAR TX!'}); + return Plotly.restyle(gd, 'hovertext', 'SCALAR HOVERTEXT !!'); + }) + .then(delay(20)) + .then(_hover) + .then(function() { + assertHoverLabelContent({nums: 'SCALAR HOVERTEXT !!'}); }) .catch(failTest) .then(done); diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 9cca890e9c7..5b0f6ee9da4 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -424,6 +424,22 @@ describe('Test violin hover:', function() { pos: [180, 240], nums: 'look:0.7', name: '' + }, { + desc: 'only hovertext items on hover', + patch: function(fig) { + fig.data.forEach(function(trace) { + trace.points = 'all'; + trace.hoveron = 'points'; + trace.hovertext = trace.y.map(function(v) { return 'look:' + v; }); + trace.text = trace.y.map(function(v) { return 'NOT THIS:' + v; }); + trace.hoverinfo = 'text'; + }); + fig.layout.hovermode = 'closest'; + return fig; + }, + pos: [180, 240], + nums: 'look:0.7', + name: '' }, { desc: 'one-sided violin under hovermode closest', // hoveron: 'kde+points'