@@ -409,6 +409,10 @@ function plotPolar(gd, data, layout) {
409409 if ( layout ) gd . layout = layout ;
410410 Plotly . micropolar . manager . fillLayout ( gd ) ;
411411
412+ if ( gd . _fullLayout . autosize === 'initial' && gd . _context . autosizable ) {
413+ plotAutoSize ( gd , { } ) ;
414+ gd . _fullLayout . autosize = layout . autosize = true ;
415+ }
412416 // resize canvas
413417 paperDiv . style ( {
414418 width : gd . _fullLayout . width + 'px' ,
@@ -2144,6 +2148,8 @@ Plotly.relayout = function relayout(gd, astr, val) {
21442148 return ( fullLayout [ axName ] || { } ) . autorange ;
21452149 }
21462150
2151+ var hw = [ 'height' , 'width' ] ;
2152+
21472153 // alter gd.layout
21482154 for ( var ai in aobj ) {
21492155 var p = Lib . nestedProperty ( layout , ai ) ,
@@ -2166,8 +2172,14 @@ Plotly.relayout = function relayout(gd, astr, val) {
21662172 // op and has no flag.
21672173 undoit [ ai ] = ( pleaf === 'reverse' ) ? vi : p . get ( ) ;
21682174
2169- // check autorange vs range
2170- if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. r a n g e ( \[ [ 0 | 1 ] \] ) ? $ / ) ) {
2175+ // check autosize or autorange vs size and range
2176+ if ( hw . indexOf ( ai ) !== - 1 ) {
2177+ doextra ( 'autosize' , false ) ;
2178+ }
2179+ else if ( ai === 'autosize' ) {
2180+ doextra ( hw , undefined ) ;
2181+ }
2182+ else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. r a n g e ( \[ [ 0 | 1 ] \] ) ? $ / ) ) {
21712183 doextra ( ptrunk + '.autorange' , false ) ;
21722184 }
21732185 else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. a u t o r a n g e $ / ) ) {
@@ -2346,20 +2358,11 @@ Plotly.relayout = function relayout(gd, astr, val) {
23462358 Queue . add ( gd , relayout , [ gd , undoit ] , relayout , [ gd , redoit ] ) ;
23472359 }
23482360
2349- var oldWidth = gd . _fullLayout . width ,
2350- oldHeight = gd . _fullLayout . height ;
2361+ // calculate autosizing - if size hasn't changed,
2362+ // will remove h&w so we don't need to redraw
2363+ if ( aobj . autosize ) aobj = plotAutoSize ( gd , aobj ) ;
23512364
2352- // coerce the updated layout
2353- Plots . supplyDefaults ( gd ) ;
2354-
2355- // calculate autosizing
2356- if ( gd . layout . autosize ) Plots . plotAutoSize ( gd , gd . layout , gd . _fullLayout ) ;
2357-
2358- // avoid unnecessary redraws
2359- var changed = aobj . height || aobj . width ||
2360- ( gd . _fullLayout . width !== oldWidth ) ||
2361- ( gd . _fullLayout . height !== oldHeight ) ;
2362- if ( changed ) docalc = true ;
2365+ if ( aobj . height || aobj . width || aobj . autosize ) docalc = true ;
23632366
23642367 // redraw
23652368 // first check if there's still anything to do
@@ -2380,6 +2383,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
23802383 }
23812384 else if ( ak . length ) {
23822385 // if we didn't need to redraw entirely, just do the needed parts
2386+ Plots . supplyDefaults ( gd ) ;
23832387 fullLayout = gd . _fullLayout ;
23842388
23852389 if ( dolegend ) {
@@ -2488,6 +2492,86 @@ Plotly.purge = function purge(gd) {
24882492 return gd ;
24892493} ;
24902494
2495+ /**
2496+ * Reduce all reserved margin objects to a single required margin reservation.
2497+ *
2498+ * @param {Object } margins
2499+ * @returns {{left: number, right: number, bottom: number, top: number} }
2500+ */
2501+ function calculateReservedMargins ( margins ) {
2502+ var resultingMargin = { left : 0 , right : 0 , bottom : 0 , top : 0 } ,
2503+ marginName ;
2504+
2505+ if ( margins ) {
2506+ for ( marginName in margins ) {
2507+ if ( margins . hasOwnProperty ( marginName ) ) {
2508+ resultingMargin . left += margins [ marginName ] . left || 0 ;
2509+ resultingMargin . right += margins [ marginName ] . right || 0 ;
2510+ resultingMargin . bottom += margins [ marginName ] . bottom || 0 ;
2511+ resultingMargin . top += margins [ marginName ] . top || 0 ;
2512+ }
2513+ }
2514+ }
2515+ return resultingMargin ;
2516+ }
2517+
2518+ function plotAutoSize ( gd , aobj ) {
2519+ var fullLayout = gd . _fullLayout ,
2520+ context = gd . _context ,
2521+ computedStyle ;
2522+
2523+ var newHeight , newWidth ;
2524+
2525+ gd . emit ( 'plotly_autosize' ) ;
2526+
2527+ // embedded in an iframe - just take the full iframe size
2528+ // if we get to this point, with no aspect ratio restrictions
2529+ if ( gd . _context . fillFrame ) {
2530+ newWidth = window . innerWidth ;
2531+ newHeight = window . innerHeight ;
2532+
2533+ // somehow we get a few extra px height sometimes...
2534+ // just hide it
2535+ document . body . style . overflow = 'hidden' ;
2536+ }
2537+ else if ( isNumeric ( context . frameMargins ) && context . frameMargins > 0 ) {
2538+ var reservedMargins = calculateReservedMargins ( gd . _boundingBoxMargins ) ,
2539+ reservedWidth = reservedMargins . left + reservedMargins . right ,
2540+ reservedHeight = reservedMargins . bottom + reservedMargins . top ,
2541+ gdBB = fullLayout . _container . node ( ) . getBoundingClientRect ( ) ,
2542+ factor = 1 - 2 * context . frameMargins ;
2543+
2544+ newWidth = Math . round ( factor * ( gdBB . width - reservedWidth ) ) ;
2545+ newHeight = Math . round ( factor * ( gdBB . height - reservedHeight ) ) ;
2546+ }
2547+ else {
2548+ // plotly.js - let the developers do what they want, either
2549+ // provide height and width for the container div,
2550+ // specify size in layout, or take the defaults,
2551+ // but don't enforce any ratio restrictions
2552+ computedStyle = window . getComputedStyle ( gd ) ;
2553+ newHeight = parseFloat ( computedStyle . height ) || fullLayout . height ;
2554+ newWidth = parseFloat ( computedStyle . width ) || fullLayout . width ;
2555+ }
2556+
2557+ if ( Math . abs ( fullLayout . width - newWidth ) > 1 ||
2558+ Math . abs ( fullLayout . height - newHeight ) > 1 ) {
2559+ fullLayout . height = gd . layout . height = newHeight ;
2560+ fullLayout . width = gd . layout . width = newWidth ;
2561+ }
2562+ // if there's no size change, update layout but
2563+ // delete the autosize attr so we don't redraw
2564+ // but can't call layoutStyles for initial autosize
2565+ else if ( fullLayout . autosize !== 'initial' ) {
2566+ delete ( aobj . autosize ) ;
2567+ fullLayout . autosize = gd . layout . autosize = true ;
2568+ }
2569+
2570+ Plots . sanitizeMargins ( fullLayout ) ;
2571+
2572+ return aobj ;
2573+ }
2574+
24912575// -------------------------------------------------------
24922576// makePlotFramework: Create the plot container and axes
24932577// -------------------------------------------------------
@@ -2507,6 +2591,13 @@ function makePlotFramework(gd) {
25072591 . classed ( 'svg-container' , true )
25082592 . style ( 'position' , 'relative' ) ;
25092593
2594+ // Initial autosize
2595+ if ( fullLayout . autosize === 'initial' ) {
2596+ plotAutoSize ( gd , { } ) ;
2597+ fullLayout . autosize = true ;
2598+ gd . layout . autosize = true ;
2599+ }
2600+
25102601 // Make the graph containers
25112602 // start fresh each time we get here, so we know the order comes out
25122603 // right, rather than enter/exit which can muck up the order
0 commit comments