Skip to content

Commit 4549692

Browse files
committed
move pie hover logic into own scope
1 parent 4877a9c commit 4549692

File tree

1 file changed

+132
-129
lines changed

1 file changed

+132
-129
lines changed

src/traces/pie/plot.js

+132-129
Original file line numberDiff line numberDiff line change
@@ -66,139 +66,11 @@ module.exports = function plot(gd, cdpie) {
6666
var sliceTop = d3.select(this);
6767
var slicePath = sliceTop.selectAll('path.surface').data([pt]);
6868

69-
// hover state vars
70-
// have we drawn a hover label, so it should be cleared later
71-
var hasHoverLabel = false;
72-
// have we emitted a hover event, so later an unhover event should be emitted
73-
// note that click events do not depend on this - you can still get them
74-
// with hovermode: false or if you were earlier dragging, then clicked
75-
// in the same slice that you moused up in
76-
var hasHoverEvent = false;
77-
78-
function handleMouseOver() {
79-
// in case fullLayout or fullData has changed without a replot
80-
var fullLayout2 = gd._fullLayout;
81-
var trace2 = gd._fullData[trace.index];
82-
83-
if(gd._dragging || fullLayout2.hovermode === false) return;
84-
85-
var hoverinfo = trace2.hoverinfo;
86-
if(Array.isArray(hoverinfo)) {
87-
// super hacky: we need to pull out the *first* hoverinfo from
88-
// pt.pts, then put it back into an array in a dummy trace
89-
// and call castHoverinfo on that.
90-
// TODO: do we want to have Fx.castHoverinfo somehow handle this?
91-
// it already takes an array for index, for 2D, so this seems tricky.
92-
hoverinfo = Fx.castHoverinfo({
93-
hoverinfo: [helpers.castOption(hoverinfo, pt.pts)],
94-
_module: trace._module
95-
}, fullLayout2, 0);
96-
}
97-
98-
if(hoverinfo === 'all') hoverinfo = 'label+text+value+percent+name';
99-
100-
// in case we dragged over the pie from another subplot,
101-
// or if hover is turned off
102-
if(trace2.hovertemplate || (hoverinfo !== 'none' && hoverinfo !== 'skip' && hoverinfo)) {
103-
var rInscribed = getInscribedRadiusFraction(pt, cd0);
104-
var hoverCenterX = cx + pt.pxmid[0] * (1 - rInscribed);
105-
var hoverCenterY = cy + pt.pxmid[1] * (1 - rInscribed);
106-
var separators = fullLayout.separators;
107-
var thisText = [];
108-
109-
if(hoverinfo && hoverinfo.indexOf('label') !== -1) thisText.push(pt.label);
110-
pt.text = helpers.castOption(trace2.hovertext || trace2.text, pt.pts);
111-
if(hoverinfo && hoverinfo.indexOf('text') !== -1) {
112-
var texti = pt.text;
113-
if(texti) thisText.push(texti);
114-
}
115-
pt.value = pt.v;
116-
pt.valueLabel = helpers.formatPieValue(pt.v, separators);
117-
if(hoverinfo && hoverinfo.indexOf('value') !== -1) thisText.push(pt.valueLabel);
118-
pt.percent = pt.v / cd0.vTotal;
119-
pt.percentLabel = helpers.formatPiePercent(pt.percent, separators);
120-
if(hoverinfo && hoverinfo.indexOf('percent') !== -1) thisText.push(pt.percentLabel);
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: (trace2.hovertemplate || 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-
trace: trace2,
139-
hovertemplate: helpers.castOption(trace2.hovertemplate, pt.pts),
140-
hovertemplateLabels: pt,
141-
eventData: [eventData(pt, trace2)]
142-
}, {
143-
container: fullLayout2._hoverlayer.node(),
144-
outerContainer: fullLayout2._paper.node(),
145-
gd: gd
146-
});
147-
148-
hasHoverLabel = true;
149-
}
150-
151-
gd.emit('plotly_hover', {
152-
points: [eventData(pt, trace2)],
153-
event: d3.event
154-
});
155-
hasHoverEvent = true;
156-
}
157-
158-
function handleMouseOut(evt) {
159-
var fullLayout2 = gd._fullLayout;
160-
var trace2 = gd._fullData[trace.index];
161-
162-
if(hasHoverEvent) {
163-
evt.originalEvent = d3.event;
164-
gd.emit('plotly_unhover', {
165-
points: [eventData(pt, trace2)],
166-
event: d3.event
167-
});
168-
hasHoverEvent = false;
169-
}
170-
171-
if(hasHoverLabel) {
172-
Fx.loneUnhover(fullLayout2._hoverlayer.node());
173-
hasHoverLabel = false;
174-
}
175-
}
176-
177-
function handleClick() {
178-
// TODO: this does not support right-click. If we want to support it, we
179-
// would likely need to change pie to use dragElement instead of straight
180-
// mapbox event binding. Or perhaps better, make a simple wrapper with the
181-
// right mousedown, mousemove, and mouseup handlers just for a left/right click
182-
// mapbox would use this too.
183-
var fullLayout2 = gd._fullLayout;
184-
var trace2 = gd._fullData[trace.index];
185-
186-
if(gd._dragging || fullLayout2.hovermode === false) return;
187-
188-
gd._hoverdata = [eventData(pt, trace2)];
189-
Fx.click(gd, d3.event);
190-
}
191-
19269
slicePath.enter().append('path')
19370
.classed('surface', true)
19471
.style({'pointer-events': 'all'});
19572

