@@ -32,6 +32,8 @@ var manageArrays = require('./manage_arrays');
3232var helpers = require ( './helpers' ) ;
3333var subroutines = require ( './subroutines' ) ;
3434var cartesianConstants = require ( '../plots/cartesian/constants' ) ;
35+ var enforceAxisConstraints = require ( '../plots/cartesian/constraints' ) ;
36+ var axisIds = require ( '../plots/cartesian/axis_ids' ) ;
3537
3638
3739/**
@@ -151,10 +153,6 @@ Plotly.plot = function(gd, data, layout, config) {
151153 makePlotFramework ( gd ) ;
152154 }
153155
154- // save initial axis range once per graph
155- if ( graphWasEmpty ) Plotly . Axes . saveRangeInitial ( gd ) ;
156-
157-
158156 // prepare the data and find the autorange
159157
160158 // generate calcdata, if we need to
@@ -256,18 +254,24 @@ Plotly.plot = function(gd, data, layout, config) {
256254 return Lib . syncOrAsync ( [
257255 Registry . getComponentMethod ( 'shapes' , 'calcAutorange' ) ,
258256 Registry . getComponentMethod ( 'annotations' , 'calcAutorange' ) ,
259- doAutoRange ,
257+ doAutoRangeAndConstraints ,
260258 Registry . getComponentMethod ( 'rangeslider' , 'calcAutorange' )
261259 ] , gd ) ;
262260 }
263261
264- function doAutoRange ( ) {
262+ function doAutoRangeAndConstraints ( ) {
265263 if ( gd . _transitioning ) return ;
266264
267265 var axList = Plotly . Axes . list ( gd , '' , true ) ;
268266 for ( var i = 0 ; i < axList . length ; i ++ ) {
269267 Plotly . Axes . doAutoRange ( axList [ i ] ) ;
270268 }
269+
270+ enforceAxisConstraints ( gd ) ;
271+
272+ // store initial ranges *after* enforcing constraints, otherwise
273+ // we will never look like we're at the initial ranges
274+ if ( graphWasEmpty ) Plotly . Axes . saveRangeInitial ( gd ) ;
271275 }
272276
273277 // draw ticks, titles, and calculate axis scaling (._b, ._m)
@@ -1863,6 +1867,16 @@ function _relayout(gd, aobj) {
18631867 return ( ax || { } ) . autorange ;
18641868 }
18651869
1870+ // for constraint enforcement: keep track of all axes (as {id: name})
1871+ // we're editing the (auto)range of, so we can tell the others constrained
1872+ // to scale with them that it's OK for them to shrink
1873+ var rangesAltered = { } ;
1874+
1875+ function recordAlteredAxis ( pleafPlus ) {
1876+ var axId = axisIds . name2id ( pleafPlus . split ( '.' ) [ 0 ] ) ;
1877+ rangesAltered [ axId ] = 1 ;
1878+ }
1879+
18661880 // alter gd.layout
18671881 for ( var ai in aobj ) {
18681882 if ( helpers . hasParent ( aobj , ai ) ) {
@@ -1897,15 +1911,17 @@ function _relayout(gd, aobj) {
18971911 //
18981912 // To do so, we must manually set them back here using the _initialAutoSize cache.
18991913 if ( [ 'width' , 'height' ] . indexOf ( ai ) !== - 1 && vi === null ) {
1900- gd . _fullLayout [ ai ] = gd . _initialAutoSize [ ai ] ;
1914+ fullLayout [ ai ] = gd . _initialAutoSize [ ai ] ;
19011915 }
19021916 // check autorange vs range
19031917 else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. r a n g e ( \[ [ 0 | 1 ] \] ) ? $ / ) ) {
19041918 doextra ( ptrunk + '.autorange' , false ) ;
1919+ recordAlteredAxis ( pleafPlus ) ;
19051920 }
19061921 else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. a u t o r a n g e $ / ) ) {
19071922 doextra ( [ ptrunk + '.range[0]' , ptrunk + '.range[1]' ] ,
19081923 undefined ) ;
1924+ recordAlteredAxis ( pleafPlus ) ;
19091925 }
19101926 else if ( pleafPlus . match ( / ^ a s p e c t r a t i o \. [ x y z ] $ / ) ) {
19111927 doextra ( proot + '.aspectmode' , 'manual' ) ;
@@ -2069,6 +2085,18 @@ function _relayout(gd, aobj) {
20692085 else if ( proot . indexOf ( 'geo' ) === 0 ) flags . doplot = true ;
20702086 else if ( proot . indexOf ( 'ternary' ) === 0 ) flags . doplot = true ;
20712087 else if ( ai === 'paper_bgcolor' ) flags . doplot = true ;
2088+ else if ( proot === 'margin' ||
2089+ pp1 === 'autorange' ||
2090+ pp1 === 'rangemode' ||
2091+ pp1 === 'type' ||
2092+ pp1 === 'domain' ||
2093+ pp1 === 'fixedrange' ||
2094+ pp1 === 'scaleanchor' ||
2095+ pp1 === 'scaleratio' ||
2096+ ai . indexOf ( 'calendar' ) !== - 1 ||
2097+ ai . match ( / ^ ( b a r | b o x | f o n t ) / ) ) {
2098+ flags . docalc = true ;
2099+ }
20722100 else if ( fullLayout . _has ( 'gl2d' ) &&
20732101 ( ai . indexOf ( 'axis' ) !== - 1 || ai === 'plot_bgcolor' )
20742102 ) flags . doplot = true ;
@@ -2092,15 +2120,6 @@ function _relayout(gd, aobj) {
20922120 else if ( ai === 'margin.pad' ) {
20932121 flags . doticks = flags . dolayoutstyle = true ;
20942122 }
2095- else if ( proot === 'margin' ||
2096- pp1 === 'autorange' ||
2097- pp1 === 'rangemode' ||
2098- pp1 === 'type' ||
2099- pp1 === 'domain' ||
2100- ai . indexOf ( 'calendar' ) !== - 1 ||
2101- ai . match ( / ^ ( b a r | b o x | f o n t ) / ) ) {
2102- flags . docalc = true ;
2103- }
21042123 /*
21052124 * hovermode and dragmode don't need any redrawing, since they just
21062125 * affect reaction to user input, everything else, assume full replot.
@@ -2124,16 +2143,37 @@ function _relayout(gd, aobj) {
21242143 if ( ! finished ) flags . doplot = true ;
21252144 }
21262145
2127- var oldWidth = gd . _fullLayout . width ,
2128- oldHeight = gd . _fullLayout . height ;
2146+ // figure out if we need to recalculate axis constraints
2147+ var constraints = fullLayout . _axisConstraintGroups ;
2148+ for ( var axId in rangesAltered ) {
2149+ for ( i = 0 ; i < constraints . length ; i ++ ) {
2150+ var group = constraints [ i ] ;
2151+ if ( group [ axId ] ) {
2152+ // Always recalc if we're changing constrained ranges.
2153+ // Otherwise it's possible to violate the constraints by
2154+ // specifying arbitrary ranges for all axes in the group.
2155+ // this way some ranges may expand beyond what's specified,
2156+ // as they do at first draw, to satisfy the constraints.
2157+ flags . docalc = true ;
2158+ for ( var groupAxId in group ) {
2159+ if ( ! rangesAltered [ groupAxId ] ) {
2160+ axisIds . getFromId ( gd , groupAxId ) . _constraintShrinkable = true ;
2161+ }
2162+ }
2163+ }
2164+ }
2165+ }
2166+
2167+ var oldWidth = fullLayout . width ,
2168+ oldHeight = fullLayout . height ;
21292169
21302170 // calculate autosizing
2131- if ( gd . layout . autosize ) Plots . plotAutoSize ( gd , gd . layout , gd . _fullLayout ) ;
2171+ if ( gd . layout . autosize ) Plots . plotAutoSize ( gd , gd . layout , fullLayout ) ;
21322172
21332173 // avoid unnecessary redraws
21342174 var hasSizechanged = aobj . height || aobj . width ||
2135- ( gd . _fullLayout . width !== oldWidth ) ||
2136- ( gd . _fullLayout . height !== oldHeight ) ;
2175+ ( fullLayout . width !== oldWidth ) ||
2176+ ( fullLayout . height !== oldHeight ) ;
21372177
21382178 if ( hasSizechanged ) flags . docalc = true ;
21392179
0 commit comments