@@ -1705,17 +1705,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
1705
1705
return Promise . resolve ( gd ) ;
1706
1706
}
1707
1707
1708
- var layout = gd . layout ,
1709
- fullLayout = gd . _fullLayout ,
1710
- aobj = { } ,
1711
- dolegend = false ,
1712
- doticks = false ,
1713
- dolayoutstyle = false ,
1714
- doplot = false ,
1715
- docalc = false ,
1716
- domodebar = false ,
1717
- newkey , axes , keys , xyref , scene , axisAttr , i ;
1718
-
1708
+ var aobj = { } ;
1719
1709
if ( typeof astr === 'string' ) aobj [ astr ] = val ;
1720
1710
else if ( Lib . isPlainObject ( astr ) ) aobj = astr ;
1721
1711
else {
@@ -1725,30 +1715,84 @@ Plotly.relayout = function relayout(gd, astr, val) {
1725
1715
1726
1716
if ( Object . keys ( aobj ) . length ) gd . changed = true ;
1727
1717
1728
- keys = Object . keys ( aobj ) ;
1729
- axes = Plotly . Axes . list ( gd ) ;
1718
+ var specs = _relayout ( gd , aobj ) ,
1719
+ flags = specs . flags ;
1720
+
1721
+ // clear calcdata if required
1722
+ if ( flags . docalc ) gd . calcdata = undefined ;
1723
+
1724
+ // fill in redraw sequence
1725
+ var seq = [ ] ;
1726
+
1727
+ if ( flags . layoutReplot ) {
1728
+ seq . push ( subroutines . layoutReplot ) ;
1729
+ }
1730
+ else if ( Object . keys ( aobj ) . length ) {
1731
+ seq . push ( Plots . previousPromises ) ;
1732
+ Plots . supplyDefaults ( gd ) ;
1733
+
1734
+ if ( flags . dolegend ) seq . push ( subroutines . doLegend ) ;
1735
+ if ( flags . dolayoutstyle ) seq . push ( subroutines . layoutStyles ) ;
1736
+ if ( flags . doticks ) seq . push ( subroutines . doTicksRelayout ) ;
1737
+ if ( flags . domodebar ) seq . push ( subroutines . doModeBar ) ;
1738
+ }
1739
+
1740
+ Queue . add ( gd ,
1741
+ relayout , [ gd , specs . undoit ] ,
1742
+ relayout , [ gd , specs . redoit ]
1743
+ ) ;
1744
+
1745
+ var plotDone = Lib . syncOrAsync ( seq , gd ) ;
1746
+ if ( ! plotDone || ! plotDone . then ) plotDone = Promise . resolve ( gd ) ;
1747
+
1748
+ return plotDone . then ( function ( ) {
1749
+ subroutines . setRangeSliderRange ( gd , specs . eventData ) ;
1750
+ gd . emit ( 'plotly_relayout' , specs . eventData ) ;
1751
+ return gd ;
1752
+ } ) ;
1753
+ } ;
1754
+
1755
+ function _relayout ( gd , aobj ) {
1756
+ var layout = gd . layout ,
1757
+ fullLayout = gd . _fullLayout ,
1758
+ keys = Object . keys ( aobj ) ,
1759
+ axes = Plotly . Axes . list ( gd ) ,
1760
+ i ;
1730
1761
1762
+ // look for 'allaxes', split out into all axes
1763
+ // in case of 3D the axis are nested within a scene which is held in _id
1731
1764
for ( i = 0 ; i < keys . length ; i ++ ) {
1732
- // look for 'allaxes', split out into all axes
1733
1765
if ( keys [ i ] . indexOf ( 'allaxes' ) === 0 ) {
1734
1766
for ( var j = 0 ; j < axes . length ; j ++ ) {
1735
- // in case of 3D the axis are nested within a scene which is held in _id
1736
- scene = axes [ j ] . _id . substr ( 1 ) ;
1737
- axisAttr = ( scene . indexOf ( 'scene' ) !== - 1 ) ? ( scene + '.' ) : '' ;
1738
- newkey = keys [ i ] . replace ( 'allaxes' , axisAttr + axes [ j ] . _name ) ;
1739
- if ( ! aobj [ newkey ] ) { aobj [ newkey ] = aobj [ keys [ i ] ] ; }
1767
+ var scene = axes [ j ] . _id . substr ( 1 ) ,
1768
+ axisAttr = ( scene . indexOf ( 'scene' ) !== - 1 ) ? ( scene + '.' ) : '' ,
1769
+ newkey = keys [ i ] . replace ( 'allaxes' , axisAttr + axes [ j ] . _name ) ;
1770
+
1771
+ if ( ! aobj [ newkey ] ) aobj [ newkey ] = aobj [ keys [ i ] ] ;
1740
1772
}
1741
- delete aobj [ keys [ i ] ] ;
1742
- }
1773
+
1743
1774
delete aobj [ keys [ i ] ] ;
1744
1775
}
1745
1776
}
1746
1777
1778
+ // initialize flags
1779
+ var flags = {
1780
+ dolegend : false ,
1781
+ doticks : false ,
1782
+ dolayoutstyle : false ,
1783
+ doplot : false ,
1784
+ docalc : false ,
1785
+ domodebar : false ,
1786
+ layoutReplot : false
1787
+ } ;
1788
+
1747
1789
// copies of the change (and previous values of anything affected)
1748
1790
// for the undo / redo queue
1749
1791
var redoit = { } ,
1750
1792
undoit = { } ;
1751
1793
1794
+ var hw = [ 'height' , 'width' ] ;
1795
+
1752
1796
// for attrs that interact (like scales & autoscales), save the
1753
1797
// old vals before making the change
1754
1798
// val=undefined will not set a value, just record what the value was.
@@ -1772,8 +1816,6 @@ Plotly.relayout = function relayout(gd, astr, val) {
1772
1816
return ( fullLayout [ axName ] || { } ) . autorange ;
1773
1817
}
1774
1818
1775
- var hw = [ 'height' , 'width' ] ;
1776
-
1777
1819
// alter gd.layout
1778
1820
for ( var ai in aobj ) {
1779
1821
var p = Lib . nestedProperty ( layout , ai ) ,
@@ -1826,23 +1868,24 @@ Plotly.relayout = function relayout(gd, astr, val) {
1826
1868
doextra ( [ ptrunk + '.tick0' , ptrunk + '.dtick' ] , undefined ) ;
1827
1869
}
1828
1870
else if ( / [ x y ] a x i s [ 0 - 9 ] * ?$ / . test ( pleaf ) && ! Object . keys ( vi || { } ) . length ) {
1829
- docalc = true ;
1871
+ flags . docalc = true ;
1830
1872
}
1831
1873
else if ( / [ x y ] a x i s [ 0 - 9 ] * \. c a t e g o r y o r d e r $ / . test ( pleafPlus ) ) {
1832
- docalc = true ;
1874
+ flags . docalc = true ;
1833
1875
}
1834
1876
else if ( / [ x y ] a x i s [ 0 - 9 ] * \. c a t e g o r y a r r a y / . test ( pleafPlus ) ) {
1835
- docalc = true ;
1877
+ flags . docalc = true ;
1836
1878
}
1837
1879
1838
1880
if ( pleafPlus . indexOf ( 'rangeslider' ) !== - 1 ) {
1839
- docalc = true ;
1881
+ flags . docalc = true ;
1840
1882
}
1841
1883
1842
1884
// toggling log without autorange: need to also recalculate ranges
1843
1885
// logical XOR (ie are we toggling log)
1844
1886
if ( pleaf === 'type' && ( ( parentFull . type === 'log' ) !== ( vi === 'log' ) ) ) {
1845
1887
var ax = parentIn ;
1888
+
1846
1889
if ( ! ax || ! ax . range ) {
1847
1890
doextra ( ptrunk + '.autorange' , true ) ;
1848
1891
}
@@ -1881,8 +1924,8 @@ Plotly.relayout = function relayout(gd, astr, val) {
1881
1924
parentIn . range = [ 1 , 0 ] ;
1882
1925
}
1883
1926
1884
- if ( parentFull . autorange ) docalc = true ;
1885
- else doplot = true ;
1927
+ if ( parentFull . autorange ) flags . docalc = true ;
1928
+ else flags . doplot = true ;
1886
1929
}
1887
1930
// send annotation and shape mods one-by-one through Annotations.draw(),
1888
1931
// don't set via nestedProperty
@@ -1912,7 +1955,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
1912
1955
1913
1956
if ( ( refAutorange ( obji , 'x' ) || refAutorange ( obji , 'y' ) ) &&
1914
1957
! Lib . containsAny ( ai , [ 'color' , 'opacity' , 'align' , 'dash' ] ) ) {
1915
- docalc = true ;
1958
+ flags . docalc = true ;
1916
1959
}
1917
1960
1918
1961
// TODO: combine all edits to a given annotation / shape into one call
@@ -1940,7 +1983,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
1940
1983
1941
1984
for ( i = 0 ; i < diff ; i ++ ) fullLayers . push ( { } ) ;
1942
1985
1943
- doplot = true ;
1986
+ flags . doplot = true ;
1944
1987
}
1945
1988
else if ( p . parts [ 0 ] === 'updatemenus' ) {
1946
1989
Lib . extendDeepAll ( gd . layout , Lib . objectFromPath ( ai , vi ) ) ;
@@ -1949,165 +1992,101 @@ Plotly.relayout = function relayout(gd, astr, val) {
1949
1992
diff = ( p . parts [ 2 ] + 1 ) - menus . length ;
1950
1993
1951
1994
for ( i = 0 ; i < diff ; i ++ ) menus . push ( { } ) ;
1952
- doplot = true ;
1995
+ flags . doplot = true ;
1953
1996
}
1954
1997
// alter gd.layout
1955
1998
else {
1956
1999
// check whether we can short-circuit a full redraw
1957
2000
// 3d or geo at this point just needs to redraw.
1958
- if ( p . parts [ 0 ] . indexOf ( 'scene' ) === 0 ) doplot = true ;
1959
- else if ( p . parts [ 0 ] . indexOf ( 'geo' ) === 0 ) doplot = true ;
1960
- else if ( p . parts [ 0 ] . indexOf ( 'ternary' ) === 0 ) doplot = true ;
2001
+ if ( p . parts [ 0 ] . indexOf ( 'scene' ) === 0 ) flags . doplot = true ;
2002
+ else if ( p . parts [ 0 ] . indexOf ( 'geo' ) === 0 ) flags . doplot = true ;
2003
+ else if ( p . parts [ 0 ] . indexOf ( 'ternary' ) === 0 ) flags . doplot = true ;
1961
2004
else if ( fullLayout . _has ( 'gl2d' ) &&
1962
2005
( ai . indexOf ( 'axis' ) !== - 1 || p . parts [ 0 ] === 'plot_bgcolor' )
1963
- ) doplot = true ;
1964
- else if ( ai === 'hiddenlabels' ) docalc = true ;
1965
- else if ( p . parts [ 0 ] . indexOf ( 'legend' ) !== - 1 ) dolegend = true ;
1966
- else if ( ai . indexOf ( 'title' ) !== - 1 ) doticks = true ;
1967
- else if ( p . parts [ 0 ] . indexOf ( 'bgcolor' ) !== - 1 ) dolayoutstyle = true ;
2006
+ ) flags . doplot = true ;
2007
+ else if ( ai === 'hiddenlabels' ) flags . docalc = true ;
2008
+ else if ( p . parts [ 0 ] . indexOf ( 'legend' ) !== - 1 ) flags . dolegend = true ;
2009
+ else if ( ai . indexOf ( 'title' ) !== - 1 ) flags . doticks = true ;
2010
+ else if ( p . parts [ 0 ] . indexOf ( 'bgcolor' ) !== - 1 ) flags . dolayoutstyle = true ;
1968
2011
else if ( p . parts . length > 1 &&
1969
2012
Lib . containsAny ( p . parts [ 1 ] , [ 'tick' , 'exponent' , 'grid' , 'zeroline' ] ) ) {
1970
- doticks = true ;
2013
+ flags . doticks = true ;
1971
2014
}
1972
2015
else if ( ai . indexOf ( '.linewidth' ) !== - 1 &&
1973
2016
ai . indexOf ( 'axis' ) !== - 1 ) {
1974
- doticks = dolayoutstyle = true ;
2017
+ flags . doticks = flags . dolayoutstyle = true ;
1975
2018
}
1976
2019
else if ( p . parts . length > 1 && p . parts [ 1 ] . indexOf ( 'line' ) !== - 1 ) {
1977
- dolayoutstyle = true ;
2020
+ flags . dolayoutstyle = true ;
1978
2021
}
1979
2022
else if ( p . parts . length > 1 && p . parts [ 1 ] === 'mirror' ) {
1980
- doticks = dolayoutstyle = true ;
2023
+ flags . doticks = flags . dolayoutstyle = true ;
1981
2024
}
1982
2025
else if ( ai === 'margin.pad' ) {
1983
- doticks = dolayoutstyle = true ;
2026
+ flags . doticks = flags . dolayoutstyle = true ;
1984
2027
}
1985
2028
else if ( p . parts [ 0 ] === 'margin' ||
1986
2029
p . parts [ 1 ] === 'autorange' ||
1987
2030
p . parts [ 1 ] === 'rangemode' ||
1988
2031
p . parts [ 1 ] === 'type' ||
1989
2032
p . parts [ 1 ] === 'domain' ||
1990
2033
ai . match ( / ^ ( b a r | b o x | f o n t ) / ) ) {
1991
- docalc = true ;
2034
+ flags . docalc = true ;
1992
2035
}
1993
2036
/*
1994
2037
* hovermode and dragmode don't need any redrawing, since they just
1995
- * affect reaction to user input. everything else, assume full replot.
2038
+ * affect reaction to user input, everything else, assume full replot.
1996
2039
* height, width, autosize get dealt with below. Except for the case of
1997
2040
* of subplots - scenes - which require scene.updateFx to be called.
1998
2041
*/
1999
- else if ( [ 'hovermode' , 'dragmode' ] . indexOf ( ai ) !== - 1 ) domodebar = true ;
2042
+ else if ( [ 'hovermode' , 'dragmode' ] . indexOf ( ai ) !== - 1 ) flags . domodebar = true ;
2000
2043
else if ( [ 'hovermode' , 'dragmode' , 'height' ,
2001
2044
'width' , 'autosize' ] . indexOf ( ai ) === - 1 ) {
2002
- doplot = true ;
2045
+ flags . doplot = true ;
2003
2046
}
2004
2047
2005
2048
p . set ( vi ) ;
2006
2049
}
2007
2050
}
2008
- // now all attribute mods are done, as are
2009
- // redo and undo so we can save them
2010
- Queue . add ( gd , relayout , [ gd , undoit ] , relayout , [ gd , redoit ] ) ;
2011
2051
2012
2052
// calculate autosizing - if size hasn't changed,
2013
2053
// will remove h&w so we don't need to redraw
2014
2054
if ( aobj . autosize ) aobj = plotAutoSize ( gd , aobj ) ;
2055
+ if ( aobj . height || aobj . width || aobj . autosize ) flags . docalc = true ;
2015
2056
2016
- if ( aobj . height || aobj . width || aobj . autosize ) docalc = true ;
2057
+ if ( flags . doplot || flags . docalc ) {
2058
+ flags . layoutReplot = true ;
2059
+ }
2017
2060
2018
- // redraw
2019
- // first check if there's still anything to do
2020
- var ak = Object . keys ( aobj ) ,
2021
- seq = [ Plots . previousPromises ] ;
2061
+ // now all attribute mods are done, as are
2062
+ // redo and undo so we can save them
2022
2063
2023
- if ( doplot || docalc ) {
2024
- seq . push ( function layoutReplot ( ) {
2025
- // force plot() to redo the layout
2026
- gd . layout = undefined ;
2064
+ return {
2065
+ flags : flags ,
2066
+ undoit : undoit ,
2067
+ redoit : redoit ,
2068
+ eventData : Lib . extendDeep ( { } , redoit )
2069
+ } ;
2070
+ }
2027
2071
2028
- // force it to redo calcdata?
2029
- if ( docalc ) gd . calcdata = undefined ;
2030
2072
2031
- // replot with the modified layout
2032
- return Plotly . plot ( gd , '' , layout ) ;
2033
- } ) ;
2034
2073
}
2035
- else if ( ak . length ) {
2036
- // if we didn't need to redraw entirely, just do the needed parts
2037
- Plots . supplyDefaults ( gd ) ;
2038
- fullLayout = gd . _fullLayout ;
2039
2074
2040
- if ( dolegend ) {
2041
- seq . push ( function doLegend ( ) {
2042
- Registry . getComponentMethod ( 'legend' , 'draw' ) ( gd ) ;
2043
- return Plots . previousPromises ( gd ) ;
2044
- } ) ;
2045
- }
2046
2075
2047
- if ( dolayoutstyle ) seq . push ( layoutStyles ) ;
2048
2076
2049
- if ( doticks ) {
2050
- seq . push ( function ( ) {
2051
- Plotly . Axes . doTicks ( gd , 'redraw' ) ;
2052
- drawMainTitle ( gd ) ;
2053
- return Plots . previousPromises ( gd ) ;
2054
- } ) ;
2055
- }
2056
2077
2057
- // this is decoupled enough it doesn't need async regardless
2058
- if ( domodebar ) {
2059
- var subplotIds ;
2060
- ModeBar . manage ( gd ) ;
2061
2078
2062
- Plotly . Fx . supplyLayoutDefaults ( gd . layout , fullLayout , gd . _fullData ) ;
2063
- Plotly . Fx . init ( gd ) ;
2064
2079
2065
- subplotIds = Plots . getSubplotIds ( fullLayout , 'gl3d' ) ;
2066
- for ( i = 0 ; i < subplotIds . length ; i ++ ) {
2067
- scene = fullLayout [ subplotIds [ i ] ] . _scene ;
2068
- scene . updateFx ( fullLayout . dragmode , fullLayout . hovermode ) ;
2069
- }
2070
2080
2071
- subplotIds = Plots . getSubplotIds ( fullLayout , 'gl2d' ) ;
2072
- for ( i = 0 ; i < subplotIds . length ; i ++ ) {
2073
- scene = fullLayout . _plots [ subplotIds [ i ] ] . _scene2d ;
2074
- scene . updateFx ( fullLayout ) ;
2075
- }
2076
-
2077
- subplotIds = Plots . getSubplotIds ( fullLayout , 'geo' ) ;
2078
- for ( i = 0 ; i < subplotIds . length ; i ++ ) {
2079
- var geo = fullLayout [ subplotIds [ i ] ] . _geo ;
2080
- geo . updateFx ( fullLayout . hovermode ) ;
2081
- }
2082
- }
2083
2081
}
2084
2082
2085
- function setRange ( changes ) {
2086
-
2087
- var newMin = changes [ 'xaxis.range' ] ? changes [ 'xaxis.range' ] [ 0 ] : changes [ 'xaxis.range[0]' ] ,
2088
- newMax = changes [ 'xaxis.range' ] ? changes [ 'xaxis.range' ] [ 1 ] : changes [ 'xaxis.range[1]' ] ;
2089
-
2090
- var rangeSlider = fullLayout . xaxis && fullLayout . xaxis . rangeslider ?
2091
- fullLayout . xaxis . rangeslider : { } ;
2092
-
2093
- if ( rangeSlider . visible ) {
2094
- if ( newMin || newMax ) {
2095
- fullLayout . xaxis . rangeslider . setRange ( newMin , newMax ) ;
2096
- } else if ( changes [ 'xaxis.autorange' ] ) {
2097
- fullLayout . xaxis . rangeslider . setRange ( ) ;
2098
- }
2099
- }
2100
2083
}
2101
2084
2102
- var plotDone = Lib . syncOrAsync ( seq , gd ) ;
2103
2085
2104
2086
if ( ! plotDone || ! plotDone . then ) plotDone = Promise . resolve ( gd ) ;
2105
2087
2106
2088
return plotDone . then ( function ( ) {
2107
- var changes = Lib . extendDeep ( { } , redoit ) ;
2108
2089
2109
- setRange ( changes ) ;
2110
- gd . emit ( 'plotly_relayout' , changes ) ;
2111
2090
2112
2091
return gd ;
2113
2092
} ) ;
0 commit comments