diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index a8738cf3f6e..ddcebd1c9e8 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1609,11 +1609,11 @@ function cleanPoint(d, hovermode) { // and convert the x and y label values into formatted text if(d.xLabelVal !== undefined) { - d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal); + d.xLabel = ('xLabel' in d) ? d.xLabel : Axes.hoverLabelText(d.xa, d.xLabelVal, trace.xhoverformat); d.xVal = d.xa.c2d(d.xLabelVal); } if(d.yLabelVal !== undefined) { - d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal); + d.yLabel = ('yLabel' in d) ? d.yLabel : Axes.hoverLabelText(d.ya, d.yLabelVal, trace.yhoverformat); d.yVal = d.ya.c2d(d.yLabelVal); } diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index d2fb02d908e..ab469748308 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -1361,16 +1361,23 @@ axes.tickText = function(ax, x, hover, noSuffixPrefix) { * log axes (where negative values can't be displayed but can appear in hover text) * * @param {object} ax: the axis to format text for - * @param {number} val: calcdata value to format - * @param {Optional(number)} val2: a second value to display + * @param {number or array of numbers} values: calcdata value(s) to format + * @param {Optional(string)} hoverformat: trace (x|y)hoverformat to override axis.hoverformat * * @returns {string} `val` formatted as a string appropriate to this axis, or - * `val` and `val2` as a range (ie ' - ') if `val2` is provided and - * it's different from `val`. + * first value and second value as a range (ie ' - ') if the second value is provided and + * it's different from the first value. */ -axes.hoverLabelText = function(ax, val, val2) { - if(val2 !== BADNUM && val2 !== val) { - return axes.hoverLabelText(ax, val) + ' - ' + axes.hoverLabelText(ax, val2); +axes.hoverLabelText = function(ax, values, hoverformat) { + if(hoverformat) ax = Lib.extendFlat({}, ax, {hoverformat: hoverformat}); + + var val = Array.isArray(values) ? values[0] : values; + var val2 = Array.isArray(values) ? values[1] : undefined; + if(val2 !== undefined && val2 !== val) { + return ( + axes.hoverLabelText(ax, val, hoverformat) + ' - ' + + axes.hoverLabelText(ax, val2, hoverformat) + ); } var logOffScale = (ax.type === 'log' && val <= 0); diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index ea2b420c75e..88a96672e34 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -6,8 +6,10 @@ var dash = require('../../components/drawing/attributes').dash; var extendFlat = require('../../lib/extend').extendFlat; var templatedArray = require('../../plot_api/plot_template').templatedArray; -var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK; -var DATE_FORMAT_LINK = require('../../constants/docs').DATE_FORMAT_LINK; +var docs = require('../../constants/docs'); +var FORMAT_LINK = docs.FORMAT_LINK; +var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK; + var ONEDAY = require('../../constants/numerical').ONEDAY; var constants = require('./constants'); var HOUR = constants.HOUR_PATTERN; diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js index 6e89d682e5d..b7ee3871218 100644 --- a/src/plots/gl3d/scene.js +++ b/src/plots/gl3d/scene.js @@ -322,10 +322,14 @@ proto.render = function() { if(trace.setContourLevels) trace.setContourLevels(); } - function formatter(axisName, val) { - var axis = scene.fullSceneLayout[axisName]; + function formatter(axLetter, val, hoverformat) { + var ax = scene.fullSceneLayout[axLetter + 'axis']; - return Axes.tickText(axis, axis.d2l(val), 'hover').text; + if(ax.type !== 'log') { + val = ax.d2l(val); + } + + return Axes.hoverLabelText(ax, val, hoverformat); } var oldEventData; @@ -337,9 +341,9 @@ proto.render = function() { var ptNumber = selection.index; var labels = { - xLabel: formatter('xaxis', selection.traceCoordinate[0]), - yLabel: formatter('yaxis', selection.traceCoordinate[1]), - zLabel: formatter('zaxis', selection.traceCoordinate[2]) + xLabel: formatter('x', selection.traceCoordinate[0], trace.xhoverformat), + yLabel: formatter('y', selection.traceCoordinate[1], trace.yhoverformat), + zLabel: formatter('z', selection.traceCoordinate[2], trace.zhoverformat) }; var hoverinfo = Fx.castHoverinfo(traceNow, scene.fullLayout, ptNumber); @@ -358,17 +362,17 @@ proto.render = function() { var vectorTx = []; if(trace.type === 'cone' || trace.type === 'streamtube') { - labels.uLabel = formatter('xaxis', selection.traceCoordinate[3]); + labels.uLabel = formatter('x', selection.traceCoordinate[3], trace.uhoverformat); if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) { vectorTx.push('u: ' + labels.uLabel); } - labels.vLabel = formatter('yaxis', selection.traceCoordinate[4]); + labels.vLabel = formatter('y', selection.traceCoordinate[4], trace.vhoverformat); if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) { vectorTx.push('v: ' + labels.vLabel); } - labels.wLabel = formatter('zaxis', selection.traceCoordinate[5]); + labels.wLabel = formatter('z', selection.traceCoordinate[5], trace.whoverformat); if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) { vectorTx.push('w: ' + labels.wLabel); } @@ -388,7 +392,7 @@ proto.render = function() { } tx = vectorTx.join('
'); } else if(trace.type === 'isosurface' || trace.type === 'volume') { - labels.valueLabel = Axes.tickText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), 'hover').text; + labels.valueLabel = Axes.hoverLabelText(scene._mockAxis, scene._mockAxis.d2l(selection.traceCoordinate[3]), trace.valuehoverformat); vectorTx.push('value: ' + labels.valueLabel); if(selection.textLabel) { vectorTx.push(selection.textLabel); diff --git a/src/plots/hoverformat_attributes.js b/src/plots/hoverformat_attributes.js new file mode 100644 index 00000000000..58ef52c0010 --- /dev/null +++ b/src/plots/hoverformat_attributes.js @@ -0,0 +1,27 @@ +'use strict'; + +var docs = require('../constants/docs'); +var FORMAT_LINK = docs.FORMAT_LINK; +var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK; + +module.exports = function axisHoverFormat(x, noDates) { + return { + valType: 'string', + dflt: '', + editType: 'none', + description: [ + 'Sets the hover text formatting rule for `' + x + '`', + ' using d3 formatting mini-languages which are very similar to those in Python.', + 'See: ' + FORMAT_LINK + ( + noDates ? + '' : + ' And for dates see: ' + DATE_FORMAT_LINK + ), + 'By default the values are formatted using ' + ( + noDates ? + 'generic number format' : + ('`' + x + 'axis.hoverformat`') + ) + '.', + ].join(' ') + }; +}; diff --git a/src/plots/template_attributes.js b/src/plots/template_attributes.js index efcaba0c77c..70a0e536d87 100644 --- a/src/plots/template_attributes.js +++ b/src/plots/template_attributes.js @@ -1,7 +1,8 @@ 'use strict'; -var FORMAT_LINK = require('../constants/docs').FORMAT_LINK; -var DATE_FORMAT_LINK = require('../constants/docs').DATE_FORMAT_LINK; +var docs = require('../constants/docs'); +var FORMAT_LINK = docs.FORMAT_LINK; +var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK; var templateFormatStringDescription = [ 'Variables are inserted using %{variable}, for example "y: %{y}".', diff --git a/src/traces/bar/attributes.js b/src/traces/bar/attributes.js index 3e32060afd2..6dd46228fb5 100644 --- a/src/traces/bar/attributes.js +++ b/src/traces/bar/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var scatterAttrs = require('../scatter/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var colorScaleAttrs = require('../../components/colorscale/attributes'); @@ -104,6 +105,8 @@ module.exports = { yperiod0: scatterAttrs.yperiod0, xperiodalignment: scatterAttrs.xperiodalignment, yperiodalignment: scatterAttrs.yperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), text: scatterAttrs.text, texttemplate: texttemplateAttrs({editType: 'plot'}, { diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js index 631afc4d16a..2ea8c258e2c 100644 --- a/src/traces/bar/defaults.js +++ b/src/traces/bar/defaults.js @@ -24,6 +24,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('orientation', (traceOut.x && !traceOut.y) ? 'h' : 'v'); coerce('base'); diff --git a/src/traces/bar/hover.js b/src/traces/bar/hover.js index ee0d226d027..e6023543686 100644 --- a/src/traces/bar/hover.js +++ b/src/traces/bar/hover.js @@ -170,9 +170,9 @@ function hoverOnBars(pointData, xval, yval, hovermode) { var hasPeriod = di.orig_p !== undefined; pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p; - pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal']); - pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal']); - pointData.baseLabel = hoverLabelText(sa, di.b); + pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal'], trace[posLetter + 'hoverformat']); + pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal'], trace[sizeLetter + 'hoverformat']); + pointData.baseLabel = hoverLabelText(sa, di.b, trace[sizeLetter + 'hoverformat']); // spikelines always want "closest" distance regardless of hovermode pointData.spikeDistance = (thisBarSizeFn(di) + thisBarPositionFn(di)) / 2; diff --git a/src/traces/box/attributes.js b/src/traces/box/attributes.js index 0afc351edd7..2d4ca2755c0 100644 --- a/src/traces/box/attributes.js +++ b/src/traces/box/attributes.js @@ -3,6 +3,7 @@ var scatterAttrs = require('../scatter/attributes'); var barAttrs = require('../bar/attributes'); var colorAttrs = require('../../components/color/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var extendFlat = require('../../lib/extend').extendFlat; @@ -70,6 +71,8 @@ module.exports = { yperiod0: scatterAttrs.yperiod0, xperiodalignment: scatterAttrs.xperiodalignment, yperiodalignment: scatterAttrs.yperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), name: { valType: 'string', diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index 0a5c66c9f89..ad037009559 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -17,6 +17,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { if(traceOut.visible === false) return; handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); var hasPreCompStats = traceOut._hasPreCompStats; diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 901ddb3399e..6ae73777347 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -166,7 +166,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData2.attr = attr; pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx; pointData2[vLetter + 'LabelVal'] = val; - pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val); + pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val, trace[vLetter + 'hoverformat']); // Note: introduced to be able to distinguish a // clicked point from a box during click-to-select diff --git a/src/traces/candlestick/attributes.js b/src/traces/candlestick/attributes.js index 3e310a76139..5bd37ebcb8b 100644 --- a/src/traces/candlestick/attributes.js +++ b/src/traces/candlestick/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var extendFlat = require('../../lib').extendFlat; +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var OHLCattrs = require('../ohlc/attributes'); var boxAttrs = require('../box/attributes'); @@ -21,6 +22,8 @@ module.exports = { xperiod: OHLCattrs.xperiod, xperiod0: OHLCattrs.xperiod0, xperiodalignment: OHLCattrs.xperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), x: OHLCattrs.x, open: OHLCattrs.open, @@ -46,6 +49,7 @@ module.exports = { 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 2b69f033bb5..43ca40f8809 100644 --- a/src/traces/candlestick/defaults.js +++ b/src/traces/candlestick/defaults.js @@ -18,6 +18,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } handlePeriodDefaults(traceIn, traceOut, layout, coerce, {x: true}); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('line.width'); diff --git a/src/traces/carpet/axis_attributes.js b/src/traces/carpet/axis_attributes.js index 97b129f7dc6..e3548c68d8b 100644 --- a/src/traces/carpet/axis_attributes.js +++ b/src/traces/carpet/axis_attributes.js @@ -5,8 +5,9 @@ var colorAttrs = require('../../components/color/attributes'); var axesAttrs = require('../../plots/cartesian/layout_attributes'); var overrideAll = require('../../plot_api/edit_types').overrideAll; -var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK; -var DATE_FORMAT_LINK = require('../../constants/docs').TIME_FORMAT_LINK; +var docs = require('../../constants/docs'); +var FORMAT_LINK = docs.FORMAT_LINK; +var DATE_FORMAT_LINK = docs.DATE_FORMAT_LINK; module.exports = { color: { diff --git a/src/traces/cone/attributes.js b/src/traces/cone/attributes.js index 3181e854e3a..640fa2e0ae0 100644 --- a/src/traces/cone/attributes.js +++ b/src/traces/cone/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var mesh3dAttrs = require('../mesh3d/attributes'); var baseAttrs = require('../../plots/attributes'); @@ -152,6 +153,13 @@ var attrs = { }, hovertemplate: hovertemplateAttrs({editType: 'calc'}, {keys: ['norm']}), + uhoverformat: axisHoverFormat('u', 1), + vhoverformat: axisHoverFormat('v', 1), + whoverformat: axisHoverFormat('w', 1), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}) }; diff --git a/src/traces/cone/defaults.js b/src/traces/cone/defaults.js index 479ff0205a0..0516c8635d1 100644 --- a/src/traces/cone/defaults.js +++ b/src/traces/cone/defaults.js @@ -45,6 +45,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('uhoverformat'); + coerce('vhoverformat'); + coerce('whoverformat'); + coerce('xhoverformat'); + coerce('yhoverformat'); + coerce('zhoverformat'); // disable 1D transforms (for now) traceOut._length = null; diff --git a/src/traces/contour/attributes.js b/src/traces/contour/attributes.js index 350cb1766b9..dd59ee803d4 100644 --- a/src/traces/contour/attributes.js +++ b/src/traces/contour/attributes.js @@ -2,6 +2,7 @@ var heatmapAttrs = require('../heatmap/attributes'); var scatterAttrs = require('../scatter/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var colorScaleAttrs = require('../../components/colorscale/attributes'); var dash = require('../../components/drawing/attributes').dash; var fontAttrs = require('../../plots/font_attributes'); @@ -36,7 +37,9 @@ module.exports = extendFlat({ transpose: heatmapAttrs.transpose, xtype: heatmapAttrs.xtype, ytype: heatmapAttrs.ytype, - zhoverformat: heatmapAttrs.zhoverformat, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z', 1), hovertemplate: heatmapAttrs.hovertemplate, hoverongaps: heatmapAttrs.hoverongaps, connectgaps: extendFlat({}, heatmapAttrs.connectgaps, { diff --git a/src/traces/contour/defaults.js b/src/traces/contour/defaults.js index e5a4b0424fb..d0ce4a55428 100644 --- a/src/traces/contour/defaults.js +++ b/src/traces/contour/defaults.js @@ -26,6 +26,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('text'); coerce('hovertext'); diff --git a/src/traces/funnel/attributes.js b/src/traces/funnel/attributes.js index dc921f32ec2..1c7e5ef5223 100644 --- a/src/traces/funnel/attributes.js +++ b/src/traces/funnel/attributes.js @@ -3,6 +3,7 @@ var barAttrs = require('../bar/attributes'); var lineAttrs = require('../scatter/attributes').line; var baseAttrs = require('../../plots/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var constants = require('./constants'); @@ -23,6 +24,8 @@ module.exports = { yperiod0: barAttrs.yperiod0, xperiodalignment: barAttrs.xperiodalignment, yperiodalignment: barAttrs.yperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), hovertext: barAttrs.hovertext, hovertemplate: hovertemplateAttrs({}, { diff --git a/src/traces/funnel/defaults.js b/src/traces/funnel/defaults.js index 85ad6ff466a..74c2238a72d 100644 --- a/src/traces/funnel/defaults.js +++ b/src/traces/funnel/defaults.js @@ -21,6 +21,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('orientation', (traceOut.y && !traceOut.x) ? 'v' : 'h'); coerce('offset'); diff --git a/src/traces/heatmap/attributes.js b/src/traces/heatmap/attributes.js index 750c4f68986..be43069692b 100644 --- a/src/traces/heatmap/attributes.js +++ b/src/traces/heatmap/attributes.js @@ -2,9 +2,9 @@ var scatterAttrs = require('../scatter/attributes'); var baseAttrs = require('../../plots/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var colorScaleAttrs = require('../../components/colorscale/attributes'); -var FORMAT_LINK = require('../../constants/docs').FORMAT_LINK; var extendFlat = require('../../lib/extend').extendFlat; @@ -111,16 +111,10 @@ module.exports = extendFlat({ editType: 'plot', description: 'Sets the vertical gap (in pixels) between bricks.' }, - zhoverformat: { - valType: 'string', - dflt: '', - editType: 'none', - description: [ - 'Sets the hover text formatting rule using d3 formatting mini-languages', - 'which are very similar to those in Python. See:', - FORMAT_LINK - ].join(' ') - }, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z', 1), + hovertemplate: hovertemplateAttrs(), showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}) }, { diff --git a/src/traces/heatmap/defaults.js b/src/traces/heatmap/defaults.js index 6b18dc0c7dd..a9fb34d3aa7 100644 --- a/src/traces/heatmap/defaults.js +++ b/src/traces/heatmap/defaults.js @@ -21,6 +21,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('text'); coerce('hovertext'); diff --git a/src/traces/histogram/attributes.js b/src/traces/histogram/attributes.js index 753aad4a69a..763ff0241a0 100644 --- a/src/traces/histogram/attributes.js +++ b/src/traces/histogram/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var barAttrs = require('../bar/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var makeBinAttrs = require('./bin_attributes'); var constants = require('./constants'); @@ -22,6 +23,9 @@ module.exports = { ].join(' ') }, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + text: extendFlat({}, barAttrs.text, { description: [ 'Sets hover text elements associated with each bar.', diff --git a/src/traces/histogram/defaults.js b/src/traces/histogram/defaults.js index 73ad3a78f3a..c71c7927f95 100644 --- a/src/traces/histogram/defaults.js +++ b/src/traces/histogram/defaults.js @@ -24,6 +24,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); var orientation = coerce('orientation', (y && !x) ? 'h' : 'v'); var sampleLetter = orientation === 'v' ? 'x' : 'y'; diff --git a/src/traces/histogram/hover.js b/src/traces/histogram/hover.js index 3e77b33da22..317c632e984 100644 --- a/src/traces/histogram/hover.js +++ b/src/traces/histogram/hover.js @@ -15,7 +15,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { if(!trace.cumulative.enabled) { var posLetter = trace.orientation === 'h' ? 'y' : 'x'; - pointData[posLetter + 'Label'] = hoverLabelText(pointData[posLetter + 'a'], di.ph0, di.ph1); + pointData[posLetter + 'Label'] = hoverLabelText(pointData[posLetter + 'a'], [di.ph0, di.ph1], trace[posLetter + 'hoverformat']); } return pts; diff --git a/src/traces/histogram2d/attributes.js b/src/traces/histogram2d/attributes.js index ca5d6a3c02a..8f02b906261 100644 --- a/src/traces/histogram2d/attributes.js +++ b/src/traces/histogram2d/attributes.js @@ -4,6 +4,7 @@ var histogramAttrs = require('../histogram/attributes'); var makeBinAttrs = require('../histogram/bin_attributes'); var heatmapAttrs = require('../heatmap/attributes'); var baseAttrs = require('../../plots/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var colorScaleAttrs = require('../../components/colorscale/attributes'); @@ -64,7 +65,9 @@ module.exports = extendFlat( xgap: heatmapAttrs.xgap, ygap: heatmapAttrs.ygap, zsmooth: heatmapAttrs.zsmooth, - zhoverformat: heatmapAttrs.zhoverformat, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z', 1), hovertemplate: hovertemplateAttrs({}, {keys: 'z'}), showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}) }, diff --git a/src/traces/histogram2d/defaults.js b/src/traces/histogram2d/defaults.js index 8162274a2ef..4b942bbea0c 100644 --- a/src/traces/histogram2d/defaults.js +++ b/src/traces/histogram2d/defaults.js @@ -19,4 +19,6 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleStyleDefaults(traceIn, traceOut, coerce, layout); colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'z'}); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); }; diff --git a/src/traces/histogram2d/hover.js b/src/traces/histogram2d/hover.js index 879b44cdc13..f645e5427d0 100644 --- a/src/traces/histogram2d/hover.js +++ b/src/traces/histogram2d/hover.js @@ -13,11 +13,12 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay var ny = indices[0]; var nx = indices[1]; var cd0 = pointData.cd[0]; + var trace = cd0.trace; var xRange = cd0.xRanges[nx]; var yRange = cd0.yRanges[ny]; - pointData.xLabel = hoverLabelText(pointData.xa, xRange[0], xRange[1]); - pointData.yLabel = hoverLabelText(pointData.ya, yRange[0], yRange[1]); + pointData.xLabel = hoverLabelText(pointData.xa, [xRange[0], xRange[1]], trace.xhoverformat); + pointData.yLabel = hoverLabelText(pointData.ya, [yRange[0], yRange[1]], trace.yhoverformat); return pts; }; diff --git a/src/traces/histogram2dcontour/attributes.js b/src/traces/histogram2dcontour/attributes.js index 57d5cb4a2e7..0f8cca3fb62 100644 --- a/src/traces/histogram2dcontour/attributes.js +++ b/src/traces/histogram2dcontour/attributes.js @@ -3,6 +3,7 @@ var histogram2dAttrs = require('../histogram2d/attributes'); var contourAttrs = require('../contour/attributes'); var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var extendFlat = require('../../lib/extend').extendFlat; @@ -38,7 +39,9 @@ module.exports = extendFlat({ smoothing: contourAttrs.line.smoothing, editType: 'plot' }, - zhoverformat: histogram2dAttrs.zhoverformat, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z', 1), hovertemplate: histogram2dAttrs.hovertemplate }, colorScaleAttrs('', { diff --git a/src/traces/histogram2dcontour/defaults.js b/src/traces/histogram2dcontour/defaults.js index e7b3ea468d3..f60f2aadf70 100644 --- a/src/traces/histogram2dcontour/defaults.js +++ b/src/traces/histogram2dcontour/defaults.js @@ -23,4 +23,6 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleContoursDefaults(traceIn, traceOut, coerce, coerce2); handleStyleDefaults(traceIn, traceOut, coerce, layout); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); }; diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index b98d500890a..7e7499314a6 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var meshAttrs = require('../mesh3d/attributes'); var baseAttrs = require('../../plots/attributes'); @@ -206,6 +207,11 @@ var attrs = module.exports = overrideAll(extendFlat({ description: 'Same as `text`.' }, hovertemplate: hovertemplateAttrs(), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + valuehoverformat: axisHoverFormat('value', 1), + showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}) }, diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index d30037c4e3a..c0553d80897 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -43,7 +43,10 @@ function supplyIsoDefaults(traceIn, traceOut, defaultColor, layout, coerce) { var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults'); handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout); + coerce('valuehoverformat'); ['x', 'y', 'z'].forEach(function(dim) { + coerce(dim + 'hoverformat'); + var capDim = 'caps.' + dim; var showCap = coerce(capDim + '.show'); if(showCap) { diff --git a/src/traces/mesh3d/attributes.js b/src/traces/mesh3d/attributes.js index d9b34d38ca9..b0aebf3b5f9 100644 --- a/src/traces/mesh3d/attributes.js +++ b/src/traces/mesh3d/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var surfaceAttrs = require('../surface/attributes'); var baseAttrs = require('../../plots/attributes'); @@ -89,6 +90,10 @@ module.exports = extendFlat({ }, hovertemplate: hovertemplateAttrs({editType: 'calc'}), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + delaunayaxis: { valType: 'enumerated', values: [ 'x', 'y', 'z' ], diff --git a/src/traces/mesh3d/defaults.js b/src/traces/mesh3d/defaults.js index 66f3dc4b0d9..c3e94d6501f 100644 --- a/src/traces/mesh3d/defaults.js +++ b/src/traces/mesh3d/defaults.js @@ -83,6 +83,9 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); + coerce('zhoverformat'); // disable 1D transforms // x/y/z should match lengths, and i/j/k should match as well, but diff --git a/src/traces/ohlc/attributes.js b/src/traces/ohlc/attributes.js index 6fc019825d0..7ce3c82b348 100644 --- a/src/traces/ohlc/attributes.js +++ b/src/traces/ohlc/attributes.js @@ -2,6 +2,7 @@ var extendFlat = require('../../lib').extendFlat; var scatterAttrs = require('../scatter/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var dash = require('../../components/drawing/attributes').dash; var fxAttrs = require('../../components/fx/attributes'); var delta = require('../../constants/delta.js'); @@ -28,6 +29,8 @@ module.exports = { xperiod: scatterAttrs.xperiod, xperiod0: scatterAttrs.xperiod0, xperiodalignment: scatterAttrs.xperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), x: { valType: 'data_array', diff --git a/src/traces/ohlc/defaults.js b/src/traces/ohlc/defaults.js index ee9178b17b8..9c0dc35086d 100644 --- a/src/traces/ohlc/defaults.js +++ b/src/traces/ohlc/defaults.js @@ -17,6 +17,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } handlePeriodDefaults(traceIn, traceOut, layout, coerce, {x: true}); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('line.width'); coerce('line.dash'); diff --git a/src/traces/ohlc/hover.js b/src/traces/ohlc/hover.js index df8c6492717..e189c828733 100644 --- a/src/traces/ohlc/hover.js +++ b/src/traces/ohlc/hover.js @@ -125,14 +125,14 @@ function hoverSplit(pointData, xval, yval, hovermode) { var pointData2; if(val in usedVals) { pointData2 = usedVals[val]; - pointData2.yLabel += '
' + t.labels[attr] + Axes.hoverLabelText(ya, val); + pointData2.yLabel += '
' + t.labels[attr] + Axes.hoverLabelText(ya, val, trace.yhoverformat); } else { // copy out to a new object for each new y-value to label pointData2 = Lib.extendFlat({}, closestPoint); pointData2.y0 = pointData2.y1 = valPx; pointData2.yLabelVal = val; - pointData2.yLabel = t.labels[attr] + Axes.hoverLabelText(ya, val); + pointData2.yLabel = t.labels[attr] + Axes.hoverLabelText(ya, val, trace.yhoverformat); pointData2.name = ''; @@ -162,7 +162,7 @@ function hoverOnPoints(pointData, xval, yval, hovermode) { var dir = di.dir; function getLabelLine(attr) { - return t.labels[attr] + Axes.hoverLabelText(ya, trace[attr][i]); + return t.labels[attr] + Axes.hoverLabelText(ya, trace[attr][i], trace.yhoverformat); } var hoverinfo = di.hi || trace.hoverinfo; diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index 0bccd03b4f2..7860cdd693a 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -1,5 +1,6 @@ 'use strict'; +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var colorScaleAttrs = require('../../components/colorscale/attributes'); @@ -118,6 +119,8 @@ module.exports = { yperiod0: axisPeriod0('y0'), xperiodalignment: axisPeriodAlignment('x'), yperiodalignment: axisPeriodAlignment('y'), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), stackgroup: { valType: 'string', @@ -248,6 +251,7 @@ module.exports = { hovertemplate: hovertemplateAttrs({}, { keys: constants.eventDataKeys }), + line: { color: { valType: 'color', diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js index 2b18b1c9cbd..0450df06fa9 100644 --- a/src/traces/scatter/defaults.js +++ b/src/traces/scatter/defaults.js @@ -26,6 +26,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout if(!traceOut.visible) return; handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); var stackGroupOpts = handleStackDefaults(traceIn, traceOut, layout, coerce); diff --git a/src/traces/scatter3d/attributes.js b/src/traces/scatter3d/attributes.js index 62567e3ff54..ca9c6c5979d 100644 --- a/src/traces/scatter3d/attributes.js +++ b/src/traces/scatter3d/attributes.js @@ -2,6 +2,7 @@ var scatterAttrs = require('../scatter/attributes'); var colorAttributes = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var baseAttrs = require('../../plots/attributes'); @@ -89,6 +90,10 @@ var attrs = module.exports = overrideAll({ }), hovertemplate: hovertemplateAttrs(), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + mode: extendFlat({}, scatterAttrs.mode, // shouldn't this be on-par with 2D? {dflt: 'lines+markers'}), surfaceaxis: { diff --git a/src/traces/scatter3d/defaults.js b/src/traces/scatter3d/defaults.js index 2cde1d287bc..eb9e130565b 100644 --- a/src/traces/scatter3d/defaults.js +++ b/src/traces/scatter3d/defaults.js @@ -24,6 +24,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); + coerce('zhoverformat'); + coerce('mode'); if(subTypes.hasLines(traceOut)) { diff --git a/src/traces/scattergl/attributes.js b/src/traces/scattergl/attributes.js index ab95dca6118..d69c8b6c349 100644 --- a/src/traces/scattergl/attributes.js +++ b/src/traces/scattergl/attributes.js @@ -2,6 +2,7 @@ var baseAttrs = require('../../plots/attributes'); var scatterAttrs = require('../scatter/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var colorScaleAttrs = require('../../components/colorscale/attributes'); var extendFlat = require('../../lib/extend').extendFlat; @@ -26,6 +27,8 @@ var attrs = module.exports = overrideAll({ yperiod0: scatterAttrs.yperiod0, xperiodalignment: scatterAttrs.xperiodalignment, yperiodalignment: scatterAttrs.yperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), text: scatterAttrs.text, hovertext: scatterAttrs.hovertext, diff --git a/src/traces/scattergl/defaults.js b/src/traces/scattergl/defaults.js index 01436dad735..b4cce07a5d7 100644 --- a/src/traces/scattergl/defaults.js +++ b/src/traces/scattergl/defaults.js @@ -29,6 +29,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines'; diff --git a/src/traces/splom/attributes.js b/src/traces/splom/attributes.js index 08b9904fb3d..a02947883b9 100644 --- a/src/traces/splom/attributes.js +++ b/src/traces/splom/attributes.js @@ -2,6 +2,7 @@ var scatterAttrs = require('../scatter/attributes'); var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var scatterGlAttrs = require('../scattergl/attributes'); var cartesianIdRegex = require('../../plots/cartesian/constants').idRegex; @@ -130,6 +131,9 @@ module.exports = { hovertemplate: hovertemplateAttrs(), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + marker: markerAttrs, xaxes: makeAxesValObject('x'), diff --git a/src/traces/splom/defaults.js b/src/traces/splom/defaults.js index 2785c65b314..8e450badf07 100644 --- a/src/traces/splom/defaults.js +++ b/src/traces/splom/defaults.js @@ -33,6 +33,8 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce); diff --git a/src/traces/streamtube/attributes.js b/src/traces/streamtube/attributes.js index 7bef021ef25..2b7e50f628c 100644 --- a/src/traces/streamtube/attributes.js +++ b/src/traces/streamtube/attributes.js @@ -1,6 +1,7 @@ 'use strict'; var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var mesh3dAttrs = require('../mesh3d/attributes'); var baseAttrs = require('../../plots/attributes'); @@ -129,6 +130,13 @@ var attrs = { 'norm', 'divergence' ] }), + uhoverformat: axisHoverFormat('u', 1), + vhoverformat: axisHoverFormat('v', 1), + whoverformat: axisHoverFormat('w', 1), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + showlegend: extendFlat({}, baseAttrs.showlegend, {dflt: false}) }; diff --git a/src/traces/streamtube/defaults.js b/src/traces/streamtube/defaults.js index 20018a05d2a..9b5135890f9 100644 --- a/src/traces/streamtube/defaults.js +++ b/src/traces/streamtube/defaults.js @@ -47,6 +47,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('uhoverformat'); + coerce('vhoverformat'); + coerce('whoverformat'); + coerce('xhoverformat'); + coerce('yhoverformat'); + coerce('zhoverformat'); // disable 1D transforms (for now) // x/y/z and u/v/w have matching lengths, diff --git a/src/traces/surface/attributes.js b/src/traces/surface/attributes.js index 0bccddc80e6..1efb5e18fe2 100644 --- a/src/traces/surface/attributes.js +++ b/src/traces/surface/attributes.js @@ -2,6 +2,7 @@ var Color = require('../../components/color'); var colorScaleAttrs = require('../../components/colorscale/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var baseAttrs = require('../../plots/attributes'); @@ -145,6 +146,10 @@ var attrs = module.exports = overrideAll(extendFlat({ }, hovertemplate: hovertemplateAttrs(), + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + zhoverformat: axisHoverFormat('z'), + connectgaps: { valType: 'boolean', dflt: false, diff --git a/src/traces/surface/defaults.js b/src/traces/surface/defaults.js index 63a65137711..3330882bf59 100644 --- a/src/traces/surface/defaults.js +++ b/src/traces/surface/defaults.js @@ -72,6 +72,9 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { coerce('text'); coerce('hovertext'); coerce('hovertemplate'); + coerce('xhoverformat'); + coerce('yhoverformat'); + coerce('zhoverformat'); // Coerce remaining properties [ diff --git a/src/traces/violin/attributes.js b/src/traces/violin/attributes.js index 11b8372d13d..a34e5c4dbbc 100644 --- a/src/traces/violin/attributes.js +++ b/src/traces/violin/attributes.js @@ -2,6 +2,7 @@ var boxAttrs = require('../box/attributes'); var extendFlat = require('../../lib/extend').extendFlat; +var axisHoverFormat = require('../../plots/hoverformat_attributes'); module.exports = { y: boxAttrs.y, @@ -9,6 +10,9 @@ module.exports = { x0: boxAttrs.x0, y0: boxAttrs.y0, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), + name: extendFlat({}, boxAttrs.name, { description: [ 'Sets the trace name.', diff --git a/src/traces/violin/hover.js b/src/traces/violin/hover.js index 4f3c56fb69e..c6e2b27535b 100644 --- a/src/traces/violin/hover.js +++ b/src/traces/violin/hover.js @@ -50,7 +50,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay kdePointData[pLetter + '0'] = pOnPath[0]; kdePointData[pLetter + '1'] = pOnPath[1]; kdePointData[vLetter + '0'] = kdePointData[vLetter + '1'] = vValPx; - kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3); + kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal, trace[vLetter + 'hoverformat']) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3); // move the spike to the KDE point kdePointData.spikeDistance = closeBoxData[0].spikeDistance; diff --git a/src/traces/volume/attributes.js b/src/traces/volume/attributes.js index 01da4bf507e..95c72146458 100644 --- a/src/traces/volume/attributes.js +++ b/src/traces/volume/attributes.js @@ -43,6 +43,10 @@ var attrs = module.exports = overrideAll(extendFlat({ caps: isosurfaceAttrs.caps, text: isosurfaceAttrs.text, hovertext: isosurfaceAttrs.hovertext, + xhoverformat: isosurfaceAttrs.xhoverformat, + yhoverformat: isosurfaceAttrs.yhoverformat, + zhoverformat: isosurfaceAttrs.zhoverformat, + valuehoverformat: isosurfaceAttrs.valuehoverformat, hovertemplate: isosurfaceAttrs.hovertemplate }, diff --git a/src/traces/waterfall/attributes.js b/src/traces/waterfall/attributes.js index 83f826c089c..73d7313a7e0 100644 --- a/src/traces/waterfall/attributes.js +++ b/src/traces/waterfall/attributes.js @@ -3,6 +3,7 @@ var barAttrs = require('../bar/attributes'); var lineAttrs = require('../scatter/attributes').line; var baseAttrs = require('../../plots/attributes'); +var axisHoverFormat = require('../../plots/hoverformat_attributes'); var hovertemplateAttrs = require('../../plots/template_attributes').hovertemplateAttrs; var texttemplateAttrs = require('../../plots/template_attributes').texttemplateAttrs; var constants = require('./constants'); @@ -73,6 +74,8 @@ module.exports = { yperiod0: barAttrs.yperiod0, xperiodalignment: barAttrs.xperiodalignment, yperiodalignment: barAttrs.yperiodalignment, + xhoverformat: axisHoverFormat('x'), + yhoverformat: axisHoverFormat('y'), hovertext: barAttrs.hovertext, hovertemplate: hovertemplateAttrs({}, { diff --git a/src/traces/waterfall/defaults.js b/src/traces/waterfall/defaults.js index fb5960773b2..4abbd2ebc29 100644 --- a/src/traces/waterfall/defaults.js +++ b/src/traces/waterfall/defaults.js @@ -32,6 +32,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) { } handlePeriodDefaults(traceIn, traceOut, layout, coerce); + coerce('xhoverformat'); + coerce('yhoverformat'); coerce('measure'); diff --git a/src/traces/waterfall/hover.js b/src/traces/waterfall/hover.js index 53d36934939..95950200cc4 100644 --- a/src/traces/waterfall/hover.js +++ b/src/traces/waterfall/hover.js @@ -18,10 +18,11 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) { var trace = cd[0].trace; var isHorizontal = (trace.orientation === 'h'); + var vLetter = isHorizontal ? 'x' : 'y'; var vAxis = isHorizontal ? pointData.xa : pointData.ya; function formatNumber(a) { - return hoverLabelText(vAxis, a); + return hoverLabelText(vAxis, a, trace[vLetter + 'hoverformat']); } // the closest data point diff --git a/test/jasmine/tests/gl3d_hover_click_test.js b/test/jasmine/tests/gl3d_hover_click_test.js index c1c7e9504ef..374ade0178c 100644 --- a/test/jasmine/tests/gl3d_hover_click_test.js +++ b/test/jasmine/tests/gl3d_hover_click_test.js @@ -1267,3 +1267,162 @@ describe('Test gl3d trace click/hover:', function() { }); }); }); + +describe('hover on traces with (x|y|z|u|v|w)hoverformat and valuehoverformat', function() { + 'use strict'; + + var gd, fig; + + beforeEach(function() { + gd = createGraphDiv(); + + fig = { + layout: { + hovermode: 'closest', + width: 400, + height: 400, + margin: { + t: 0, + b: 0, + l: 0, + r: 0 + } + } + }; + }); + + afterEach(function() { + Plotly.purge(gd); + destroyGraphDiv(); + }); + + function _hover() { + mouseEvent('mouseover', 190, 210); + } + + [ + {type: 'scatter3d', nums: 'x: 0.0\ny: 1.0\nz: 2.0'}, + {type: 'cone', nums: 'x: 0.0\ny: 1.0\nz: 2.0\nu: 0.0030\nv: 0.00400\nw: 0.005000'}, + {type: 'streamtube', nums: 'x: 0.0\ny: 1.0\nz: 2.0\nu: 0.0030\nv: 0.00400\nw: 0.005000'}, + ].forEach(function(t) { + it('@gl ' + t.type + ' trace', function(done) { + fig.data = [{ + showscale: false, + hoverinfo: 'x+y+z+u+v+w', + xhoverformat: '.1f', + yhoverformat: '.1f', + zhoverformat: '.1f', + uhoverformat: '.4f', + vhoverformat: '.5f', + whoverformat: '.6f', + x: [0], + y: [1], + z: [2], + u: [0.003], + v: [0.004], + w: [0.005] + }]; + + fig.data[0].type = t.type; + + Plotly.newPlot(gd, fig) + .then(delay(20)) + .then(_hover) + .then(delay(20)) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: t.nums + }); + }) + .then(done, done.fail); + }); + }); + + it('@gl surface trace', function(done) { + fig.data = [{ + showscale: false, + xhoverformat: '.1f', + yhoverformat: '.2f', + zhoverformat: '.3f', + x: [0, 1], + y: [0, 1], + z: [[1, 0], [0, 1]], + type: 'surface' + }]; + + Plotly.newPlot(gd, fig) + .then(delay(20)) + .then(_hover) + .then(delay(20)) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: 'x: 1.0\ny: 1.00\nz: 1.000' + }); + }) + .then(done, done.fail); + }); + + it('@gl mesh3d trace', function(done) { + fig.data = [{ + showscale: false, + xhoverformat: '.1f', + yhoverformat: '.2f', + zhoverformat: '.3f', + x: [0, 1, 2], + y: [1, 2, 0], + z: [2, 0, 1], + i: [0], + j: [1], + k: [2], + type: 'mesh3d' + }]; + + Plotly.newPlot(gd, fig) + .then(delay(20)) + .then(_hover) + .then(delay(20)) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: 'x: 2.0\ny: 0.00\nz: 1.000' + }); + }) + .then(done, done.fail); + }); + + [ + {type: 'isosurface', nums: 'x: 1.0\ny: 1.00\nz: 1.000\nvalue: 8.0000'}, + {type: 'volume', nums: 'x: 1.0\ny: 1.00\nz: 1.000\nvalue: 8.0000'}, + ].forEach(function(t) { + it('@gl ' + t.type + ' trace', function(done) { + fig.data = [{ + showscale: false, + hoverinfo: 'x+y+z+u+v+w+value', + xhoverformat: '.1f', + yhoverformat: '.2f', + zhoverformat: '.3f', + valuehoverformat: '.4f', + x: [0, 1, 0, 1, 0, 1, 0, 1], + y: [0, 0, 1, 1, 0, 0, 1, 1], + z: [0, 0, 0, 0, 1, 1, 1, 1], + value: [1, 2, 3, 4, 5, 6, 7, 8] + }]; + + fig.data[0].type = t.type; + + Plotly.newPlot(gd, fig) + .then(delay(20)) + .then(_hover) + .then(delay(20)) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: t.nums + }); + }) + .then(done, done.fail); + }); + }); +}); diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 22aee441ae6..559b3744cd1 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -5086,3 +5086,128 @@ describe('hovermode: (x|y)unified', function() { .then(done, done.fail); }); }); + +describe('hover on traces with (x|y)hoverformat', function() { + 'use strict'; + + var gd, fig; + + beforeEach(function() { + gd = createGraphDiv(); + + fig = { + layout: { + hovermode: 'closest', + width: 400, + height: 400, + margin: { + t: 0, + b: 0, + l: 0, + r: 0 + } + } + }; + }); + + afterEach(destroyGraphDiv); + + function _hover(x, y) { + delete gd._hoverdata; + Lib.clearThrottle(); + mouseEvent('mousemove', x, y); + } + + [ + {type: 'scatter', nums: '(02/01/2000, 1.00)'}, + {type: 'scattergl', nums: '(02/01/2000, 1.00)'}, + {type: 'histogram', nums: '(02/01/2000, 1.00)'}, + {type: 'bar', nums: '(02/01/2000, 1.00)'}, + {type: 'box', nums: '(02/01/2000, median: 1.00)'}, + {type: 'ohlc', nums: '02/01/2000\nopen: 4.00\nhigh: 5.00\nlow: 2.00\nclose: 3.00 ▼'}, + {type: 'candlestick', nums: '02/01/2000\nopen: 4.00\nhigh: 5.00\nlow: 2.00\nclose: 3.00 ▼'}, + {type: 'waterfall', nums: '(02/01/2000, 1.00)\n1.00 ▲\nInitial: 0.00'}, + {type: 'funnel', nums: '(02/01/2000, 1.00)\n100% of initial\n100% of previous\n100% of total'}, + ].forEach(function(t) { + it(t.type + ' trace', function(done) { + fig.data = [{ + xhoverformat: '%x', + yhoverformat: '.2f', + x: ['2000-02'], + y: [1], + low: [2], + high: [5], + open: [4], + close: [3] + }]; + + fig.data[0].type = t.type; + + Plotly.newPlot(gd, fig) + .then(function() { _hover(200, 200); }) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: t.nums + }); + }) + .then(done, done.fail); + }); + }); + + [ + {type: 'contour', nums: 'x: 02/01/2000\ny: 1.00\nz: 4.000'}, + {type: 'heatmap', nums: 'x: 02/01/2000\ny: 1.00\nz: 4.000'}, + {type: 'histogram2d', nums: 'x: 02/01/2000\ny: 1.00\nz: 1.000'}, + {type: 'histogram2dcontour', nums: 'x: 01/31/2000\ny: 1.00\nz: 1.000'}, + ].forEach(function(t) { + it(t.type + ' trace', function(done) { + fig.data = [{ + xhoverformat: '%x', + yhoverformat: '.2f', + zhoverformat: '.3f', + x: ['2000-01', '2000-02'], + y: [1, 1], + z: [[1, 2], [3, 4]] + }]; + + fig.data[0].type = t.type; + + Plotly.newPlot(gd, fig) + .then(function() { _hover(200, 200); }) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: t.nums + }); + }) + .then(done, done.fail); + }); + }); + + it('splom trace', function(done) { + fig.data = [{ + xhoverformat: '%x', + yhoverformat: '.2f', + dimensions: [{ + label: 'A', + values: ['2000-01', '2000-02'], + type: 'date' + }, { + label: 'B', + values: [3, 4] + }], + type: 'splom' + }]; + + Plotly.newPlot(gd, fig) + .then(function() { _hover(180, 220); }) + .then(function() { + assertHoverLabelContent({ + name: '', + nums: '(02/01/2000, 4.00)' + }); + }) + .then(done, done.fail); + }); +});