diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 80fc4a07cf3..2153d70dbb7 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -1211,10 +1211,26 @@ function createHoverText(hoverData, opts) { // mock legend var hoverlabel = fullLayout.hoverlabel; var font = hoverlabel.font; + + var item0 = groupedHoverData[0]; + + var unifiedhovertemplate = ( + hovermode === 'y unified' ? + item0.xa : + item0.ya + ).unifiedhovertemplate; + + var mainText = !unifiedhovertemplate ? t0 : + Lib.hovertemplateString(unifiedhovertemplate, {}, fullLayout._d3locale, + hovermode === 'y unified' ? + {xa: item0.xa, x: item0.xVal} : + {ya: item0.ya, y: item0.yVal} + ); + var mockLayoutIn = { showlegend: true, legend: { - title: {text: t0, font: font}, + title: {text: mainText, font: font}, font: font, bgcolor: hoverlabel.bgcolor, bordercolor: hoverlabel.bordercolor, diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 4531785cd2f..a1c091863e1 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -100,7 +100,10 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, handleCategoryOrderDefaults(containerIn, containerOut, coerce, options); - if(axType !== 'category' && !options.noHover) coerce('hoverformat'); + if(!options.noHover) { + if(axType !== 'category') coerce('hoverformat'); + if(!options.noUnifiedhovertemplate) coerce('unifiedhovertemplate'); + } var dfltColor = coerce('color'); // if axis.color was provided, use it for fonts too; otherwise, diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index f1b7bbbe5d6..fc0e70e2345 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -5,6 +5,7 @@ var colorAttrs = require('../../components/color/attributes'); var dash = require('../../components/drawing/attributes').dash; var extendFlat = require('../../lib/extend').extendFlat; var templatedArray = require('../../plot_api/plot_template').templatedArray; +var templateFormatStringDescription = require('../../plots/template_attributes').templateFormatStringDescription; var descriptionWithDates = require('../../plots/cartesian/axis_format_attributes').descriptionWithDates; var ONEDAY = require('../../constants/numerical').ONEDAY; @@ -975,6 +976,15 @@ module.exports = { editType: 'none', description: descriptionWithDates('hover text') }, + unifiedhovertemplate: { + valType: 'string', + dflt: '', + editType: 'none', + description: [ + 'Template string used for rendering the title that appear on x or y unified hover box.', + templateFormatStringDescription() + ].join(' ') + }, // lines and grids showline: { valType: 'boolean', diff --git a/src/plots/gl3d/layout/axis_defaults.js b/src/plots/gl3d/layout/axis_defaults.js index e3d71be24cb..d8df3f46032 100644 --- a/src/plots/gl3d/layout/axis_defaults.js +++ b/src/plots/gl3d/layout/axis_defaults.js @@ -51,6 +51,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) { noTicklabelposition: true, noTicklabeloverflow: true, noInsiderange: true, + noUnifiedhovertemplate: true, bgColor: options.bgColor, calendar: options.calendar }, diff --git a/src/plots/template_attributes.js b/src/plots/template_attributes.js index 9f01f920688..5d5193c3f30 100644 --- a/src/plots/template_attributes.js +++ b/src/plots/template_attributes.js @@ -22,6 +22,7 @@ function templateFormatStringDescription(opts) { 'for details on the date formatting syntax.' ].join(' '); } +exports.templateFormatStringDescription = templateFormatStringDescription; function shapeTemplateFormatStringDescription() { return [ diff --git a/test/plot-schema.json b/test/plot-schema.json index df08db9d5c3..249bcc278ba 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -14949,6 +14949,12 @@ "editType": "none", "valType": "any" }, + "unifiedhovertemplate": { + "description": "Template string used for rendering the title that appear on x or y unified hover box. Variables are inserted using %{variable}, for example \"y: %{y}\". Numbers are formatted using d3-format's syntax %{variable:d3-format}, for example \"Price: %{y:$.2f}\". https://github.com/d3/d3-format/tree/v1.4.5#d3-format for details on the formatting syntax. Dates are formatted using d3-time-format's syntax %{variable|d3-time-format}, for example \"Day: %{2019-01-01|%A}\". https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format for details on the date formatting syntax.", + "dflt": "", + "editType": "none", + "valType": "string" + }, "visible": { "description": "A single toggle to hide the axis while preserving interaction like dragging. Default is true when a cheater plot is present on the axis, otherwise false", "editType": "plot", @@ -16193,6 +16199,12 @@ "editType": "none", "valType": "any" }, + "unifiedhovertemplate": { + "description": "Template string used for rendering the title that appear on x or y unified hover box. Variables are inserted using %{variable}, for example \"y: %{y}\". Numbers are formatted using d3-format's syntax %{variable:d3-format}, for example \"Price: %{y:$.2f}\". https://github.com/d3/d3-format/tree/v1.4.5#d3-format for details on the formatting syntax. Dates are formatted using d3-time-format's syntax %{variable|d3-time-format}, for example \"Day: %{2019-01-01|%A}\". https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format for details on the date formatting syntax.", + "dflt": "", + "editType": "none", + "valType": "string" + }, "visible": { "description": "A single toggle to hide the axis while preserving interaction like dragging. Default is true when a cheater plot is present on the axis, otherwise false", "editType": "plot",