diff --git a/src/traces/funnel/attributes.js b/src/traces/funnel/attributes.js
index 045ea7bca02..5e5f5f2ed27 100644
--- a/src/traces/funnel/attributes.js
+++ b/src/traces/funnel/attributes.js
@@ -10,6 +10,9 @@
var barAttrs = require('../bar/attributes');
var lineAttrs = require('../scatter/attributes').line;
+var plotAttrs = require('../../plots/attributes');
+var hovertemplateAttrs = require('../../components/fx/hovertemplate_attributes');
+var constants = require('./constants');
var extendFlat = require('../../lib/extend').extendFlat;
var Color = require('../../components/color');
@@ -22,7 +25,13 @@ module.exports = {
dy: barAttrs.dy,
hovertext: barAttrs.hovertext,
- hovertemplate: barAttrs.hovertemplate,
+ hovertemplate: hovertemplateAttrs({}, {
+ keys: constants.eventDataKeys
+ }),
+
+ hoverinfo: extendFlat({}, plotAttrs.hoverinfo, {
+ flags: ['name', 'x', 'y', 'text', 'percent initial', 'percent previous', 'percent total']
+ }),
textinfo: {
valType: 'flaglist',
diff --git a/src/traces/funnel/constants.js b/src/traces/funnel/constants.js
new file mode 100644
index 00000000000..590f59a2b2c
--- /dev/null
+++ b/src/traces/funnel/constants.js
@@ -0,0 +1,17 @@
+/**
+* Copyright 2012-2019, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+module.exports = {
+ eventDataKeys: [
+ 'percentInitial',
+ 'percentPrevious',
+ 'percentTotal'
+ ]
+};
diff --git a/src/traces/funnel/event_data.js b/src/traces/funnel/event_data.js
new file mode 100644
index 00000000000..ae94e3d28a0
--- /dev/null
+++ b/src/traces/funnel/event_data.js
@@ -0,0 +1,25 @@
+/**
+* Copyright 2012-2019, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+module.exports = function eventData(out, pt /* , trace, cd, pointNumber */) {
+ // standard cartesian event data
+ out.x = 'xVal' in pt ? pt.xVal : pt.x;
+ out.y = 'yVal' in pt ? pt.yVal : pt.y;
+
+ // for funnel
+ if('percentInitial' in pt) out.percentInitial = pt.percentInitial;
+ if('percentPrevious' in pt) out.percentPrevious = pt.percentPrevious;
+ if('percentTotal' in pt) out.percentTotal = pt.percentTotal;
+
+ if(pt.xa) out.xaxis = pt.xa;
+ if(pt.ya) out.yaxis = pt.ya;
+
+ return out;
+};
diff --git a/src/traces/funnel/hover.js b/src/traces/funnel/hover.js
index 42935a87412..cbc0f0e7015 100644
--- a/src/traces/funnel/hover.js
+++ b/src/traces/funnel/hover.js
@@ -25,16 +25,36 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var di = cd[index];
var sizeLetter = isHorizontal ? 'x' : 'y';
-
point[sizeLetter + 'LabelVal'] = di.s;
- // display ratio to initial value
- point.extraText = [
- formatPercent(di.begR, 1) + ' of initial',
- formatPercent(di.difR, 1) + ' of previous',
- formatPercent(di.sumR, 1) + ' of total'
- ].join('
');
- // TODO: Should we use pieHelpers.formatPieValue instead ?
+ point.percentInitial = di.begR;
+ point.percentInitialLabel = formatPercent(di.begR, 1);
+
+ point.percentPrevious = di.difR;
+ point.percentPreviousLabel = formatPercent(di.difR, 1);
+
+ point.percentTotal = di.sumR;
+ point.percentTotalLabel = formatPercent(di.sumR, 1);
+
+ var hoverinfo = di.hi || trace.hoverinfo;
+ var text = [];
+ if(hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip') {
+ var isAll = (hoverinfo === 'all');
+ var parts = hoverinfo.split('+');
+
+ var hasFlag = function(flag) { return isAll || parts.indexOf(flag) !== -1; };
+
+ if(hasFlag('percent initial')) {
+ text.push(point.percentInitialLabel + ' of initial');
+ }
+ if(hasFlag('percent previous')) {
+ text.push(point.percentPreviousLabel + ' of previous');
+ }
+ if(hasFlag('percent total')) {
+ text.push(point.percentTotalLabel + ' of total');
+ }
+ }
+ point.extraText = text.join('
');
point.color = getTraceColor(trace, di);
diff --git a/src/traces/funnel/index.js b/src/traces/funnel/index.js
index 844f4097471..d63618e5ec4 100644
--- a/src/traces/funnel/index.js
+++ b/src/traces/funnel/index.js
@@ -19,6 +19,8 @@ module.exports = {
plot: require('./plot'),
style: require('./style').style,
hoverPoints: require('./hover'),
+ eventData: require('./event_data'),
+
selectPoints: require('../bar/select'),
moduleType: 'trace',
diff --git a/test/jasmine/tests/funnel_test.js b/test/jasmine/tests/funnel_test.js
index 1368f46efb6..cb3861833ae 100644
--- a/test/jasmine/tests/funnel_test.js
+++ b/test/jasmine/tests/funnel_test.js
@@ -1326,6 +1326,66 @@ describe('funnel hover', function() {
.then(done);
});
+ it('should turn off percentages with hoveinfo none or skip', function(done) {
+ gd = createGraphDiv();
+
+ var mock = Lib.extendDeep({}, require('@mocks/text_chart_arrays'));
+ mock.data.forEach(function(t, i) {
+ t.type = 'funnel';
+ t.orientation = 'v';
+ if(i === 0) {
+ t.hoverinfo = 'none';
+ } else {
+ t.hoverinfo = 'skip';
+ }
+ });
+
+ function _hover() {
+ var evt = { xpx: 125, ypx: 150 };
+ Fx.hover('graph', evt, 'xy');
+ }
+
+ Plotly.plot(gd, mock)
+ .then(_hover)
+ .then(function() {
+ expect(d3.selectAll('g.hovertext').size()).toBe(0);
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('should turn on percentages with hoveinfo all', function(done) {
+ gd = createGraphDiv();
+
+ var mock = Lib.extendDeep({}, require('@mocks/text_chart_arrays'));
+ mock.data.forEach(function(t) {
+ t.type = 'funnel';
+ t.orientation = 'v';
+ t.hoverinfo = 'all';
+ });
+
+ function _hover() {
+ var evt = { xpx: 125, ypx: 150 };
+ Fx.hover('graph', evt, 'xy');
+ }
+
+ Plotly.plot(gd, mock)
+ .then(_hover)
+ .then(function() {
+ assertHoverLabelContent({
+ nums: [
+ '1\nHover text A\n100% of initial\n100% of previous\n33.3% of total',
+ '2\nHover text G\n100% of initial\n100% of previous\n33.3% of total',
+ '1.5\na (hover)\n100% of initial\n100% of previous\n33.3% of total'
+ ],
+ name: ['Lines, Marke...', 'Lines and Text', 'missing text'],
+ axis: '0'
+ });
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
it('should use hovertemplate if specified', function(done) {
gd = createGraphDiv();
@@ -1333,7 +1393,7 @@ describe('funnel hover', function() {
mock.data.forEach(function(t) {
t.type = 'funnel';
t.orientation = 'v';
- t.hovertemplate = '%{y}';
+ t.hovertemplate = 'Value: %{y}
Total percentage: %{percentTotal}
Initial percentage: %{percentInitial}
Previous percentage: %{percentPrevious}';
});
function _hover() {
@@ -1345,11 +1405,14 @@ describe('funnel hover', function() {
.then(_hover)
.then(function() {
assertHoverLabelContent({
- nums: ['1', '2', '1.5'],
+ nums: [
+ 'Value: 1\nTotal percentage: 33.3%\nInitial percentage: 100%\nPrevious percentage: 100%',
+ 'Value: 2\nTotal percentage: 33.3%\nInitial percentage: 100%\nPrevious percentage: 100%',
+ 'Value: 1.5\nTotal percentage: 33.3%\nInitial percentage: 100%\nPrevious percentage: 100%'
+ ],
name: ['', '', ''],
axis: '0'
});
- // return Plotly.restyle(gd, 'text', ['APPLE', 'BANANA', 'ORANGE']);
})
.catch(failTest)
.then(done);