Skip to content

Commit c936fb3

Browse files
committed
Merge branch 'master' into doeg-cc-form
2 parents c2b05c1 + f2d7066 commit c936fb3

File tree

5 files changed

+324
-22
lines changed

5 files changed

+324
-22
lines changed

shelly/plotlyjs/static/plotlyjs/src/annotations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ annotations.draw = function(gd, index, opt, value) {
603603
.style('opacity', options.opacity)
604604
.on('click', function() {
605605
gd._dragging = false;
606-
$(gd).trigger('plotly_clickannotation', {
606+
gd.emit('plotly_clickannotation', {
607607
index: index,
608608
annotation: optionsIn,
609609
fullAnnotation: options
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
var EventEmitter = require('events').EventEmitter;
4+
5+
var Events = {
6+
7+
init: function(plotObj) {
8+
9+
/*
10+
* If we have already instantiated an emitter for this plot
11+
* return early.
12+
*/
13+
if (plotObj._ev instanceof EventEmitter) return plotObj;
14+
15+
var ev = new EventEmitter();
16+
17+
/*
18+
* Assign to plot._ev while we still live in a land
19+
* where plot is a DOM element with stuff attached to it.
20+
* In the future we can make plot the event emitter itself.
21+
*/
22+
plotObj._ev = ev;
23+
24+
/*
25+
* Assign bound methods from the ev to the plot object. These methods
26+
* will reference the 'this' of plot._ev even though they are methods
27+
* of plot. This will keep the event machinery away from the plot object
28+
* which currently is often a DOM element but presents an API that will
29+
* continue to function when plot becomes an emitter. Not all EventEmitter
30+
* methods have been bound to `plot` as some do not currently add value to
31+
* the Plotly event API.
32+
*/
33+
plotObj.on = ev.on.bind(ev);
34+
plotObj.once = ev.once.bind(ev);
35+
plotObj.removeListener = ev.removeListener.bind(ev);
36+
plotObj.removeAllListeners = ev.removeAllListeners.bind(ev);
37+
38+
/*
39+
* We must wrap emit to continue to support JQuery events. The idea
40+
* is to check to see if the user is using JQuery events, if they are
41+
* we emit JQuery events to trigger user handlers as well as the EventEmitter
42+
* events.
43+
*/
44+
plotObj.emit = function(event, data) {
45+
if (typeof $ !== 'undefined') {
46+
$(plotObj).trigger(event, data);
47+
}
48+
49+
ev.emit(event, data);
50+
};
51+
52+
return plotObj;
53+
},
54+
55+
/*
56+
* This function behaves like jQueries triggerHandler. It calls
57+
* all handlers for a particular event and returns the return value
58+
* of the LAST handler. This function also triggers jQuery's
59+
* triggerHandler for backwards compatibility.
60+
*/
61+
triggerHandler: function(plotObj, event, data) {
62+
var jQueryHandlerValue;
63+
var nodeEventHandlerValue;
64+
/*
65+
* If Jquery exists run all its handlers for this event and
66+
* collect the return value of the LAST handler function
67+
*/
68+
if (typeof $ !== 'undefined') {
69+
jQueryHandlerValue = $(plotObj).triggerHandler(event, data);
70+
}
71+
72+
/*
73+
* Now run all the node style event handlers
74+
*/
75+
var ev = plotObj._ev;
76+
if (!ev) return jQueryHandlerValue;
77+
78+
var handlers = ev._events[event];
79+
if (!handlers) return jQueryHandlerValue;
80+
81+
/*
82+
* handlers can be function or an array of functions
83+
*/
84+
if (typeof handlers === 'function') handlers = [handlers];
85+
var lastHandler = handlers.pop();
86+
87+
/*
88+
* Call all the handlers except the last one.
89+
*/
90+
for (var i = 0; i < handlers.length; i++) {
91+
handlers[i](data);
92+
}
93+
94+
/*
95+
* Now call the final handler and collect its value
96+
*/
97+
nodeEventHandlerValue = lastHandler(data);
98+
99+
/*
100+
* Return either the jquery handler value if it exists or the
101+
* nodeEventHandler value. Jquery event value superceeds nodejs
102+
* events for backwards compatability reasons.
103+
*/
104+
return jQueryHandlerValue !== undefined ? jQueryHandlerValue :
105+
nodeEventHandlerValue;
106+
}
107+
};
108+
109+
module.exports = Events;

shelly/plotlyjs/static/plotlyjs/src/graph_interact.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
var Plotly = require('./plotly'),
66
d3 = require('d3'),
77
tinycolor = require('tinycolor2'),
8-
isNumeric = require('./isnumeric');
8+
isNumeric = require('./isnumeric'),
9+
Events = require('./events');
910

1011
var fx = module.exports = {};
1112

@@ -380,7 +381,7 @@ function hover(gd, evt, subplot){
380381
// fire the beforehover event and quit if it returns false
381382
// note that we're only calling this on real mouse events, so
382383
// manual calls to fx.hover will always run.
383-
if($(gd).triggerHandler('plotly_beforehover',evt)===false) {
384+
if(Events.triggerHandler(gd, 'plotly_beforehover', evt)===false) {
384385
return;
385386
}
386387

@@ -531,7 +532,7 @@ function hover(gd, evt, subplot){
531532

532533
alignHoverText(hoverLabels, rotateLabels);
533534

534-
// lastly, trigger custom hover/unhover events
535+
// lastly, emit custom hover/unhover events
535536
var oldhoverdata = gd._hoverdata,
536537
newhoverdata = [];
537538

@@ -556,13 +557,13 @@ function hover(gd, evt, subplot){
556557

557558
if(!hoverChanged(gd, evt, oldhoverdata)) return;
558559

559-
// trigger the custom hover handler. Bind this like:
560+
// emit the custom hover handler. Bind this like:
560561
// $(gd).on('hover.plotly',
561562
// function(event,extras){ do something with extras.data });
562563
if(oldhoverdata) {
563-
$(gd).trigger('plotly_unhover', {points: oldhoverdata});
564+
gd.emit('plotly_unhover', {points: oldhoverdata});
564565
}
565-
$(gd).trigger('plotly_hover', {
566+
gd.emit('plotly_hover', {
566567
points: gd._hoverdata,
567568
xaxes: xaArray,
568569
yaxes: yaArray,
@@ -1231,7 +1232,7 @@ function alignHoverText(hoverLabels, rotateLabels) {
12311232
}
12321233

12331234
function hoverChanged(gd, evt, oldhoverdata) {
1234-
// don't trigger any events if nothing changed or
1235+
// don't emit any events if nothing changed or
12351236
// if fx.hover was called manually
12361237
if(!evt.target) return false;
12371238
if(!oldhoverdata || oldhoverdata.length!==gd._hoverdata.length) return true;
@@ -1247,25 +1248,25 @@ function hoverChanged(gd, evt, oldhoverdata) {
12471248
return false;
12481249
}
12491250

1250-
// remove hover effects on mouse out, and trigger unhover event
1251+
// remove hover effects on mouse out, and emit unhover event
12511252
function unhover(gd, evt){
12521253
var fullLayout = gd._fullLayout;
12531254
if(!evt) evt = {};
12541255
if(evt.target &&
1255-
$(gd).triggerHandler('plotly_beforehover',evt)===false) {
1256+
Events.triggerHandler(gd, 'plotly_beforehover', evt) === false) {
12561257
return;
12571258
}
12581259
fullLayout._hoverlayer.selectAll('g').remove();
12591260
if(evt.target && gd._hoverdata) {
1260-
$(gd).trigger('plotly_unhover', {points: gd._hoverdata});
1261+
gd.emit('plotly_unhover', {points: gd._hoverdata});
12611262
}
12621263
gd._hoverdata = undefined;
12631264
}
12641265

12651266
// on click
12661267
fx.click = function(gd,evt){
12671268
if(gd._hoverdata && evt && evt.target) {
1268-
$(gd).trigger('plotly_click', {points: gd._hoverdata});
1269+
gd.emit('plotly_click', {points: gd._hoverdata});
12691270
// why do we get a double event without this???
12701271
evt.stopImmediatePropagation();
12711272
}

shelly/plotlyjs/static/plotlyjs/src/graph_obj.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
var Plotly = require('./plotly'),
99
d3 = require('d3'),
1010
m4FromQuat = require('gl-mat4/fromQuat'),
11-
isNumeric = require('./isnumeric');
11+
isNumeric = require('./isnumeric'),
12+
Events = require('./events');
1213

1314
var plots = module.exports = {};
1415
// Most of the generic plotting functions get put into Plotly.Plots,
@@ -387,7 +388,7 @@ function positionPlayWithData(gd, container){
387388

388389
if(gd._context.sendData) {
389390
link.on('click',function(){
390-
$(gd).trigger('plotly_beforeexport');
391+
gd.emit('plotly_beforeexport');
391392

392393
var baseUrl = (window.PLOTLYENV && window.PLOTLYENV.BASE_URL) || 'https://plot.ly';
393394

@@ -402,7 +403,7 @@ function positionPlayWithData(gd, container){
402403
hiddenform.find('form').submit();
403404
hiddenform.remove();
404405

405-
$(gd).trigger('plotly_afterexport');
406+
gd.emit('plotly_afterexport');
406407
return false;
407408
});
408409
}
@@ -431,7 +432,12 @@ Plotly.plot = function(gd, data, layout, config) {
431432

432433
gd = getGraphDiv(gd);
433434

434-
var okToPlot = $(gd).triggerHandler('plotly_beforeplot', [data, layout, config]);
435+
/*
436+
* Events.init is idempotent and bails early if gd has already been init'd
437+
*/
438+
Events.init(gd);
439+
440+
var okToPlot = Events.triggerHandler(gd, 'plotly_beforeplot', [data, layout, config]);
435441
if(okToPlot===false) return;
436442

437443
// if there's no data or layout, and this isn't yet a plotly plot
@@ -727,7 +733,7 @@ Plotly.plot = function(gd, data, layout, config) {
727733
// so mark it as done and let other procedures call a replot
728734
gd._replotting = false;
729735
Plotly.Lib.markTime('done plot');
730-
$(gd).trigger('plotly_afterplot');
736+
gd.emit('plotly_afterplot');
731737
}
732738

733739
var donePlotting = Plotly.Lib.syncOrAsync([
@@ -1255,7 +1261,7 @@ Plotly.redraw = function(gd) {
12551261
}
12561262
gd.calcdata = undefined;
12571263
return Plotly.plot(gd).then(function () {
1258-
$(gd).trigger('plotly_redraw');
1264+
gd.emit('plotly_redraw');
12591265
});
12601266
};
12611267

@@ -3049,7 +3055,7 @@ Plotly.restyle = function restyle(gd, astr, val, traces) {
30493055
if(!plotDone || !plotDone.then) plotDone = Promise.resolve();
30503056

30513057
return plotDone.then(function(){
3052-
$(gd).trigger('plotly_restyle',
3058+
gd.emit('plotly_restyle',
30533059
Plotly.Lib.extendDeep([], [redoit, traces]));
30543060
});
30553061
};
@@ -3410,7 +3416,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
34103416
if(!plotDone || !plotDone.then) plotDone = Promise.resolve();
34113417

34123418
return plotDone.then(function(){
3413-
$(gd).trigger('plotly_relayout',
3419+
gd.emit('plotly_relayout',
34143420
Plotly.Lib.extendDeep({}, redoit));
34153421
});
34163422
};
@@ -3444,7 +3450,7 @@ function plotAutoSize(gd, aobj) {
34443450

34453451
var newHeight, newWidth;
34463452

3447-
$(gd).trigger('plotly_autosize');
3453+
gd.emit('plotly_autosize');
34483454

34493455
// embedded in an iframe - just take the full iframe size
34503456
// if we get to this point, with no aspect ratio restrictions
@@ -3629,7 +3635,7 @@ function makePlotFramework(gd) {
36293635
fullLayout._infolayer = fullLayout._toppaper.append('g').classed('infolayer', true);
36303636
fullLayout._hoverlayer = fullLayout._toppaper.append('g').classed('hoverlayer', true);
36313637

3632-
$(gd).trigger('plotly_framework');
3638+
gd.emit('plotly_framework');
36333639

36343640
// position and style the containers, make main title
36353641
var frameWorkDone = Plotly.Lib.syncOrAsync([

0 commit comments

Comments
 (0)