Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/7619_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add `hovertemplate` for `candlestick` and `ohlc` traces [[#7619](https://github.com/plotly/plotly.js/pull/7619)]
6 changes: 5 additions & 1 deletion src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -1662,7 +1662,11 @@ function getHoverLabelText(d, showCommonLabel, hovermode, fullLayout, t0, g) {
text = name;
}

// hovertemplate
// Ignore hovertemplate if hoverlabel.split is set
// This ensures correct behavior of hoverlabel.split for candlestick and OHLC traces
// Not very elegant but it works
if (d.trace?.hoverlabel?.split) d.hovertemplate = '';

const { hovertemplate = false } = d;
if (hovertemplate) {
const labels = d.hovertemplateLabels || d;
Expand Down
2 changes: 2 additions & 0 deletions src/traces/candlestick/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ module.exports = {

text: OHLCattrs.text,
hovertext: OHLCattrs.hovertext,
hovertemplate: OHLCattrs.hovertemplate,
hovertemplatefallback: OHLCattrs.hovertemplatefallback,

whiskerwidth: extendFlat({}, boxAttrs.whiskerwidth, { dflt: 0 }),

Expand Down
3 changes: 3 additions & 0 deletions src/traces/candlestick/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout

coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('hovertemplatefallback');

coerce('whiskerwidth');

layout._requestRangeslider[traceOut.xaxis] = true;
Expand Down
18 changes: 14 additions & 4 deletions src/traces/ohlc/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var extendFlat = require('../../lib').extendFlat;
var scatterAttrs = require('../scatter/attributes');
var axisHoverFormat = require('../../plots/cartesian/axis_format_attributes').axisHoverFormat;
const { hovertemplateAttrs, templatefallbackAttrs } = require('../../plots/template_attributes');
var dash = require('../../components/drawing/attributes').dash;
var fxAttrs = require('../../components/fx/attributes');
var delta = require('../../constants/delta.js');
Expand Down Expand Up @@ -34,7 +35,7 @@ module.exports = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the x coordinates.', 'If absent, linear coordinate will be generated.'].join(' ')
description: 'Sets the x coordinates. If absent, linear coordinate will be generated.'
},

open: {
Expand Down Expand Up @@ -105,22 +106,31 @@ module.exports = {
editType: 'calc',
description: 'Same as `text`.'
},

hovertemplate: hovertemplateAttrs(
{},
{
keys: ['open', 'high', 'low', 'close']
}
),
hovertemplatefallback: templatefallbackAttrs(),
tickwidth: {
valType: 'number',
min: 0,
max: 0.5,
dflt: 0.3,
editType: 'calc',
description: ['Sets the width of the open/close tick marks', 'relative to the *x* minimal interval.'].join(' ')
description: 'Sets the width of the open/close tick marks relative to the *x* minimal interval.'
},

hoverlabel: extendFlat({}, fxAttrs.hoverlabel, {
split: {
valType: 'boolean',
dflt: false,
editType: 'style',
description: ['Show hover information (open, close, high, low) in', 'separate labels.'].join(' ')
description: [
'Show hover information (open, close, high, low) in separate labels, rather than a single unified label.',
'Default: *false*. When set to *true*, `hovertemplate` is ignored.'
].join(' ')
}
}),

Expand Down
3 changes: 3 additions & 0 deletions src/traces/ohlc/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout

coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('hovertemplatefallback');

coerce('tickwidth');

layout._requestRangeslider[traceOut.xaxis] = true;
Expand Down
15 changes: 5 additions & 10 deletions src/traces/ohlc/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,11 @@ function hoverSplit(pointData, xval, yval, hovermode) {
// skip the rest (for this trace) if we didn't find a close point
if(!closestPoint) return [];

var cdIndex = closestPoint.index;
var di = cd[cdIndex];
var hoverinfo = di.hi || trace.hoverinfo;
var hoverParts = hoverinfo.split('+');
var isAll = hoverinfo === 'all';
var hasY = isAll || hoverParts.indexOf('y') !== -1;
var di = cd[closestPoint.index];
var hoverinfo = di.hi || trace.hoverinfo || '';

// similar to hoverOnPoints, we return nothing
// if all or y is not present.
if(!hasY) return [];
// If hoverinfo is 'none' or 'skip', we don't show any hover labels
if (hoverinfo === 'none' || hoverinfo === 'skip') return [];

var attrs = ['high', 'open', 'close', 'low'];

Expand Down Expand Up @@ -165,7 +160,7 @@ function hoverOnPoints(pointData, xval, yval, hovermode) {
return t.labels[attr] + Axes.hoverLabelText(ya, trace[attr][i], trace.yhoverformat);
}

var hoverinfo = di.hi || trace.hoverinfo;
var hoverinfo = di.hi || trace.hoverinfo || '';
var hoverParts = hoverinfo.split('+');
var isAll = hoverinfo === 'all';
var hasY = isAll || hoverParts.indexOf('y') !== -1;
Expand Down
64 changes: 64 additions & 0 deletions test/jasmine/tests/finance_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1298,5 +1298,69 @@ describe('finance trace hover via Fx.hover():', function () {
})
.then(done, done.fail);
});

it('should use hovertemplate (when provided) for ' + type, function (done) {
Plotly.newPlot(
gd,
[
{
x: [1, 2, 3],
open: [10, 20, 15],
high: [15, 25, 20],
low: [8, 18, 13],
close: [12, 22, 17],
type: type,
hovertemplate: 'O:%{open} H:%{high}<br>L:%{low} C:%{close}<extra></extra>'
}
],
{
xaxis: { rangeslider: { visible: false } },
width: 500,
height: 500
}
)
.then(function () {
hover(251, 178);
})
.then(function () {
assertHoverLabelContent({
nums: 'O:20 H:25\nL:18 C:22',
name: ''
});
})
.then(done, done.fail);
});
it('should ignore hovertemplate in split mode for ' + type, function (done) {
Plotly.newPlot(
gd,
[
{
x: [1, 2, 3],
open: [10, 20, 15],
high: [15, 25, 20],
low: [8, 18, 13],
close: [12, 22, 17],
type: type,
hovertemplate: 'O:%{open} H:%{high}<br>L:%{low} C:%{close}<extra></extra>',
hoverlabel: { split: true }
}
],
{
xaxis: { rangeslider: { visible: false } },
width: 500,
height: 500
}
)
.then(function () {
hover(251, 178);
})
.then(function () {
assertHoverLabelContent({
nums: ['(2, high: 25)', '(2, close: 22)', '(2, open: 20)', '(2, low: 18)'],
name: ['', '', '', '']
});
})
.then(done, done.fail);
});
});
});
40 changes: 38 additions & 2 deletions test/plot-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -22186,12 +22186,30 @@
"valType": "boolean"
},
"split": {
"description": "Show hover information (open, close, high, low) in separate labels.",
"description": "Show hover information (open, close, high, low) in separate labels, rather than a single unified label. Default: *false*. When set to *true*, `hovertemplate` is ignored.",
"dflt": false,
"editType": "style",
"valType": "boolean"
}
},
"hovertemplate": {
"arrayOk": true,
"description": "Template string used for rendering the information that appear on hover box. Note that this will override `hoverinfo`. Variables are inserted using %{variable}, for example \"y: %{y}\" as well as %{xother}, {%_xother}, {%_xother_}, {%xother_}. When showing info for several points, *xother* will be added to those with different x positions from the first point. An underscore before or after *(x|y)other* will add a space on that side, only when this field is shown. 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. Variables that can't be found will be replaced with the specifier. For example, a template of \"data: %{x}, %{y}\" will result in a value of \"data: 1, %{y}\" if x is 1 and y is missing. Variables with an undefined value will be replaced with the fallback value. The variables available in `hovertemplate` are the ones emitted as event data described at this link https://plotly.com/javascript/plotlyjs-events/#event-data. Additionally, all attributes that can be specified per-point (the ones that are `arrayOk: true`) are available. Finally, the template string has access to variables `open`, `high`, `low` and `close`. Anything contained in tag `<extra>` is displayed in the secondary box, for example `<extra>%{fullData.name}</extra>`. To hide the secondary box completely, use an empty tag `<extra></extra>`.",
"dflt": "",
"editType": "none",
"valType": "string"
},
"hovertemplatefallback": {
"description": "Fallback string that's displayed when a variable referenced in a template is missing. If the boolean value 'false' is passed in, the specifier with the missing variable will be displayed.",
"dflt": "-",
"editType": "none",
"valType": "any"
},
"hovertemplatesrc": {
"description": "Sets the source reference on Chart Studio Cloud for `hovertemplate`.",
"editType": "none",
"valType": "string"
},
"hovertext": {
"arrayOk": true,
"description": "Same as `text`.",
Expand Down Expand Up @@ -52888,12 +52906,30 @@
"valType": "boolean"
},
"split": {
"description": "Show hover information (open, close, high, low) in separate labels.",
"description": "Show hover information (open, close, high, low) in separate labels, rather than a single unified label. Default: *false*. When set to *true*, `hovertemplate` is ignored.",
"dflt": false,
"editType": "style",
"valType": "boolean"
}
},
"hovertemplate": {
"arrayOk": true,
"description": "Template string used for rendering the information that appear on hover box. Note that this will override `hoverinfo`. Variables are inserted using %{variable}, for example \"y: %{y}\" as well as %{xother}, {%_xother}, {%_xother_}, {%xother_}. When showing info for several points, *xother* will be added to those with different x positions from the first point. An underscore before or after *(x|y)other* will add a space on that side, only when this field is shown. 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. Variables that can't be found will be replaced with the specifier. For example, a template of \"data: %{x}, %{y}\" will result in a value of \"data: 1, %{y}\" if x is 1 and y is missing. Variables with an undefined value will be replaced with the fallback value. The variables available in `hovertemplate` are the ones emitted as event data described at this link https://plotly.com/javascript/plotlyjs-events/#event-data. Additionally, all attributes that can be specified per-point (the ones that are `arrayOk: true`) are available. Finally, the template string has access to variables `open`, `high`, `low` and `close`. Anything contained in tag `<extra>` is displayed in the secondary box, for example `<extra>%{fullData.name}</extra>`. To hide the secondary box completely, use an empty tag `<extra></extra>`.",
"dflt": "",
"editType": "none",
"valType": "string"
},
"hovertemplatefallback": {
"description": "Fallback string that's displayed when a variable referenced in a template is missing. If the boolean value 'false' is passed in, the specifier with the missing variable will be displayed.",
"dflt": "-",
"editType": "none",
"valType": "any"
},
"hovertemplatesrc": {
"description": "Sets the source reference on Chart Studio Cloud for `hovertemplate`.",
"editType": "none",
"valType": "string"
},
"hovertext": {
"arrayOk": true,
"description": "Same as `text`.",
Expand Down