@@ -267,7 +267,7 @@ function handleCartesian(gd, ev) {
267
267
modeBarButtons . zoom3d = {
268
268
name : 'zoom3d' ,
269
269
title : 'Zoom' ,
270
- attr : 'dragmode' ,
270
+ attr : 'scene. dragmode' ,
271
271
val : 'zoom' ,
272
272
icon : Icons . zoombox ,
273
273
click : handleDrag3d
@@ -276,7 +276,7 @@ modeBarButtons.zoom3d = {
276
276
modeBarButtons . pan3d = {
277
277
name : 'pan3d' ,
278
278
title : 'Pan' ,
279
- attr : 'dragmode' ,
279
+ attr : 'scene. dragmode' ,
280
280
val : 'pan' ,
281
281
icon : Icons . pan ,
282
282
click : handleDrag3d
@@ -285,7 +285,7 @@ modeBarButtons.pan3d = {
285
285
modeBarButtons . orbitRotation = {
286
286
name : 'orbitRotation' ,
287
287
title : 'orbital rotation' ,
288
- attr : 'dragmode' ,
288
+ attr : 'scene. dragmode' ,
289
289
val : 'orbit' ,
290
290
icon : Icons [ '3d_rotate' ] ,
291
291
click : handleDrag3d
@@ -294,7 +294,7 @@ modeBarButtons.orbitRotation = {
294
294
modeBarButtons . tableRotation = {
295
295
name : 'tableRotation' ,
296
296
title : 'turntable rotation' ,
297
- attr : 'dragmode' ,
297
+ attr : 'scene. dragmode' ,
298
298
val : 'turntable' ,
299
299
icon : Icons [ 'z-axis' ] ,
300
300
click : handleDrag3d
@@ -304,14 +304,16 @@ function handleDrag3d(gd, ev) {
304
304
var button = ev . currentTarget ,
305
305
attr = button . getAttribute ( 'data-attr' ) ,
306
306
val = button . getAttribute ( 'data-val' ) || true ,
307
+ fullLayout = gd . _fullLayout ,
308
+ sceneIds = Plotly . Plots . getSubplotIds ( fullLayout , 'gl3d' ) ,
307
309
layoutUpdate = { } ;
308
310
309
- layoutUpdate [ attr ] = val ;
311
+ var parts = attr . split ( '.' ) ;
312
+
313
+ for ( var i = 0 ; i < sceneIds . length ; i ++ ) {
314
+ layoutUpdate [ sceneIds [ i ] + '.' + parts [ 1 ] ] = val ;
315
+ }
310
316
311
- /*
312
- * Dragmode will go through the relayout -> doplot -> scene.plot()
313
- * routine where the dragmode will be set in scene.plot()
314
- */
315
317
Plotly . relayout ( gd , layoutUpdate ) ;
316
318
}
317
319
@@ -334,29 +336,19 @@ modeBarButtons.resetCameraLastSave3d = {
334
336
function handleCamera3d ( gd , ev ) {
335
337
var button = ev . currentTarget ,
336
338
attr = button . getAttribute ( 'data-attr' ) ,
337
- layout = gd . layout ,
338
339
fullLayout = gd . _fullLayout ,
339
340
sceneIds = Plotly . Plots . getSubplotIds ( fullLayout , 'gl3d' ) ;
340
341
341
342
for ( var i = 0 ; i < sceneIds . length ; i ++ ) {
342
343
var sceneId = sceneIds [ i ] ,
343
- sceneLayout = layout [ sceneId ] ,
344
344
fullSceneLayout = fullLayout [ sceneId ] ,
345
345
scene = fullSceneLayout . _scene ;
346
346
347
- if ( ! sceneLayout || attr === 'resetDefault' ) scene . setCameraToDefault ( ) ;
347
+ if ( attr === 'resetDefault' ) scene . setCameraToDefault ( ) ;
348
348
else if ( attr === 'resetLastSave' ) {
349
-
350
- var cameraPos = sceneLayout . camera ;
351
- if ( cameraPos ) scene . setCamera ( cameraPos ) ;
352
- else scene . setCameraToDefault ( ) ;
349
+ scene . setCamera ( fullSceneLayout . camera ) ;
353
350
}
354
351
}
355
-
356
- /*
357
- * TODO have a sceneLastTouched in _fullLayout to only
358
- * update the camera of the scene last touched by the user
359
- */
360
352
}
361
353
362
354
modeBarButtons . hoverClosest3d = {
@@ -367,50 +359,58 @@ modeBarButtons.hoverClosest3d = {
367
359
toggle : true ,
368
360
icon : Icons . tooltip_basic ,
369
361
gravity : 'ne' ,
370
- click : function ( gd , ev ) {
371
- var button = ev . currentTarget ,
372
- val = JSON . parse ( button . getAttribute ( 'data-val' ) ) || false ,
373
- fullLayout = gd . _fullLayout ,
374
- sceneIds = Plotly . Plots . getSubplotIds ( fullLayout , 'gl3d' ) ;
375
-
376
- var axes = [ 'xaxis' , 'yaxis' , 'zaxis' ] ,
377
- spikeAttrs = [ 'showspikes' , 'spikesides' , 'spikethickness' , 'spikecolor' ] ;
378
-
379
- // initialize 'current spike' object to be stored in the DOM
380
- var currentSpikes = { } ,
381
- axisSpikes = { } ,
382
- layoutUpdate = { } ;
383
-
384
- if ( val ) {
385
- layoutUpdate = val ;
386
- button . setAttribute ( 'data-val' , JSON . stringify ( null ) ) ;
387
- }
388
- else {
389
- layoutUpdate = { 'allaxes.showspikes' : false } ;
390
-
391
- for ( var i = 0 ; i < sceneIds . length ; i ++ ) {
392
- var sceneId = sceneIds [ i ] ,
393
- sceneLayout = fullLayout [ sceneId ] ,
394
- sceneSpikes = currentSpikes [ sceneId ] = { } ;
395
-
396
- // copy all the current spike attrs
397
- for ( var j = 0 ; j < 3 ; j ++ ) {
398
- var axis = axes [ j ] ;
399
- axisSpikes = sceneSpikes [ axis ] = { } ;
400
-
401
- for ( var k = 0 ; k < spikeAttrs . length ; k ++ ) {
402
- var spikeAttr = spikeAttrs [ k ] ;
403
- axisSpikes [ spikeAttr ] = sceneLayout [ axis ] [ spikeAttr ] ;
404
- }
362
+ click : handleHover3d
363
+ } ;
364
+
365
+ function handleHover3d ( gd , ev ) {
366
+ var button = ev . currentTarget ,
367
+ val = button . _previousVal || false ,
368
+ layout = gd . layout ,
369
+ fullLayout = gd . _fullLayout ,
370
+ sceneIds = Plotly . Plots . getSubplotIds ( fullLayout , 'gl3d' ) ;
371
+
372
+ var axes = [ 'xaxis' , 'yaxis' , 'zaxis' ] ,
373
+ spikeAttrs = [ 'showspikes' , 'spikesides' , 'spikethickness' , 'spikecolor' ] ;
374
+
375
+ // initialize 'current spike' object to be stored in the DOM
376
+ var currentSpikes = { } ,
377
+ axisSpikes = { } ,
378
+ layoutUpdate = { } ;
379
+
380
+ if ( val ) {
381
+ layoutUpdate = Lib . extendDeep ( layout , val ) ;
382
+ button . _previousVal = null ;
383
+ }
384
+ else {
385
+ layoutUpdate = {
386
+ 'allaxes.showspikes' : false
387
+ } ;
388
+
389
+ for ( var i = 0 ; i < sceneIds . length ; i ++ ) {
390
+ var sceneId = sceneIds [ i ] ,
391
+ sceneLayout = fullLayout [ sceneId ] ,
392
+ sceneSpikes = currentSpikes [ sceneId ] = { } ;
393
+
394
+ sceneSpikes . hovermode = sceneLayout . hovermode ;
395
+ layoutUpdate [ sceneId + '.hovermode' ] = false ;
396
+
397
+ // copy all the current spike attrs
398
+ for ( var j = 0 ; j < 3 ; j ++ ) {
399
+ var axis = axes [ j ] ;
400
+ axisSpikes = sceneSpikes [ axis ] = { } ;
401
+
402
+ for ( var k = 0 ; k < spikeAttrs . length ; k ++ ) {
403
+ var spikeAttr = spikeAttrs [ k ] ;
404
+ axisSpikes [ spikeAttr ] = sceneLayout [ axis ] [ spikeAttr ] ;
405
405
}
406
406
}
407
-
408
- button . setAttribute ( 'data-val' , JSON . stringify ( currentSpikes ) ) ;
409
407
}
410
408
411
- Plotly . relayout ( gd , layoutUpdate ) ;
409
+ button . _previousVal = Lib . extendDeep ( { } , currentSpikes ) ;
412
410
}
413
- } ;
411
+
412
+ Plotly . relayout ( gd , layoutUpdate ) ;
413
+ }
414
414
415
415
modeBarButtons . zoomInGeo = {
416
416
name : 'zoomInGeo' ,
@@ -447,7 +447,7 @@ modeBarButtons.hoverClosestGeo = {
447
447
toggle : true ,
448
448
icon : Icons . tooltip_basic ,
449
449
gravity : 'ne' ,
450
- click : handleGeo
450
+ click : toggleHover
451
451
} ;
452
452
453
453
function handleGeo ( gd , ev ) {
@@ -468,7 +468,6 @@ function handleGeo(gd, ev) {
468
468
geo . render ( ) ;
469
469
}
470
470
else if ( attr === 'reset' ) geo . zoomReset ( ) ;
471
- else if ( attr === 'hovermode' ) geo . showHover = ! geo . showHover ;
472
471
}
473
472
}
474
473
@@ -494,7 +493,54 @@ modeBarButtons.hoverClosestPie = {
494
493
} ;
495
494
496
495
function toggleHover ( gd ) {
497
- var newHover = gd . _fullLayout . hovermode ? false : 'closest' ;
496
+ var fullLayout = gd . _fullLayout ;
497
+
498
+ var onHoverVal ;
499
+ if ( fullLayout . _hasCartesian ) {
500
+ onHoverVal = fullLayout . _isHoriz ? 'y' : 'x' ;
501
+ }
502
+ else onHoverVal = 'closest' ;
503
+
504
+ var newHover = gd . _fullLayout . hovermode ? false : onHoverVal ;
498
505
499
506
Plotly . relayout ( gd , 'hovermode' , newHover ) ;
500
507
}
508
+
509
+ // buttons when more then one plot types are present
510
+
511
+ modeBarButtons . toggleHover = {
512
+ name : 'toggleHover' ,
513
+ title : 'Toggle show closest data on hover' ,
514
+ attr : 'hovermode' ,
515
+ val : null ,
516
+ toggle : true ,
517
+ icon : Icons . tooltip_basic ,
518
+ gravity : 'ne' ,
519
+ click : function ( gd , ev ) {
520
+ toggleHover ( gd ) ;
521
+
522
+ // the 3d hovermode update must come
523
+ // last so that layout.hovermode update does not
524
+ // override scene?.hovermode?.layout.
525
+ handleHover3d ( gd , ev ) ;
526
+ }
527
+ } ;
528
+
529
+ modeBarButtons . resetViews = {
530
+ name : 'resetViews' ,
531
+ title : 'Reset views' ,
532
+ icon : Icons . home ,
533
+ click : function ( gd , ev ) {
534
+ var button = ev . currentTarget ;
535
+
536
+ button . setAttribute ( 'data-attr' , 'zoom' ) ;
537
+ button . setAttribute ( 'data-val' , 'reset' ) ;
538
+ handleCartesian ( gd , ev ) ;
539
+
540
+ button . setAttribute ( 'data-attr' , 'resetLastSave' ) ;
541
+ handleCamera3d ( gd , ev ) ;
542
+
543
+ // N.B handleCamera3d also triggers a replot for
544
+ // geo subplots.
545
+ }
546
+ } ;
0 commit comments