@@ -287,17 +287,26 @@ plots.resize = function(gd) {
287
287
if ( gd . _redrawTimer ) clearTimeout ( gd . _redrawTimer ) ;
288
288
289
289
gd . _redrawTimer = setTimeout ( function ( ) {
290
- if ( ( gd . _fullLayout || { } ) . autosize ) {
291
- // autosizing doesn't count as a change that needs saving
292
- var oldchanged = gd . changed ;
290
+ // return if there is nothing to resize
291
+ if ( gd . layout . width && gd . layout . height ) {
292
+ resolve ( gd ) ;
293
+ return ;
294
+ }
295
+
296
+ delete gd . _fullLayout . _initialAutoSizeIsDone ;
297
+ if ( ! gd . layout . width ) delete ( gd . _fullLayout || { } ) . width ;
298
+ if ( ! gd . layout . height ) delete ( gd . _fullLayout || { } ) . height ;
293
299
294
- // nor should it be included in the undo queue
295
- gd . autoplay = true ;
300
+ // autosizing doesn't count as a change that needs saving
301
+ var oldchanged = gd . changed ;
296
302
297
- Plotly . relayout ( gd , { autosize : true } ) ;
303
+ // nor should it be included in the undo queue
304
+ gd . autoplay = true ;
305
+
306
+ Plotly . plot ( gd ) . then ( function ( ) {
298
307
gd . changed = oldchanged ;
299
308
resolve ( gd ) ;
300
- }
309
+ } ) ;
301
310
} , 100 ) ;
302
311
} ) ;
303
312
} ;
@@ -455,7 +464,7 @@ plots.sendDataToCloud = function(gd) {
455
464
plots . supplyDefaults = function ( gd ) {
456
465
var oldFullLayout = gd . _fullLayout || { } ,
457
466
newFullLayout = gd . _fullLayout = { } ,
458
- newLayout = gd . layout || { } ;
467
+ layout = gd . layout || { } ;
459
468
460
469
var oldFullData = gd . _fullData || [ ] ,
461
470
newFullData = gd . _fullData = [ ] ,
@@ -468,7 +477,27 @@ plots.supplyDefaults = function(gd) {
468
477
469
478
// first fill in what we can of layout without looking at data
470
479
// because fullData needs a few things from layout
471
- plots . supplyLayoutGlobalDefaults ( newLayout , newFullLayout ) ;
480
+
481
+ if ( oldFullLayout . _initialAutoSizeIsDone ) {
482
+ // coerce the updated layout while preserving width and height
483
+ var oldWidth = oldFullLayout . width ,
484
+ oldHeight = oldFullLayout . height ;
485
+
486
+ plots . supplyLayoutGlobalDefaults ( layout , newFullLayout ) ;
487
+
488
+ if ( ! layout . width ) newFullLayout . width = oldWidth ;
489
+ if ( ! layout . height ) newFullLayout . height = oldHeight ;
490
+ }
491
+ else {
492
+ // coerce the updated layout and autosize if needed
493
+ plots . supplyLayoutGlobalDefaults ( layout , newFullLayout ) ;
494
+
495
+ if ( ! layout . width || ! layout . height ) {
496
+ plots . plotAutoSize ( gd , layout , newFullLayout ) ;
497
+ }
498
+ }
499
+
500
+ newFullLayout . _initialAutoSizeIsDone = true ;
472
501
473
502
// keep track of how many traces are inputted
474
503
newFullLayout . _dataLength = newData . length ;
@@ -505,7 +534,7 @@ plots.supplyDefaults = function(gd) {
505
534
}
506
535
507
536
// finally, fill in the pieces of layout that may need to look at data
508
- plots . supplyLayoutModuleDefaults ( newLayout , newFullLayout , newFullData ) ;
537
+ plots . supplyLayoutModuleDefaults ( layout , newFullLayout , newFullData ) ;
509
538
510
539
// TODO remove in v2.0.0
511
540
// add has-plot-type refs to fullLayout for backward compatibility
@@ -522,6 +551,7 @@ plots.supplyDefaults = function(gd) {
522
551
// relink functions and _ attributes to promote consistency between plots
523
552
relinkPrivateKeys ( newFullLayout , oldFullLayout ) ;
524
553
554
+ // TODO may return a promise
525
555
plots . doAutoMargin ( gd ) ;
526
556
527
557
// can't quite figure out how to get rid of this... each axis needs
@@ -730,11 +760,9 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
730
760
color : globalFont . color
731
761
} ) ;
732
762
733
- var autosize = coerce ( 'autosize' ,
734
- ( layoutIn . width && layoutIn . height ) ? false : 'initial' ) ;
763
+ coerce ( 'autosize' ) ;
735
764
coerce ( 'width' ) ;
736
765
coerce ( 'height' ) ;
737
-
738
766
coerce ( 'margin.l' ) ;
739
767
coerce ( 'margin.r' ) ;
740
768
coerce ( 'margin.t' ) ;
@@ -743,7 +771,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
743
771
coerce ( 'margin.autoexpand' ) ;
744
772
745
773
// called in plotAutoSize otherwise
746
- if ( autosize !== 'initial' ) plots . sanitizeMargins ( layoutOut ) ;
774
+ if ( layoutOut . width && layoutOut . height ) plots . sanitizeMargins ( layoutOut ) ;
747
775
748
776
coerce ( 'paper_bgcolor' ) ;
749
777
@@ -752,6 +780,85 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
752
780
coerce ( 'smith' ) ;
753
781
} ;
754
782
783
+ plots . plotAutoSize = function plotAutoSize ( gd , layout , fullLayout ) {
784
+ var context = gd . _context || { } ,
785
+ frameMargins = context . frameMargins ,
786
+ newWidth ,
787
+ newHeight ;
788
+
789
+ if ( typeof gd . emit === 'function' ) gd . emit ( 'plotly_autosize' ) ;
790
+
791
+ // embedded in an iframe - just take the full iframe size
792
+ // if we get to this point, with no aspect ratio restrictions
793
+ if ( context . fillFrame ) {
794
+ newWidth = window . innerWidth ;
795
+ newHeight = window . innerHeight ;
796
+
797
+ // somehow we get a few extra px height sometimes...
798
+ // just hide it
799
+ document . body . style . overflow = 'hidden' ;
800
+ }
801
+ else if ( isNumeric ( frameMargins ) && frameMargins > 0 ) {
802
+ var reservedMargins = calculateReservedMargins ( gd . _boundingBoxMargins ) ,
803
+ reservedWidth = reservedMargins . left + reservedMargins . right ,
804
+ reservedHeight = reservedMargins . bottom + reservedMargins . top ,
805
+ gdBB = fullLayout . _container . node ( ) . getBoundingClientRect ( ) ,
806
+ factor = 1 - 2 * frameMargins ;
807
+
808
+ newWidth = Math . round ( factor * ( gdBB . width - reservedWidth ) ) ;
809
+ newHeight = Math . round ( factor * ( gdBB . height - reservedHeight ) ) ;
810
+ }
811
+ else {
812
+ // plotly.js - let the developers do what they want, either
813
+ // provide height and width for the container div,
814
+ // specify size in layout, or take the defaults,
815
+ // but don't enforce any ratio restrictions
816
+ var computedStyle ;
817
+ try {
818
+ computedStyle = window . getComputedStyle ( gd ) ;
819
+ } catch ( err ) {
820
+ computedStyle = { } ;
821
+ }
822
+ newWidth = parseFloat ( computedStyle . width ) || fullLayout . width ;
823
+ newHeight = parseFloat ( computedStyle . height ) || fullLayout . height ;
824
+ }
825
+
826
+ var widthHasChanged = ! layout . width &&
827
+ ( Math . abs ( fullLayout . width - newWidth ) > 1 ) ,
828
+ heightHasChanged = ! layout . height &&
829
+ ( Math . abs ( fullLayout . height - newHeight ) > 1 ) ;
830
+
831
+ if ( heightHasChanged || widthHasChanged ) {
832
+ if ( widthHasChanged ) fullLayout . width = newWidth ;
833
+ if ( heightHasChanged ) fullLayout . height = newHeight ;
834
+
835
+ plots . sanitizeMargins ( fullLayout ) ;
836
+ }
837
+ } ;
838
+
839
+ /**
840
+ * Reduce all reserved margin objects to a single required margin reservation.
841
+ *
842
+ * @param {Object } margins
843
+ * @returns {{left: number, right: number, bottom: number, top: number} }
844
+ */
845
+ function calculateReservedMargins ( margins ) {
846
+ var resultingMargin = { left : 0 , right : 0 , bottom : 0 , top : 0 } ,
847
+ marginName ;
848
+
849
+ if ( margins ) {
850
+ for ( marginName in margins ) {
851
+ if ( margins . hasOwnProperty ( marginName ) ) {
852
+ resultingMargin . left += margins [ marginName ] . left || 0 ;
853
+ resultingMargin . right += margins [ marginName ] . right || 0 ;
854
+ resultingMargin . bottom += margins [ marginName ] . bottom || 0 ;
855
+ resultingMargin . top += margins [ marginName ] . top || 0 ;
856
+ }
857
+ }
858
+ }
859
+ return resultingMargin ;
860
+ }
861
+
755
862
plots . supplyLayoutModuleDefaults = function ( layoutIn , layoutOut , fullData ) {
756
863
var i , _module ;
757
864
0 commit comments