99
1010'use strict' ; 
1111
12- var  createCamera  =  require ( 'gl-plot3d' ) . createCamera ; 
13- var  createPlot  =  require ( 'gl-plot3d' ) . createScene ; 
12+ var  glPlot3d  =  require ( 'gl-plot3d' ) ; 
13+ var  createCamera  =  glPlot3d . createCamera ; 
14+ var  createPlot  =  glPlot3d . createScene ; 
15+ 
1416var  getContext  =  require ( 'webgl-context' ) ; 
1517var  passiveSupported  =  require ( 'has-passive-events' ) ; 
1618
@@ -246,10 +248,10 @@ function tryCreatePlot(scene, cameraObject, pixelRatio, canvas, gl) {
246248    return  failed  <  2 ; 
247249} 
248250
249- function  initializeGLPlot ( scene ,  pixelRatio ,   canvas ,  gl )  { 
251+ function  initializeGLPlot ( scene ,  canvas ,  gl )  { 
250252    scene . initializeGLCamera ( ) ; 
251253
252-     var  success  =  tryCreatePlot ( scene ,  scene . camera ,  pixelRatio ,  canvas ,  gl ) ; 
254+     var  success  =  tryCreatePlot ( scene ,  scene . camera ,  scene . pixelRatio ,  canvas ,  gl ) ; 
253255    /* 
254256    * createPlot will throw when webgl is not enabled in the client. 
255257    * Lets return an instance of the module with all functions noop'd. 
@@ -259,22 +261,48 @@ function initializeGLPlot(scene, pixelRatio, canvas, gl) {
259261    if ( ! success )  return  showNoWebGlMsg ( scene ) ; 
260262
261263    var  gd  =  scene . graphDiv ; 
264+     var  layout  =  gd . layout ; 
265+ 
266+     var  makeUpdate  =  function ( )  { 
267+         var  update  =  { } ; 
268+ 
269+         if ( scene . isCameraChanged ( layout ) )  { 
270+             // camera updates 
271+             update [ scene . id  +  '.camera' ]  =  scene . getCamera ( ) ; 
272+         } 
273+ 
274+         if ( scene . isAspectChanged ( layout ) )  { 
275+             // scene updates 
276+             update [ scene . id  +  '.aspectratio' ]  =  scene . glplot . getAspectratio ( ) ; 
277+         } 
278+ 
279+         return  update ; 
280+     } ; 
262281
263282    var  relayoutCallback  =  function ( scene )  { 
264283        if ( scene . fullSceneLayout . dragmode  ===  false )  return ; 
265284
266-         var  update  =  { } ; 
267-         update [ scene . id  +  '.camera' ]  =  getLayoutCamera ( scene . camera ) ; 
268-         scene . saveCamera ( gd . layout ) ; 
285+         var  update  =  makeUpdate ( ) ; 
286+         scene . saveLayout ( layout ) ; 
269287        scene . graphDiv . emit ( 'plotly_relayout' ,  update ) ; 
270288    } ; 
271289
272290    scene . glplot . canvas . addEventListener ( 'mouseup' ,  function ( )  { 
273291        relayoutCallback ( scene ) ; 
274292    } ) ; 
275293
276-     scene . glplot . canvas . addEventListener ( 'wheel' ,  function ( )  { 
294+     scene . glplot . canvas . addEventListener ( 'wheel' ,  function ( e )  { 
277295        if ( gd . _context . _scrollZoom . gl3d )  { 
296+             if ( scene . glplot . camera . _ortho )  { 
297+                 var  s  =  ( e . deltaX  >  e . deltaY )  ? 1.1  : 1.0  /  1.1 ; 
298+                 var  o  =  scene . glplot . getAspectratio ( ) ; 
299+                 scene . glplot . setAspectratio ( { 
300+                     x : s  *  o . x , 
301+                     y : s  *  o . y , 
302+                     z : s  *  o . z 
303+                 } ) ; 
304+             } 
305+ 
278306            relayoutCallback ( scene ) ; 
279307        } 
280308    } ,  passiveSupported  ? { passive : false }  : false ) ; 
@@ -283,8 +311,7 @@ function initializeGLPlot(scene, pixelRatio, canvas, gl) {
283311        if ( scene . fullSceneLayout . dragmode  ===  false )  return ; 
284312        if ( scene . camera . mouseListener . buttons  ===  0 )  return ; 
285313
286-         var  update  =  { } ; 
287-         update [ scene . id  +  '.camera' ]  =  getLayoutCamera ( scene . camera ) ; 
314+         var  update  =  makeUpdate ( ) ; 
288315        scene . graphDiv . emit ( 'plotly_relayouting' ,  update ) ; 
289316    } ) ; 
290317
@@ -366,7 +393,7 @@ function Scene(options, fullLayout) {
366393    this . convertAnnotations  =  Registry . getComponentMethod ( 'annotations3d' ,  'convert' ) ; 
367394    this . drawAnnotations  =  Registry . getComponentMethod ( 'annotations3d' ,  'draw' ) ; 
368395
369-     initializeGLPlot ( this ,   this . pixelRatio ) ; 
396+     initializeGLPlot ( this ) ; 
370397} 
371398
372399var  proto  =  Scene . prototype ; 
@@ -390,16 +417,15 @@ proto.recoverContext = function() {
390417    var  scene  =  this ; 
391418    var  gl  =  this . glplot . gl ; 
392419    var  canvas  =  this . glplot . canvas ; 
393-     var  camera  =  this . glplot . camera ; 
394-     var  pixelRatio  =  this . glplot . pixelRatio ; 
420+ 
395421    this . glplot . dispose ( ) ; 
396422
397423    function  tryRecover ( )  { 
398424        if ( gl . isContextLost ( ) )  { 
399425            requestAnimationFrame ( tryRecover ) ; 
400426            return ; 
401427        } 
402-         if ( ! initializeGLPlot ( scene ,  camera ,   pixelRatio ,   canvas ,  gl ) )  { 
428+         if ( ! initializeGLPlot ( scene ,  canvas ,  gl ) )  { 
403429            Lib . error ( 'Catastrophic and unrecoverable WebGL error. Context lost.' ) ; 
404430            return ; 
405431        } 
@@ -496,7 +522,7 @@ proto.plot = function(sceneData, fullLayout, layout) {
496522    this . spikeOptions . merge ( fullSceneLayout ) ; 
497523
498524    // Update camera and camera mode 
499-     this . setCamera ( fullSceneLayout . camera ) ; 
525+     this . setViewport ( fullSceneLayout ) ; 
500526    this . updateFx ( fullSceneLayout . dragmode ,  fullSceneLayout . hovermode ) ; 
501527    this . camera . enableWheel  =  this . graphDiv . _context . _scrollZoom . gl3d ; 
502528
@@ -720,8 +746,16 @@ proto.plot = function(sceneData, fullLayout, layout) {
720746     * Finally assign the computed aspecratio to the glplot module. This will have an effect 
721747     * on the next render cycle. 
722748     */ 
723-     this . glplot . aspect  =  aspectRatio ; 
724- 
749+     this . glplot . setAspectratio ( fullSceneLayout . aspectratio ) ; 
750+ 
751+     // save 'initial' camera view settings for modebar button 
752+     if ( ! this . viewInitial . aspectratio )  { 
753+         this . viewInitial . aspectratio  =  { 
754+             x : fullSceneLayout . aspectratio . x , 
755+             y : fullSceneLayout . aspectratio . y , 
756+             z : fullSceneLayout . aspectratio . z 
757+         } ; 
758+     } 
725759
726760    // Update frame position for multi plots 
727761    var  domain  =  fullSceneLayout . domain  ||  null ; 
@@ -751,18 +785,18 @@ proto.destroy = function() {
751785    this . glplot  =  null ; 
752786} ; 
753787
754- // getOrbitCamera  :: plotly_coords -> orbit_camera_coords  
788+ // getCameraArrays  :: plotly_coords -> gl-plot3d_coords  
755789// inverse of getLayoutCamera 
756- function  getOrbitCamera ( camera )  { 
790+ function  getCameraArrays ( camera )  { 
757791    return  [ 
758792        [ camera . eye . x ,  camera . eye . y ,  camera . eye . z ] , 
759793        [ camera . center . x ,  camera . center . y ,  camera . center . z ] , 
760794        [ camera . up . x ,  camera . up . y ,  camera . up . z ] 
761795    ] ; 
762796} 
763797
764- // getLayoutCamera :: orbit_camera_coords  -> plotly_coords 
765- // inverse of getOrbitCamera  
798+ // getLayoutCamera :: gl-plot3d_coords  -> plotly_coords 
799+ // inverse of getCameraArrays  
766800function  getLayoutCamera ( camera )  { 
767801    return  { 
768802        up : { x : camera . up [ 0 ] ,  y : camera . up [ 1 ] ,  z : camera . up [ 2 ] } , 
@@ -772,24 +806,25 @@ function getLayoutCamera(camera) {
772806    } ; 
773807} 
774808
775- // get camera position in plotly coords from 'orbit-camera ' coords 
776- proto . getCamera  =  function   getCamera ( )  { 
809+ // get camera position in plotly coords from 'gl-plot3d ' coords 
810+ proto . getCamera  =  function ( )  { 
777811    this . glplot . camera . view . recalcMatrix ( this . camera . view . lastT ( ) ) ; 
778812    return  getLayoutCamera ( this . glplot . camera ) ; 
779813} ; 
780814
781- // set camera position with a set of plotly coords 
782- proto . setCamera  =  function  setCamera ( cameraData )  { 
783-     this . glplot . camera . lookAt . apply ( this ,  getOrbitCamera ( cameraData ) ) ; 
815+ // set gl-plot3d camera position and scene aspects with a set of plotly coords 
816+ proto . setViewport  =  function ( sceneLayout )  { 
817+     var  cameraData  =  sceneLayout . camera ; 
818+ 
819+     this . glplot . camera . lookAt . apply ( this ,  getCameraArrays ( cameraData ) ) ; 
820+     this . glplot . setAspectratio ( sceneLayout . aspectratio ) ; 
784821
785822    var  newOrtho  =  ( cameraData . projection . type  ===  'orthographic' ) ; 
786823    var  oldOrtho  =  this . glplot . camera . _ortho ; 
787824
788825    if ( newOrtho  !==  oldOrtho )  { 
789826        this . glplot . redraw ( ) ; 
790827
791-         var  pixelRatio  =  this . glplot . pixelRatio ; 
792- 
793828        var  RGBA  =  this . glplot . clearColor ; 
794829        this . glplot . gl . clearColor ( 
795830            RGBA [ 0 ] ,  RGBA [ 1 ] ,  RGBA [ 2 ] ,  RGBA [ 3 ] 
@@ -801,32 +836,30 @@ proto.setCamera = function setCamera(cameraData) {
801836
802837        this . glplot . dispose ( ) ; 
803838
804-         initializeGLPlot ( this ,   pixelRatio ) ; 
839+         initializeGLPlot ( this ) ; 
805840        this . glplot . camera . _ortho  =  newOrtho ; 
806841    } 
807842} ; 
808843
809- // save camera to user layout (i.e. gd.layout) 
810- proto . saveCamera  =  function  saveCamera ( layout )  { 
811-     var  fullLayout  =  this . fullLayout ; 
844+ proto . isCameraChanged  =  function ( layout )  { 
812845    var  cameraData  =  this . getCamera ( ) ; 
813846    var  cameraNestedProp  =  Lib . nestedProperty ( layout ,  this . id  +  '.camera' ) ; 
814847    var  cameraDataLastSave  =  cameraNestedProp . get ( ) ; 
815-     var  hasChanged  =  false ; 
816848
817849    function  same ( x ,  y ,  i ,  j )  { 
818850        var  vectors  =  [ 'up' ,  'center' ,  'eye' ] ; 
819851        var  components  =  [ 'x' ,  'y' ,  'z' ] ; 
820852        return  y [ vectors [ i ] ]  &&  ( x [ vectors [ i ] ] [ components [ j ] ]  ===  y [ vectors [ i ] ] [ components [ j ] ] ) ; 
821853    } 
822854
855+     var  changed  =  false ; 
823856    if ( cameraDataLastSave  ===  undefined )  { 
824-         hasChanged  =  true ; 
857+         changed  =  true ; 
825858    }  else  { 
826859        for ( var  i  =  0 ;  i  <  3 ;  i ++ )  { 
827860            for ( var  j  =  0 ;  j  <  3 ;  j ++ )  { 
828861                if ( ! same ( cameraData ,  cameraDataLastSave ,  i ,  j ) )  { 
829-                     hasChanged  =  true ; 
862+                     changed  =  true ; 
830863                    break ; 
831864                } 
832865            } 
@@ -835,19 +868,75 @@ proto.saveCamera = function saveCamera(layout) {
835868        if ( ! cameraDataLastSave . projection  ||  ( 
836869            cameraData . projection  && 
837870            cameraData . projection . type  !==  cameraDataLastSave . projection . type ) )  { 
838-             hasChanged  =  true ; 
871+             changed  =  true ; 
839872        } 
840873    } 
841874
875+     return  changed ; 
876+ } ; 
877+ 
878+ proto . isAspectChanged  =  function ( layout )  { 
879+     var  aspectData  =  this . glplot . getAspectratio ( ) ; 
880+     var  aspectNestedProp  =  Lib . nestedProperty ( layout ,  this . id  +  '.aspectratio' ) ; 
881+     var  aspectDataLastSave  =  aspectNestedProp . get ( ) ; 
882+ 
883+     return  ( 
884+         aspectDataLastSave  ===  undefined  ||  ( 
885+         aspectDataLastSave . x  !==  aspectData . x  || 
886+         aspectDataLastSave . y  !==  aspectData . y  || 
887+         aspectDataLastSave . z  !==  aspectData . z 
888+     ) ) ; 
889+ } ; 
890+ 
891+ // save camera to user layout (i.e. gd.layout) 
892+ proto . saveLayout  =  function ( layout )  { 
893+     var  fullLayout  =  this . fullLayout ; 
894+ 
895+     var  cameraData ; 
896+     var  cameraNestedProp ; 
897+     var  cameraDataLastSave ; 
898+ 
899+     var  aspectData ; 
900+     var  aspectNestedProp ; 
901+     var  aspectDataLastSave ; 
902+ 
903+     var  cameraChanged  =  this . isCameraChanged ( layout ) ; 
904+     var  aspectChanged  =  this . isAspectChanged ( layout ) ; 
905+ 
906+     var  hasChanged  =  cameraChanged  ||  aspectChanged ; 
842907    if ( hasChanged )  { 
843908        var  preGUI  =  { } ; 
844-         preGUI [ this . id  +  '.camera' ]  =  cameraDataLastSave ; 
909+         if ( cameraChanged )  { 
910+             cameraData  =  this . getCamera ( ) ; 
911+             cameraNestedProp  =  Lib . nestedProperty ( layout ,  this . id  +  '.camera' ) ; 
912+             cameraDataLastSave  =  cameraNestedProp . get ( ) ; 
913+ 
914+             preGUI [ this . id  +  '.camera' ]  =  cameraDataLastSave ; 
915+         } 
916+         if ( aspectChanged )  { 
917+             aspectData  =  this . glplot . getAspectratio ( ) ; 
918+             aspectNestedProp  =  Lib . nestedProperty ( layout ,  this . id  +  '.aspectratio' ) ; 
919+             aspectDataLastSave  =  aspectNestedProp . get ( ) ; 
920+ 
921+             preGUI [ this . id  +  '.aspectratio' ]  =  aspectDataLastSave ; 
922+         } 
845923        Registry . call ( '_storeDirectGUIEdit' ,  layout ,  fullLayout . _preGUI ,  preGUI ) ; 
846924
847-         cameraNestedProp . set ( cameraData ) ; 
925+         if ( cameraChanged )  { 
926+             cameraNestedProp . set ( cameraData ) ; 
848927
849-         var  cameraFullNP  =  Lib . nestedProperty ( fullLayout ,  this . id  +  '.camera' ) ; 
850-         cameraFullNP . set ( cameraData ) ; 
928+             var  cameraFullNP  =  Lib . nestedProperty ( fullLayout ,  this . id  +  '.camera' ) ; 
929+             cameraFullNP . set ( cameraData ) ; 
930+         } 
931+ 
932+         if ( aspectChanged )  { 
933+             aspectNestedProp . set ( aspectData ) ; 
934+ 
935+             var  aspectFullNP  =  Lib . nestedProperty ( fullLayout ,  this . id  +  '.aspectratio' ) ; 
936+             aspectFullNP . set ( aspectData ) ; 
937+ 
938+             this . glplot . redraw ( ) ; 
939+         } 
851940    } 
852941
853942    return  hasChanged ; 
0 commit comments