@@ -32,6 +32,8 @@ var manageArrays = require('./manage_arrays');
32
32
var helpers = require ( './helpers' ) ;
33
33
var subroutines = require ( './subroutines' ) ;
34
34
var cartesianConstants = require ( '../plots/cartesian/constants' ) ;
35
+ var enforceAxisConstraints = require ( '../plots/cartesian/constraints' ) ;
36
+ var axisIds = require ( '../plots/cartesian/axis_ids' ) ;
35
37
36
38
37
39
/**
@@ -151,10 +153,6 @@ Plotly.plot = function(gd, data, layout, config) {
151
153
makePlotFramework ( gd ) ;
152
154
}
153
155
154
- // save initial axis range once per graph
155
- if ( graphWasEmpty ) Plotly . Axes . saveRangeInitial ( gd ) ;
156
-
157
-
158
156
// prepare the data and find the autorange
159
157
160
158
// generate calcdata, if we need to
@@ -256,18 +254,24 @@ Plotly.plot = function(gd, data, layout, config) {
256
254
return Lib . syncOrAsync ( [
257
255
Registry . getComponentMethod ( 'shapes' , 'calcAutorange' ) ,
258
256
Registry . getComponentMethod ( 'annotations' , 'calcAutorange' ) ,
259
- doAutoRange ,
257
+ doAutoRangeAndConstraints ,
260
258
Registry . getComponentMethod ( 'rangeslider' , 'calcAutorange' )
261
259
] , gd ) ;
262
260
}
263
261
264
- function doAutoRange ( ) {
262
+ function doAutoRangeAndConstraints ( ) {
265
263
if ( gd . _transitioning ) return ;
266
264
267
265
var axList = Plotly . Axes . list ( gd , '' , true ) ;
268
266
for ( var i = 0 ; i < axList . length ; i ++ ) {
269
267
Plotly . Axes . doAutoRange ( axList [ i ] ) ;
270
268
}
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 ) ;
271
275
}
272
276
273
277
// draw ticks, titles, and calculate axis scaling (._b, ._m)
@@ -1863,6 +1867,16 @@ function _relayout(gd, aobj) {
1863
1867
return ( ax || { } ) . autorange ;
1864
1868
}
1865
1869
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
+
1866
1880
// alter gd.layout
1867
1881
for ( var ai in aobj ) {
1868
1882
if ( helpers . hasParent ( aobj , ai ) ) {
@@ -1897,15 +1911,17 @@ function _relayout(gd, aobj) {
1897
1911
//
1898
1912
// To do so, we must manually set them back here using the _initialAutoSize cache.
1899
1913
if ( [ 'width' , 'height' ] . indexOf ( ai ) !== - 1 && vi === null ) {
1900
- gd . _fullLayout [ ai ] = gd . _initialAutoSize [ ai ] ;
1914
+ fullLayout [ ai ] = gd . _initialAutoSize [ ai ] ;
1901
1915
}
1902
1916
// check autorange vs range
1903
1917
else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. r a n g e ( \[ [ 0 | 1 ] \] ) ? $ / ) ) {
1904
1918
doextra ( ptrunk + '.autorange' , false ) ;
1919
+ recordAlteredAxis ( pleafPlus ) ;
1905
1920
}
1906
1921
else if ( pleafPlus . match ( / ^ [ x y z ] a x i s [ 0 - 9 ] * \. a u t o r a n g e $ / ) ) {
1907
1922
doextra ( [ ptrunk + '.range[0]' , ptrunk + '.range[1]' ] ,
1908
1923
undefined ) ;
1924
+ recordAlteredAxis ( pleafPlus ) ;
1909
1925
}
1910
1926
else if ( pleafPlus . match ( / ^ a s p e c t r a t i o \. [ x y z ] $ / ) ) {
1911
1927
doextra ( proot + '.aspectmode' , 'manual' ) ;
@@ -2069,6 +2085,18 @@ function _relayout(gd, aobj) {
2069
2085
else if ( proot . indexOf ( 'geo' ) === 0 ) flags . doplot = true ;
2070
2086
else if ( proot . indexOf ( 'ternary' ) === 0 ) flags . doplot = true ;
2071
2087
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
+ }
2072
2100
else if ( fullLayout . _has ( 'gl2d' ) &&
2073
2101
( ai . indexOf ( 'axis' ) !== - 1 || ai === 'plot_bgcolor' )
2074
2102
) flags . doplot = true ;
@@ -2092,15 +2120,6 @@ function _relayout(gd, aobj) {
2092
2120
else if ( ai === 'margin.pad' ) {
2093
2121
flags . doticks = flags . dolayoutstyle = true ;
2094
2122
}
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
- }
2104
2123
/*
2105
2124
* hovermode and dragmode don't need any redrawing, since they just
2106
2125
* affect reaction to user input, everything else, assume full replot.
@@ -2124,16 +2143,37 @@ function _relayout(gd, aobj) {
2124
2143
if ( ! finished ) flags . doplot = true ;
2125
2144
}
2126
2145
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 ;
2129
2169
2130
2170
// 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 ) ;
2132
2172
2133
2173
// avoid unnecessary redraws
2134
2174
var hasSizechanged = aobj . height || aobj . width ||
2135
- ( gd . _fullLayout . width !== oldWidth ) ||
2136
- ( gd . _fullLayout . height !== oldHeight ) ;
2175
+ ( fullLayout . width !== oldWidth ) ||
2176
+ ( fullLayout . height !== oldHeight ) ;
2137
2177
2138
2178
if ( hasSizechanged ) flags . docalc = true ;
2139
2179
0 commit comments