diff --git a/src/traces/ohlc/hover.js b/src/traces/ohlc/hover.js
index c843fdf5951..3d2e82ea06b 100644
--- a/src/traces/ohlc/hover.js
+++ b/src/traces/ohlc/hover.js
@@ -101,7 +101,9 @@ function hoverSplit(pointData, xval, yval, hovermode) {
// skip the rest (for this trace) if we didn't find a close point
if(!closestPoint) return [];
- var hoverinfo = trace.hoverinfo;
+ 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;
@@ -166,7 +168,7 @@ function hoverOnPoints(pointData, xval, yval, hovermode) {
return t.labels[attr] + Axes.hoverLabelText(ya, trace[attr][i]);
}
- var hoverinfo = trace.hoverinfo;
+ var hoverinfo = di.hi || trace.hoverinfo;
var hoverParts = hoverinfo.split('+');
var isAll = hoverinfo === 'all';
var hasY = isAll || hoverParts.indexOf('y') !== -1;
diff --git a/src/traces/parcats/attributes.js b/src/traces/parcats/attributes.js
index 7035c8ea45a..163f0599657 100644
--- a/src/traces/parcats/attributes.js
+++ b/src/traces/parcats/attributes.js
@@ -41,7 +41,8 @@ module.exports = {
domain: domainAttrs({name: 'parcats', trace: true, editType: 'calc'}),
hoverinfo: extendFlat({}, plotAttrs.hoverinfo, {
flags: ['count', 'probability'],
- editType: 'plot'
+ editType: 'plot',
+ arrayOk: false
// plotAttrs.hoverinfo description is appropriate
}),
hoveron: {
diff --git a/test/jasmine/tests/finance_test.js b/test/jasmine/tests/finance_test.js
index edb3c45514c..7d721f7b29d 100644
--- a/test/jasmine/tests/finance_test.js
+++ b/test/jasmine/tests/finance_test.js
@@ -1046,5 +1046,112 @@ describe('finance charts *special* handlers:', function() {
.catch(failTest)
.then(done);
});
+});
+
+describe('finance trace hover:', function() {
+ var gd;
+
+ afterEach(destroyGraphDiv);
+
+ function run(specs) {
+ gd = createGraphDiv();
+
+ var data = specs.traces.map(function(t) {
+ return Lib.extendFlat({
+ type: specs.type,
+ open: [1, 2],
+ close: [2, 3],
+ high: [3, 4],
+ low: [0, 5]
+ }, t);
+ });
+
+ var layout = Lib.extendFlat({
+ showlegend: false,
+ width: 400,
+ height: 400,
+ margin: {t: 0, b: 0, l: 0, r: 0, pad: 0}
+ }, specs.layout || {});
+
+ var xval = 'xval' in specs ? specs.xvals : 0;
+ var yval = 'yval' in specs ? specs.yvals : 1;
+ var hovermode = layout.hovermode || 'x';
+
+ return Plotly.plot(gd, data, layout).then(function() {
+ var results = gd.calcdata.map(function(cd) {
+ var trace = cd[0].trace;
+ var pointData = {
+ index: false,
+ distance: 20,
+ cd: cd,
+ trace: trace,
+ xa: gd._fullLayout.xaxis,
+ ya: gd._fullLayout.yaxis,
+ maxHoverDistance: 20
+ };
+ var pts = trace._module.hoverPoints(pointData, xval, yval, hovermode);
+ return pts ? pts[0] : {distance: Infinity};
+ });
+
+ var actual = results[0];
+ var exp = specs.exp;
+
+
+ for(var k in exp) {
+ var msg = '- key ' + k;
+ expect(actual[k]).toBe(exp[k], msg);
+ }
+ });
+ }
+ ['ohlc', 'candlestick'].forEach(function(type) {
+ [{
+ type: type,
+ desc: 'basic',
+ traces: [{}],
+ exp: {
+ extraText: 'open: 1
high: 3
low: 0
close: 2 ▲'
+ }
+ }, {
+ type: type,
+ desc: 'with scalar text',
+ traces: [{text: 'SCALAR'}],
+ exp: {
+ extraText: 'open: 1
high: 3
low: 0
close: 2 ▲
SCALAR'
+ }
+ }, {
+ type: type,
+ desc: 'with array text',
+ traces: [{text: ['A', 'B']}],
+ exp: {
+ extraText: 'open: 1
high: 3
low: 0
close: 2 ▲
A'
+ }
+ }, {
+ type: type,
+ desc: 'just scalar text',
+ traces: [{hoverinfo: 'text', text: 'SCALAR'}],
+ exp: {
+ extraText: 'SCALAR'
+ }
+ }, {
+ type: type,
+ desc: 'just array text',
+ traces: [{hoverinfo: 'text', text: ['A', 'B']}],
+ exp: {
+ extraText: 'A'
+ }
+ }, {
+ type: type,
+ desc: 'just array text with array hoverinfo',
+ traces: [{hoverinfo: ['text', 'text'], text: ['A', 'B']}],
+ exp: {
+ extraText: 'A'
+ }
+ }]
+ .forEach(function(specs) {
+ it('should generate correct hover labels ' + type + ' - ' + specs.desc, function(done) {
+ run(specs).catch(failTest).then(done);
+ });
+ });
+ });
});