@@ -83,7 +83,6 @@ proto.plot = function(calcData, fullLayout, promises) {
8383
8484proto . createMap = function ( calcData , fullLayout , resolve , reject ) {
8585 var self = this ;
86- var gd = self . gd ;
8786 var opts = fullLayout [ self . id ] ;
8887
8988 // store style id and URL or object
@@ -115,6 +114,10 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
115114
116115 self . rejectOnError ( reject ) ;
117116
117+ if ( ! self . isStatic ) {
118+ self . initFx ( calcData , fullLayout ) ;
119+ }
120+
118121 var promises = [ ] ;
119122
120123 promises . push ( new Promise ( function ( resolve ) {
@@ -127,121 +130,7 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
127130 self . updateData ( calcData ) ;
128131 self . updateLayout ( fullLayout ) ;
129132 self . resolveOnRender ( resolve ) ;
130- } ) ;
131-
132- if ( self . isStatic ) return ;
133-
134- var wheeling = false ;
135-
136- // keep track of pan / zoom in user layout and emit relayout event
137- map . on ( 'moveend' , function ( eventData ) {
138- if ( ! self . map ) return ;
139-
140- // 'moveend' gets triggered by map.setCenter, map.setZoom,
141- // map.setBearing and map.setPitch.
142- //
143- // Here, we make sure that state updates amd 'plotly_relayout'
144- // are triggered only when the 'moveend' originates from a
145- // mouse target (filtering out API calls) to not
146- // duplicate 'plotly_relayout' events.
147-
148- if ( eventData . originalEvent || wheeling ) {
149- var optsNow = gd . _fullLayout [ self . id ] ;
150- Registry . call ( '_storeDirectGUIEdit' , gd . layout , gd . _fullLayout . _preGUI , self . getViewEdits ( optsNow ) ) ;
151-
152- var viewNow = self . getView ( ) ;
153- optsNow . _input . center = optsNow . center = viewNow . center ;
154- optsNow . _input . zoom = optsNow . zoom = viewNow . zoom ;
155- optsNow . _input . bearing = optsNow . bearing = viewNow . bearing ;
156- optsNow . _input . pitch = optsNow . pitch = viewNow . pitch ;
157-
158- gd . emit ( 'plotly_relayout' , self . getViewEdits ( viewNow ) ) ;
159- }
160- wheeling = false ;
161- } ) ;
162-
163- map . on ( 'wheel' , function ( ) {
164- wheeling = true ;
165- } ) ;
166-
167- map . on ( 'mousemove' , function ( evt ) {
168- var bb = self . div . getBoundingClientRect ( ) ;
169-
170- // some hackery to get Fx.hover to work
171- evt . clientX = evt . point . x + bb . left ;
172- evt . clientY = evt . point . y + bb . top ;
173-
174- evt . target . getBoundingClientRect = function ( ) { return bb ; } ;
175-
176- self . xaxis . p2c = function ( ) { return evt . lngLat . lng ; } ;
177- self . yaxis . p2c = function ( ) { return evt . lngLat . lat ; } ;
178-
179- Fx . hover ( gd , evt , self . id ) ;
180- } ) ;
181-
182- function unhover ( ) {
183- Fx . loneUnhover ( fullLayout . _toppaper ) ;
184- }
185-
186- map . on ( 'dragstart' , unhover ) ;
187- map . on ( 'zoomstart' , unhover ) ;
188-
189- function emitUpdate ( ) {
190- var viewNow = self . getView ( ) ;
191- gd . emit ( 'plotly_relayouting' , self . getViewEdits ( viewNow ) ) ;
192- }
193-
194- map . on ( 'drag' , emitUpdate ) ;
195- map . on ( 'zoom' , emitUpdate ) ;
196-
197- map . on ( 'dblclick' , function ( ) {
198- var optsNow = gd . _fullLayout [ self . id ] ;
199- Registry . call ( '_storeDirectGUIEdit' , gd . layout , gd . _fullLayout . _preGUI , self . getViewEdits ( optsNow ) ) ;
200-
201- var viewInitial = self . viewInitial ;
202- map . setCenter ( convertCenter ( viewInitial . center ) ) ;
203- map . setZoom ( viewInitial . zoom ) ;
204- map . setBearing ( viewInitial . bearing ) ;
205- map . setPitch ( viewInitial . pitch ) ;
206-
207- var viewNow = self . getView ( ) ;
208- optsNow . _input . center = optsNow . center = viewNow . center ;
209- optsNow . _input . zoom = optsNow . zoom = viewNow . zoom ;
210- optsNow . _input . bearing = optsNow . bearing = viewNow . bearing ;
211- optsNow . _input . pitch = optsNow . pitch = viewNow . pitch ;
212-
213- gd . emit ( 'plotly_doubleclick' , null ) ;
214- gd . emit ( 'plotly_relayout' , self . getViewEdits ( viewNow ) ) ;
215- } ) ;
216-
217- // define event handlers on map creation, to keep one ref per map,
218- // so that map.on / map.off in updateFx works as expected
219- self . clearSelect = function ( ) {
220- gd . _fullLayout . _zoomlayer . selectAll ( '.select-outline' ) . remove ( ) ;
221- } ;
222-
223- /**
224- * Returns a click handler function that is supposed
225- * to handle clicks in pan mode.
226- */
227- self . onClickInPanFn = function ( dragOptions ) {
228- return function ( evt ) {
229- var clickMode = gd . _fullLayout . clickmode ;
230-
231- if ( clickMode . indexOf ( 'select' ) > - 1 ) {
232- selectOnClick ( evt . originalEvent , gd , [ self . xaxis ] , [ self . yaxis ] , self . id , dragOptions ) ;
233- }
234-
235- if ( clickMode . indexOf ( 'event' ) > - 1 ) {
236- // TODO: this does not support right-click. If we want to support it, we
237- // would likely need to change mapbox to use dragElement instead of straight
238- // mapbox event binding. Or perhaps better, make a simple wrapper with the
239- // right mousedown, mousemove, and mouseup handlers just for a left/right click
240- // pie would use this too.
241- Fx . click ( gd , evt . originalEvent ) ;
242- }
243- } ;
244- } ;
133+ } ) . catch ( reject ) ;
245134} ;
246135
247136proto . fetchMapData = function ( calcData ) {
@@ -251,6 +140,7 @@ proto.fetchMapData = function(calcData) {
251140 return new Promise ( function ( resolve , reject ) {
252141 d3 . json ( url , function ( err , d ) {
253142 if ( err ) {
143+ delete PlotlyGeoAssets [ url ] ;
254144 var msg = err . status === 404 ?
255145 ( 'GeoJSON at URL ' + url + ' does not exist.' ) :
256146 ( 'Unexpected error while fetching from ' + url ) ;
@@ -305,7 +195,7 @@ proto.updateMap = function(calcData, fullLayout, resolve, reject) {
305195 self . updateData ( calcData ) ;
306196 self . updateLayout ( fullLayout ) ;
307197 self . resolveOnRender ( resolve ) ;
308- } ) ;
198+ } ) . catch ( reject ) ;
309199} ;
310200
311201var traceType2orderIndex = {
@@ -431,6 +321,141 @@ proto.createFramework = function(fullLayout) {
431321 Axes . setConvert ( self . mockAxis , fullLayout ) ;
432322} ;
433323
324+ proto . initFx = function ( calcData , fullLayout ) {
325+ var self = this ;
326+ var gd = self . gd ;
327+ var map = self . map ;
328+
329+ var wheeling = false ;
330+
331+ // keep track of pan / zoom in user layout and emit relayout event
332+ map . on ( 'moveend' , function ( evt ) {
333+ if ( ! self . map ) return ;
334+
335+ var fullLayoutNow = gd . _fullLayout ;
336+
337+ // 'moveend' gets triggered by map.setCenter, map.setZoom,
338+ // map.setBearing and map.setPitch.
339+ //
340+ // Here, we make sure that state updates amd 'plotly_relayout'
341+ // are triggered only when the 'moveend' originates from a
342+ // mouse target (filtering out API calls) to not
343+ // duplicate 'plotly_relayout' events.
344+
345+ if ( evt . originalEvent || wheeling ) {
346+ var optsNow = fullLayoutNow [ self . id ] ;
347+ Registry . call ( '_storeDirectGUIEdit' , gd . layout , fullLayoutNow . _preGUI , self . getViewEdits ( optsNow ) ) ;
348+
349+ var viewNow = self . getView ( ) ;
350+ optsNow . _input . center = optsNow . center = viewNow . center ;
351+ optsNow . _input . zoom = optsNow . zoom = viewNow . zoom ;
352+ optsNow . _input . bearing = optsNow . bearing = viewNow . bearing ;
353+ optsNow . _input . pitch = optsNow . pitch = viewNow . pitch ;
354+
355+ gd . emit ( 'plotly_relayout' , self . getViewEdits ( viewNow ) ) ;
356+ }
357+ wheeling = false ;
358+
359+ if ( fullLayoutNow . _rehover ) {
360+ fullLayoutNow . _rehover ( ) ;
361+ }
362+ } ) ;
363+
364+ map . on ( 'wheel' , function ( ) {
365+ wheeling = true ;
366+ } ) ;
367+
368+ map . on ( 'mousemove' , function ( evt ) {
369+ var bb = self . div . getBoundingClientRect ( ) ;
370+
371+ // some hackery to get Fx.hover to work
372+ evt . clientX = evt . point . x + bb . left ;
373+ evt . clientY = evt . point . y + bb . top ;
374+
375+ evt . target . getBoundingClientRect = function ( ) { return bb ; } ;
376+
377+ self . xaxis . p2c = function ( ) { return evt . lngLat . lng ; } ;
378+ self . yaxis . p2c = function ( ) { return evt . lngLat . lat ; } ;
379+
380+ gd . _fullLayout . _rehover = function ( ) {
381+ if ( gd . _fullLayout . _hoversubplot === self . id ) {
382+ Fx . hover ( gd , evt , self . id ) ;
383+ }
384+ } ;
385+
386+ Fx . hover ( gd , evt , self . id ) ;
387+ gd . _fullLayout . _hoversubplot = self . id ;
388+ } ) ;
389+
390+ function unhover ( ) {
391+ Fx . loneUnhover ( fullLayout . _hoverlayer ) ;
392+ }
393+
394+ map . on ( 'dragstart' , unhover ) ;
395+ map . on ( 'zoomstart' , unhover ) ;
396+
397+ map . on ( 'mouseout' , function ( ) {
398+ gd . _fullLayout . _hoversubplot = null ;
399+ } ) ;
400+
401+ function emitUpdate ( ) {
402+ var viewNow = self . getView ( ) ;
403+ gd . emit ( 'plotly_relayouting' , self . getViewEdits ( viewNow ) ) ;
404+ }
405+
406+ map . on ( 'drag' , emitUpdate ) ;
407+ map . on ( 'zoom' , emitUpdate ) ;
408+
409+ map . on ( 'dblclick' , function ( ) {
410+ var optsNow = gd . _fullLayout [ self . id ] ;
411+ Registry . call ( '_storeDirectGUIEdit' , gd . layout , gd . _fullLayout . _preGUI , self . getViewEdits ( optsNow ) ) ;
412+
413+ var viewInitial = self . viewInitial ;
414+ map . setCenter ( convertCenter ( viewInitial . center ) ) ;
415+ map . setZoom ( viewInitial . zoom ) ;
416+ map . setBearing ( viewInitial . bearing ) ;
417+ map . setPitch ( viewInitial . pitch ) ;
418+
419+ var viewNow = self . getView ( ) ;
420+ optsNow . _input . center = optsNow . center = viewNow . center ;
421+ optsNow . _input . zoom = optsNow . zoom = viewNow . zoom ;
422+ optsNow . _input . bearing = optsNow . bearing = viewNow . bearing ;
423+ optsNow . _input . pitch = optsNow . pitch = viewNow . pitch ;
424+
425+ gd . emit ( 'plotly_doubleclick' , null ) ;
426+ gd . emit ( 'plotly_relayout' , self . getViewEdits ( viewNow ) ) ;
427+ } ) ;
428+
429+ // define event handlers on map creation, to keep one ref per map,
430+ // so that map.on / map.off in updateFx works as expected
431+ self . clearSelect = function ( ) {
432+ gd . _fullLayout . _zoomlayer . selectAll ( '.select-outline' ) . remove ( ) ;
433+ } ;
434+
435+ /**
436+ * Returns a click handler function that is supposed
437+ * to handle clicks in pan mode.
438+ */
439+ self . onClickInPanFn = function ( dragOptions ) {
440+ return function ( evt ) {
441+ var clickMode = gd . _fullLayout . clickmode ;
442+
443+ if ( clickMode . indexOf ( 'select' ) > - 1 ) {
444+ selectOnClick ( evt . originalEvent , gd , [ self . xaxis ] , [ self . yaxis ] , self . id , dragOptions ) ;
445+ }
446+
447+ if ( clickMode . indexOf ( 'event' ) > - 1 ) {
448+ // TODO: this does not support right-click. If we want to support it, we
449+ // would likely need to change mapbox to use dragElement instead of straight
450+ // mapbox event binding. Or perhaps better, make a simple wrapper with the
451+ // right mousedown, mousemove, and mouseup handlers just for a left/right click
452+ // pie would use this too.
453+ Fx . click ( gd , evt . originalEvent ) ;
454+ }
455+ } ;
456+ } ;
457+ } ;
458+
434459proto . updateFx = function ( fullLayout ) {
435460 var self = this ;
436461 var map = self . map ;
0 commit comments