Skip to content

Commit 5d0f3e2

Browse files
committed
standardize pie events, and add internal aggregation info
1 parent ebc4d8b commit 5d0f3e2

File tree

5 files changed

+239
-176
lines changed

5 files changed

+239
-176
lines changed

src/components/fx/helpers.js

+46-10
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,58 @@ exports.appendArrayPointValue = function(pointData, trace, pointNumber) {
100100

101101
for(var i = 0; i < arrayAttrs.length; i++) {
102102
var astr = arrayAttrs[i];
103-
var key;
103+
var key = getPointKey(astr);
104104

105-
if(astr === 'ids') key = 'id';
106-
else if(astr === 'locations') key = 'location';
107-
else key = astr;
105+
if(pointData[key] === undefined) {
106+
var val = Lib.nestedProperty(trace, astr).get();
107+
var pointVal = getPointData(val, pointNumber);
108+
109+
if(pointVal !== undefined) pointData[key] = pointVal;
110+
}
111+
}
112+
};
113+
114+
exports.appendArrayPointValues = function(pointData, trace, pointNumbers) {
115+
var arrayAttrs = trace._arrayAttrs;
116+
117+
if(!arrayAttrs) {
118+
return;
119+
}
120+
121+
for(var i = 0; i < arrayAttrs.length; i++) {
122+
var astr = arrayAttrs[i];
123+
var key = getPointKey(astr);
108124

109125
if(pointData[key] === undefined) {
110126
var val = Lib.nestedProperty(trace, astr).get();
127+
var keyVal = new Array(pointNumbers.length);
111128

112-
if(Array.isArray(pointNumber)) {
113-
if(Array.isArray(val) && Array.isArray(val[pointNumber[0]])) {
114-
pointData[key] = val[pointNumber[0]][pointNumber[1]];
115-
}
116-
} else {
117-
pointData[key] = val[pointNumber];
129+
for(var j = 0; j < pointNumbers.length; j++) {
130+
keyVal[j] = getPointData(val, pointNumbers[j]);
118131
}
132+
pointData[key] = keyVal;
119133
}
120134
}
121135
};
136+
137+
var pointKeyMap = {
138+
ids: 'id',
139+
locations: 'location',
140+
labels: 'label',
141+
values: 'value',
142+
'marker.colors': 'color'
143+
};
144+
145+
function getPointKey(astr) {
146+
return pointKeyMap[astr] || astr;
147+
}
148+
149+
function getPointData(val, pointNumber) {
150+
if(Array.isArray(pointNumber)) {
151+
if(Array.isArray(val) && Array.isArray(val[pointNumber[0]])) {
152+
return val[pointNumber[0]][pointNumber[1]];
153+
}
154+
} else {
155+
return val[pointNumber];
156+
}
157+
}

src/components/fx/hover.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ exports.loneHover = function loneHover(hoverItem, opts) {
155155

156156
// The actual implementation is here:
157157
function _hover(gd, evt, subplot, noHoverEvent) {
158-
if((subplot === 'pie' || subplot === 'sankey') && !noHoverEvent) {
158+
if(subplot === 'sankey' && !noHoverEvent) {
159159
gd.emit('plotly_hover', {
160160
event: evt.originalEvent,
161161
points: [evt]

src/traces/pie/event_data.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright 2012-2017, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var appendArrayPointValues = require('../../components/fx/helpers').appendArrayPointValues;
13+
14+
15+
// Note: like other eventData routines, this creates the data for hover/unhover/click events
16+
// but it has a different API and goes through a totally different pathway.
17+
// So to ensure it doesn't get misused, it's not attached to the Pie module.
18+
module.exports = function eventData(pt, trace) {
19+
var out = {
20+
curveNumber: trace.index,
21+
pointNumbers: pt.pts,
22+
data: trace._input,
23+
fullData: trace,
24+
label: pt.label,
25+
color: pt.color,
26+
value: pt.v,
27+
28+
// pt.v (and pt.i below) for backward compatibility
29+
v: pt.v
30+
};
31+
32+
// Only include pointNumber if it's unambiguous
33+
if(pt.pts.length === 1) out.pointNumber = out.i = pt.pts[0];
34+
35+
// Add extra data arrays to the output
36+
// notice that this is the multi-point version ('s' on the end!)
37+
// so added data will be arrays matching the pointNumbers array.
38+
appendArrayPointValues(out, trace, pt.pts);
39+
40+
return out;
41+
};

src/traces/pie/plot.js

+73-54
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var Drawing = require('../../components/drawing');
1616
var svgTextUtils = require('../../lib/svg_text_utils');
1717

1818
var helpers = require('./helpers');
19+
var eventData = require('./event_data');
1920

2021
module.exports = function plot(gd, cdpie) {
2122
var fullLayout = gd._fullLayout;
@@ -69,15 +70,23 @@ module.exports = function plot(gd, cdpie) {
6970
var cy = cd0.cy;
7071
var sliceTop = d3.select(this);
7172
var slicePath = sliceTop.selectAll('path.surface').data([pt]);
72-
var hasHoverData = false;
7373

74-
function handleMouseOver(evt) {
75-
evt.originalEvent = d3.event;
74+
// hover state vars
75+
// have we drawn a hover label, so it should be cleared later
76+
var hasHoverLabel = false;
77+
// have we emitted a hover event, so later an unhover event should be emitted
78+
// note that click events do not depend on this - you can still get them
79+
// with hovermode: false or if you were earlier dragging, then clicked
80+
// in the same slice that you moused up in
81+
var hasHoverEvent = false;
7682

83+
function handleMouseOver() {
7784
// in case fullLayout or fullData has changed without a replot
7885
var fullLayout2 = gd._fullLayout;
7986
var trace2 = gd._fullData[trace.index];
8087

88+
if(gd._dragging || fullLayout2.hovermode === false) return;
89+
8190
var hoverinfo = trace2.hoverinfo;
8291
if(Array.isArray(hoverinfo)) {
8392
// super hacky: we need to pull out the *first* hoverinfo from
@@ -95,68 +104,78 @@ module.exports = function plot(gd, cdpie) {
95104

96105
// in case we dragged over the pie from another subplot,
97106
// or if hover is turned off
98-
if(gd._dragging || fullLayout2.hovermode === false ||
99-
hoverinfo === 'none' || hoverinfo === 'skip' || !hoverinfo) {
100-
Fx.hover(gd, evt, 'pie');
101-
return;
102-
}
103-
104-
var rInscribed = getInscribedRadiusFraction(pt, cd0);
105-
var hoverCenterX = cx + pt.pxmid[0] * (1 - rInscribed);
106-
var hoverCenterY = cy + pt.pxmid[1] * (1 - rInscribed);
107-
var separators = fullLayout.separators;
108-
var thisText = [];
107+
if(hoverinfo !== 'none' && hoverinfo !== 'skip' && hoverinfo) {
108+
var rInscribed = getInscribedRadiusFraction(pt, cd0);
109+
var hoverCenterX = cx + pt.pxmid[0] * (1 - rInscribed);
110+
var hoverCenterY = cy + pt.pxmid[1] * (1 - rInscribed);
111+
var separators = fullLayout.separators;
112+
var thisText = [];
113+
114+
if(hoverinfo.indexOf('label') !== -1) thisText.push(pt.label);
115+
if(hoverinfo.indexOf('text') !== -1) {
116+
var texti = helpers.castOption(trace2.hovertext || trace2.text, pt.pts);
117+
if(texti) thisText.push(texti);
118+
}
119+
if(hoverinfo.indexOf('value') !== -1) thisText.push(helpers.formatPieValue(pt.v, separators));
120+
if(hoverinfo.indexOf('percent') !== -1) thisText.push(helpers.formatPiePercent(pt.v / cd0.vTotal, separators));
121+
122+
var hoverLabel = trace.hoverlabel;
123+
var hoverFont = hoverLabel.font;
124+
125+
Fx.loneHover({
126+
x0: hoverCenterX - rInscribed * cd0.r,
127+
x1: hoverCenterX + rInscribed * cd0.r,
128+
y: hoverCenterY,
129+
text: thisText.join('<br>'),
130+
name: hoverinfo.indexOf('name') !== -1 ? trace2.name : undefined,
131+
idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right',
132+
color: helpers.castOption(hoverLabel.bgcolor, pt.pts) || pt.color,
133+
borderColor: helpers.castOption(hoverLabel.bordercolor, pt.pts),
134+
fontFamily: helpers.castOption(hoverFont.family, pt.pts),
135+
fontSize: helpers.castOption(hoverFont.size, pt.pts),
136+
fontColor: helpers.castOption(hoverFont.color, pt.pts)
137+
}, {
138+
container: fullLayout2._hoverlayer.node(),
139+
outerContainer: fullLayout2._paper.node(),
140+
gd: gd
141+
});
109142

110-
if(hoverinfo.indexOf('label') !== -1) thisText.push(pt.label);
111-
if(hoverinfo.indexOf('text') !== -1) {
112-
var texti = helpers.castOption(trace2.hovertext || trace2.text, pt.pts);
113-
if(texti) thisText.push(texti);
143+
hasHoverLabel = true;
114144
}
115-
if(hoverinfo.indexOf('value') !== -1) thisText.push(helpers.formatPieValue(pt.v, separators));
116-
if(hoverinfo.indexOf('percent') !== -1) thisText.push(helpers.formatPiePercent(pt.v / cd0.vTotal, separators));
117-
118-
var hoverLabel = trace.hoverlabel;
119-
var hoverFont = hoverLabel.font;
120-
121-
Fx.loneHover({
122-
x0: hoverCenterX - rInscribed * cd0.r,
123-
x1: hoverCenterX + rInscribed * cd0.r,
124-
y: hoverCenterY,
125-
text: thisText.join('<br>'),
126-
name: hoverinfo.indexOf('name') !== -1 ? trace2.name : undefined,
127-
idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right',
128-
color: helpers.castOption(hoverLabel.bgcolor, pt.pts) || pt.color,
129-
borderColor: helpers.castOption(hoverLabel.bordercolor, pt.pts),
130-
fontFamily: helpers.castOption(hoverFont.family, pt.pts),
131-
fontSize: helpers.castOption(hoverFont.size, pt.pts),
132-
fontColor: helpers.castOption(hoverFont.color, pt.pts)
133-
}, {
134-
container: fullLayout2._hoverlayer.node(),
135-
outerContainer: fullLayout2._paper.node(),
136-
gd: gd
137-
});
138-
139-
Fx.hover(gd, evt, 'pie');
140145

141-
hasHoverData = true;
146+
gd.emit('plotly_hover', {
147+
points: [eventData(pt, trace2)],
148+
event: d3.event
149+
});
150+
hasHoverEvent = true;
142151
}
143152

144153
function handleMouseOut(evt) {
145-
evt.originalEvent = d3.event;
146-
gd.emit('plotly_unhover', {
147-
event: d3.event,
148-
points: [evt]
149-
});
154+
var fullLayout2 = gd._fullLayout;
155+
var trace2 = gd._fullData[trace.index];
156+
157+
if(hasHoverEvent) {
158+
evt.originalEvent = d3.event;
159+
gd.emit('plotly_unhover', {
160+
points: [eventData(pt, trace2)],
161+
event: d3.event
162+
});
163+
hasHoverEvent = false;
164+
}
150165

151-
if(hasHoverData) {
152-
Fx.loneUnhover(fullLayout._hoverlayer.node());
153-
hasHoverData = false;
166+
if(hasHoverLabel) {
167+
Fx.loneUnhover(fullLayout2._hoverlayer.node());
168+
hasHoverLabel = false;
154169
}
155170
}
156171

157172
function handleClick() {
158-
gd._hoverdata = [pt];
159-
gd._hoverdata.trace = cd0.trace;
173+
var fullLayout2 = gd._fullLayout;
174+
var trace2 = gd._fullData[trace.index];
175+
176+
if(gd._dragging || fullLayout2.hovermode === false) return;
177+
178+
gd._hoverdata = [eventData(pt, trace2)];
160179
Fx.click(gd, d3.event);
161180
}
162181

0 commit comments

Comments
 (0)