diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 3b5e15e0ced..1b365338205 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -934,10 +934,24 @@ function createHoverText(hoverData, opts, gd) { } } + var xLetter = 'x'; + var yLetter = 'y'; + var zLetter = 'z'; + + if(gd._fullLayout.scene) { + xLetter = gd._fullLayout.scene.xaxis.hovertitle || xLetter; + yLetter = gd._fullLayout.scene.yaxis.hovertitle || yLetter; + zLetter = gd._fullLayout.scene.zaxis.hovertitle || zLetter; + } + else if(!gd._fullLayout.ternary && !gd._fullLayout.title) { + xLetter = gd._fullLayout.xaxis.hovertitle || xLetter; + yLetter = gd._fullLayout.yaxis.hovertitle || yLetter; + } + if(d.zLabel !== undefined) { - if(d.xLabel !== undefined) text += 'x: ' + d.xLabel + '
'; - if(d.yLabel !== undefined) text += 'y: ' + d.yLabel + '
'; - text += (text ? 'z: ' : '') + d.zLabel; + if(d.xLabel !== undefined) text += xLetter + ': ' + d.xLabel + '
'; + if(d.yLabel !== undefined) text += yLetter + ': ' + d.yLabel + '
'; + text += (text ? zLetter + ': ' : '') + d.zLabel; } else if(showCommonLabel && d[hovermode + 'Label'] === t0) { text = d[(hovermode === 'x' ? 'y' : 'x') + 'Label'] || ''; diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 2269152de39..aceec3c2064 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -56,7 +56,10 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, handleCategoryOrderDefaults(containerIn, containerOut, coerce, options); - if(axType !== 'category' && !options.noHover) coerce('hoverformat'); + if(axType !== 'category' && !options.noHover) { + coerce('hoverformat'); + coerce('hovertitle', options.dfltHoverTitle); + } if(!visible) return containerOut; diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index ae48118491e..92fc412d793 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -593,6 +593,14 @@ module.exports = { '*%H~%M~%S.%2f* would display *09~15~23.46*' ].join(' ') }, + hovertitle: { + valType: 'string', + role: 'info', + editType: 'none', + description: [ + 'Sets axis title(s) to be displayed in the hovering popup' + ].join(' ') + }, // lines and grids showline: { valType: 'boolean', diff --git a/src/plots/cartesian/layout_defaults.js b/src/plots/cartesian/layout_defaults.js index 2a59a1bb428..4cbe3403a58 100644 --- a/src/plots/cartesian/layout_defaults.js +++ b/src/plots/cartesian/layout_defaults.js @@ -167,6 +167,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { var defaultOptions = { letter: axLetter, + dfltHoverTitle: axLetter, font: layoutOut.font, outerTicks: outerTicks[axName], showGrid: !noGrids[axName], diff --git a/src/plots/gl3d/layout/axis_attributes.js b/src/plots/gl3d/layout/axis_attributes.js index 7264cf521fb..f1810fd9976 100644 --- a/src/plots/gl3d/layout/axis_attributes.js +++ b/src/plots/gl3d/layout/axis_attributes.js @@ -103,6 +103,7 @@ module.exports = overrideAll({ tickformat: axesAttrs.tickformat, tickformatstops: axesAttrs.tickformatstops, hoverformat: axesAttrs.hoverformat, + hovertitle: axesAttrs.hovertitle, // lines and grids showline: axesAttrs.showline, linecolor: axesAttrs.linecolor, diff --git a/src/plots/polar/layout_attributes.js b/src/plots/polar/layout_attributes.js index f6905453dd9..92d4ce80cd7 100644 --- a/src/plots/polar/layout_attributes.js +++ b/src/plots/polar/layout_attributes.js @@ -118,6 +118,7 @@ var radialAxisAttrs = { // might need a 'titleside' and even 'titledirection' down the road hoverformat: axesAttrs.hoverformat, + hovertitle: axesAttrs.hovertitle, uirevision: { valType: 'any', @@ -234,6 +235,7 @@ var angularAxisAttrs = { }, hoverformat: axesAttrs.hoverformat, + hovertitle: axesAttrs.hovertitle, uirevision: { valType: 'any', diff --git a/src/plots/ternary/layout_attributes.js b/src/plots/ternary/layout_attributes.js index effa824be8d..13948d130cb 100644 --- a/src/plots/ternary/layout_attributes.js +++ b/src/plots/ternary/layout_attributes.js @@ -42,6 +42,7 @@ var ternaryAxesAttrs = { tickformat: axesAttrs.tickformat, tickformatstops: axesAttrs.tickformatstops, hoverformat: axesAttrs.hoverformat, + hovertitle: axesAttrs.hovertitle, // lines and grids showline: extendFlat({}, axesAttrs.showline, {dflt: true}), linecolor: axesAttrs.linecolor, diff --git a/src/plots/ternary/layout_defaults.js b/src/plots/ternary/layout_defaults.js index 7ab47dee7ac..0d77ee715af 100644 --- a/src/plots/ternary/layout_defaults.js +++ b/src/plots/ternary/layout_defaults.js @@ -126,5 +126,6 @@ function handleAxisDefaults(containerIn, containerOut, options, ternaryLayoutOut }); coerce('hoverformat'); + coerce('hovertitle'); coerce('layer'); } diff --git a/test/image/baselines/gl3d_surface_after_heatmap.png b/test/image/baselines/gl3d_surface_after_heatmap.png index e2e84ff714a..06bd02e3df2 100644 Binary files a/test/image/baselines/gl3d_surface_after_heatmap.png and b/test/image/baselines/gl3d_surface_after_heatmap.png differ diff --git a/test/image/mocks/gl3d_surface_after_heatmap.json b/test/image/mocks/gl3d_surface_after_heatmap.json index bd34b7f8c70..da6b4a4cf37 100644 --- a/test/image/mocks/gl3d_surface_after_heatmap.json +++ b/test/image/mocks/gl3d_surface_after_heatmap.json @@ -2,28 +2,72 @@ "data": [ { "type": "heatmap", - "x": [0, 1, 2], - "y": [0, 1, 2], + "zsmooth": "best", + "x": [0, 1, 2, 3, 4], + "y": [0, 1, 2, 3, 4], "z": [ - [0, 1, 0], - [1, 0, 1], - [0, 1, 0] + [0, 1, 0, 1, 0], + [1, 0.25, 0.75, 0.25, 1], + [0, 0.75, 0.25, 0.75, 0], + [1, 0.25, 0.75, 0.25, 1], + [0, 1, 0, 1, 0] ] }, { "type": "surface", - "x": [0, 1, 2], - "y": [0, 1, 2], + "x": [0, 1, 2, 3, 4], + "y": [0, 1, 2, 3, 4], "z": [ - [0, 1, 0], - [1, 0, 1], - [0, 1, 0] + [0, 1, 0, 1, 0], + [1, 0.25, 0.75, 0.25, 1], + [0, 0.75, 0.25, 0.75, 0], + [1, 0.25, 0.75, 0.25, 1], + [0, 1, 0, 1, 0] ] } ], "layout": { "title": "Surface 3d plot on top of 2d heatmap!", "width": 600, - "height": 400 + "height": 400, + "xaxis": { + "hovertitle": "lon", + "title": { + "text": "Longitude" + } + }, + "yaxis": { + "hovertitle": "lat", + "title": { + "text": "Latitude" + } + }, + "scene": { + "xaxis": { + "hovertitle": "lon", + "title": { + "text": "Longitude" + } + }, + "yaxis": { + "hovertitle": "lat", + "title": { + "text": "Latitude" + } + }, + "zaxis": { + "hovertitle": "alt", + "title": { + "text": "Altitude" + } + }, + "camera": { + "eye": { + "x": 2, + "y": 2, + "z": 2 + } + } + } } } diff --git a/test/image/mocks/polar_wind-rose.json b/test/image/mocks/polar_wind-rose.json index fb40daa5592..cf37ab28b66 100644 --- a/test/image/mocks/polar_wind-rose.json +++ b/test/image/mocks/polar_wind-rose.json @@ -31,8 +31,8 @@ "polar": { "barmode": "overlay", "bargap": 0, - "radialaxis": {"ticksuffix": "%", "angle": 45, "dtick": 20}, - "angularaxis": {"direction": "clockwise"} + "radialaxis": {"hovertitle": "likelihood", "ticksuffix": "%", "angle": 45, "dtick": 20}, + "angularaxis": {"hovertitle": "direction", "direction": "clockwise"} } } }