196-
sliceTop.select('path.textline').remove();
197-
198-
sliceTop
199-
.on('mouseover', handleMouseOver)
200-
.on('mouseout', handleMouseOut)
201-
.on('click', handleClick);
73+
sliceTop.call(attachFxHandlers, gd, cd);
20274

20375
if(trace.pull) {
20476
var pull = +helpers.castOption(trace.pull, pt.pts) || 0;
@@ -424,6 +296,137 @@ module.exports = function plot(gd, cdpie) {
424296
}, 0);
425297
};
426298

299+
function attachFxHandlers(sliceTop, gd, cd) {
300+
var cd0 = cd[0];
301+
var trace = cd0.trace;
302+
var cx = cd0.cx;
303+
var cy = cd0.cy;
304+
305+
// hover state vars
306+
// have we drawn a hover label, so it should be cleared later
307+
var hasHoverLabel = false;
308+
// have we emitted a hover event, so later an unhover event should be emitted
309+
// note that click events do not depend on this - you can still get them
310+
// with hovermode: false or if you were earlier dragging, then clicked
311+
// in the same slice that you moused up in
312+
var hasHoverEvent = false;
313+
314+
sliceTop.on('mouseover', function(pt) {
315+
// in case fullLayout or fullData has changed without a replot
316+
var fullLayout2 = gd._fullLayout;
317+
var trace2 = gd._fullData[trace.index];
318+
319+
if(gd._dragging || fullLayout2.hovermode === false) return;
320+
321+
var hoverinfo = trace2.hoverinfo;
322+
if(Array.isArray(hoverinfo)) {
323+
// super hacky: we need to pull out the *first* hoverinfo from
324+
// pt.pts, then put it back into an array in a dummy trace
325+
// and call castHoverinfo on that.
326+
// TODO: do we want to have Fx.castHoverinfo somehow handle this?
327+
// it already takes an array for index, for 2D, so this seems tricky.
328+
hoverinfo = Fx.castHoverinfo({
329+
hoverinfo: [helpers.castOption(hoverinfo, pt.pts)],
330+
_module: trace._module
331+
}, fullLayout2, 0);
332+
}
333+
334+
if(hoverinfo === 'all') hoverinfo = 'label+text+value+percent+name';
335+
336+
// in case we dragged over the pie from another subplot,
337+
// or if hover is turned off
338+
if(trace2.hovertemplate || (hoverinfo !== 'none' && hoverinfo !== 'skip' && hoverinfo)) {
339+
var rInscribed = pt.rInscribed;
340+
var hoverCenterX = cx + pt.pxmid[0] * (1 - rInscribed);
341+
var hoverCenterY = cy + pt.pxmid[1] * (1 - rInscribed);
342+
var separators = fullLayout2.separators;
343+
var thisText = [];
344+
345+
if(hoverinfo && hoverinfo.indexOf('label') !== -1) thisText.push(pt.label);
346+
pt.text = helpers.castOption(trace2.hovertext || trace2.text, pt.pts);
347+
if(hoverinfo && hoverinfo.indexOf('text') !== -1) {
348+
var texti = pt.text;
349+
if(texti) thisText.push(texti);
350+
}
351+
pt.value = pt.v;
352+
pt.valueLabel = helpers.formatPieValue(pt.v, separators);
353+
if(hoverinfo && hoverinfo.indexOf('value') !== -1) thisText.push(pt.valueLabel);
354+
pt.percent = pt.v / cd0.vTotal;
355+
pt.percentLabel = helpers.formatPiePercent(pt.percent, separators);
356+
if(hoverinfo && hoverinfo.indexOf('percent') !== -1) thisText.push(pt.percentLabel);
357+
358+
var hoverLabel = trace.hoverlabel;
359+
var hoverFont = hoverLabel.font;
360+
361+
Fx.loneHover({
362+
x0: hoverCenterX - rInscribed * cd0.r,
363+
x1: hoverCenterX + rInscribed * cd0.r,
364+
y: hoverCenterY,
365+
text: thisText.join('<br>'),
366+
name: (trace2.hovertemplate || hoverinfo.indexOf('name') !== -1) ? trace2.name : undefined,
367+
idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right',
368+
color: helpers.castOption(hoverLabel.bgcolor, pt.pts) || pt.color,
369+
borderColor: helpers.castOption(hoverLabel.bordercolor, pt.pts),
370+
fontFamily: helpers.castOption(hoverFont.family, pt.pts),
371+
fontSize: helpers.castOption(hoverFont.size, pt.pts),
372+
fontColor: helpers.castOption(hoverFont.color, pt.pts),
373+
374+
trace: trace2,
375+
hovertemplate: helpers.castOption(trace2.hovertemplate, pt.pts),
376+
hovertemplateLabels: pt,
377+
eventData: [eventData(pt, trace2)]
378+
}, {
379+
container: fullLayout2._hoverlayer.node(),
380+
outerContainer: fullLayout2._paper.node(),
381+
gd: gd
382+
});
383+
384+
hasHoverLabel = true;
385+
}
386+
387+
gd.emit('plotly_hover', {
388+
points: [eventData(pt, trace2)],
389+
event: d3.event
390+
});
391+
hasHoverEvent = true;
392+
});
393+
394+
sliceTop.on('mouseout', function(evt) {
395+
var fullLayout2 = gd._fullLayout;
396+
var trace2 = gd._fullData[trace.index];
397+
var pt = d3.select(this).datum();
398+
399+
if(hasHoverEvent) {
400+
evt.originalEvent = d3.event;
401+
gd.emit('plotly_unhover', {
402+
points: [eventData(pt, trace2)],
403+
event: d3.event
404+
});
405+
hasHoverEvent = false;
406+
}
407+
408+
if(hasHoverLabel) {
409+
Fx.loneUnhover(fullLayout2._hoverlayer.node());
410+
hasHoverLabel = false;
411+
}
412+
});
413+
414+
sliceTop.on('click', function(pt) {
415+
// TODO: this does not support right-click. If we want to support it, we
416+
// would likely need to change pie to use dragElement instead of straight
417+
// mapbox event binding. Or perhaps better, make a simple wrapper with the
418+
// right mousedown, mousemove, and mouseup handlers just for a left/right click
419+
// mapbox would use this too.
420+
var fullLayout2 = gd._fullLayout;
421+
var trace2 = gd._fullData[trace.index];
422+
423+
if(gd._dragging || fullLayout2.hovermode === false) return;
424+
425+
gd._hoverdata = [eventData(pt, trace2)];
426+
Fx.click(gd, d3.event);
427+
});
428+
}
429+
427430
function determineOutsideTextFont(trace, pt, layoutFont) {
428431
var color = helpers.castOption(trace.outsidetextfont.color, pt.pts) ||
429432
helpers.castOption(trace.textfont.color, pt.pts) ||

0 commit comments

Comments
 (0)