@@ -35,8 +35,6 @@ var subroutines = require('./subroutines');
3535/**
3636 * Main plot-creation function
3737 *
38- * Note: will call makePlotFramework if necessary to create the framework
39- *
4038 * @param {string id or DOM element } gd
4139 * the id or DOM element of the graph container div
4240 * @param {array of objects } data
@@ -123,28 +121,15 @@ Plotly.plot = function(gd, data, layout, config) {
123121 // so we don't try to re-call Plotly.plot from inside
124122 // legend and colorbar, if margins changed
125123 gd . _replotting = true ;
126- var hasData = gd . _fullData . length > 0 ;
127124
128- var subplots = Plotly . Axes . getSubplots ( gd ) . join ( '' ) ,
129- oldSubplots = Object . keys ( gd . _fullLayout . _plots || { } ) . join ( '' ) ,
130- hasSameSubplots = ( oldSubplots === subplots ) ;
125+ // make or remake the framework if we need to
126+ if ( graphWasEmpty ) makePlotFramework ( gd ) ;
131127
132- // Make or remake the framework (ie container and axes) if we need to
133- // note: if they container already exists and has data,
134- // the new layout gets ignored (as it should)
135- // but if there's no data there yet, it's just a placeholder...
136- // then it should destroy and remake the plot
137- if ( hasData ) {
138- if ( gd . framework !== makePlotFramework || graphWasEmpty || ! hasSameSubplots ) {
139- gd . framework = makePlotFramework ;
140- makePlotFramework ( gd ) ;
141- }
142- }
143- else if ( ! hasSameSubplots ) {
128+ // polar need a different framework
129+ if ( gd . framework !== makePlotFramework ) {
144130 gd . framework = makePlotFramework ;
145131 makePlotFramework ( gd ) ;
146132 }
147- else if ( graphWasEmpty ) makePlotFramework ( gd ) ;
148133
149134 // save initial axis range once per graph
150135 if ( graphWasEmpty ) Plotly . Axes . saveRangeInitial ( gd ) ;
@@ -169,6 +154,24 @@ Plotly.plot = function(gd, data, layout, config) {
169154
170155 var oldmargins = JSON . stringify ( fullLayout . _size ) ;
171156
157+ // draw framework first so that margin-pushing
158+ // components can position themselves correctly
159+ function drawFramework ( ) {
160+ var basePlotModules = fullLayout . _basePlotModules ;
161+
162+ for ( var i = 0 ; i < basePlotModules . length ; i ++ ) {
163+ if ( basePlotModules [ i ] . drawFramework ) {
164+ basePlotModules [ i ] . drawFramework ( gd ) ;
165+ }
166+ }
167+
168+ return Lib . syncOrAsync ( [
169+ subroutines . layoutStyles ,
170+ drawAxes ,
171+ Fx . init
172+ ] , gd ) ;
173+ }
174+
172175 // draw anything that can affect margins.
173176 // currently this is legend and colorbars
174177 function marginPushers ( ) {
@@ -195,8 +198,10 @@ Plotly.plot = function(gd, data, layout, config) {
195198 function marginPushersAgain ( ) {
196199 // in case the margins changed, draw margin pushers again
197200 var seq = JSON . stringify ( fullLayout . _size ) === oldmargins ?
198- [ ] : [ marginPushers , subroutines . layoutStyles ] ;
199- return Lib . syncOrAsync ( seq . concat ( Fx . init ) , gd ) ;
201+ [ ] :
202+ [ marginPushers , subroutines . layoutStyles ] ;
203+
204+ return Lib . syncOrAsync ( seq , gd ) ;
200205 }
201206
202207 function positionAndAutorange ( ) {
@@ -220,7 +225,6 @@ Plotly.plot = function(gd, data, layout, config) {
220225 }
221226 }
222227
223-
224228 // calc and autorange for errorbars
225229 ErrorBars . calc ( gd ) ;
226230
@@ -234,14 +238,15 @@ Plotly.plot = function(gd, data, layout, config) {
234238
235239 function doAutoRange ( ) {
236240 if ( gd . _transitioning ) return ;
241+
237242 var axList = Plotly . Axes . list ( gd , '' , true ) ;
238243 for ( var i = 0 ; i < axList . length ; i ++ ) {
239244 Plotly . Axes . doAutoRange ( axList [ i ] ) ;
240245 }
241246 }
242247
248+ // draw ticks, titles, and calculate axis scaling (._b, ._m)
243249 function drawAxes ( ) {
244- // draw ticks, titles, and calculate axis scaling (._b, ._m)
245250 return Plotly . Axes . doTicks ( gd , 'redraw' ) ;
246251 }
247252
@@ -276,6 +281,11 @@ Plotly.plot = function(gd, data, layout, config) {
276281 basePlotModules [ i ] . plot ( gd ) ;
277282 }
278283
284+ // keep reference to shape layers in subplots
285+ var layerSubplot = fullLayout . _paper . selectAll ( '.layer-subplot' ) ;
286+ fullLayout . _imageSubplotLayer = layerSubplot . selectAll ( '.imagelayer' ) ;
287+ fullLayout . _shapeSubplotLayer = layerSubplot . selectAll ( '.shapelayer' ) ;
288+
279289 // styling separate from drawing
280290 Plots . style ( gd ) ;
281291
@@ -313,6 +323,7 @@ Plotly.plot = function(gd, data, layout, config) {
313323
314324 Lib . syncOrAsync ( [
315325 Plots . previousPromises ,
326+ drawFramework ,
316327 marginPushers ,
317328 marginPushersAgain ,
318329 positionAndAutorange ,
@@ -2757,21 +2768,12 @@ function makePlotFramework(gd) {
27572768 fullLayout . _shapeLowerLayer = layerBelow . append ( 'g' )
27582769 . classed ( 'shapelayer' , true ) ;
27592770
2760- var subplots = Plotly . Axes . getSubplots ( gd ) ;
2761- if ( subplots . join ( '' ) !== Object . keys ( gd . _fullLayout . _plots || { } ) . join ( '' ) ) {
2762- makeSubplots ( gd , subplots ) ;
2763- }
2764-
2765- if ( fullLayout . _has ( 'cartesian' ) ) makeCartesianPlotFramwork ( gd , subplots ) ;
2771+ // single cartesian layer for the whole plot
2772+ fullLayout . _cartesianlayer = fullLayout . _paper . append ( 'g' ) . classed ( 'cartesianlayer' , true ) ;
27662773
27672774 // single ternary layer for the whole plot
27682775 fullLayout . _ternarylayer = fullLayout . _paper . append ( 'g' ) . classed ( 'ternarylayer' , true ) ;
27692776
2770- // shape layers in subplots
2771- var layerSubplot = fullLayout . _paper . selectAll ( '.layer-subplot' ) ;
2772- fullLayout . _imageSubplotLayer = layerSubplot . selectAll ( '.imagelayer' ) ;
2773- fullLayout . _shapeSubplotLayer = layerSubplot . selectAll ( '.shapelayer' ) ;
2774-
27752777 // upper shape layer
27762778 // (only for shapes to be drawn above the whole plot, including subplots)
27772779 var layerAbove = fullLayout . _paper . append ( 'g' )
@@ -2796,176 +2798,4 @@ function makePlotFramework(gd) {
27962798 fullLayout . _hoverlayer = fullLayout . _toppaper . append ( 'g' ) . classed ( 'hoverlayer' , true ) ;
27972799
27982800 gd . emit ( 'plotly_framework' ) ;
2799-
2800- // position and style the containers, make main title
2801- var frameWorkDone = Lib . syncOrAsync ( [
2802- subroutines . layoutStyles ,
2803- function goAxes ( ) { return Plotly . Axes . doTicks ( gd , 'redraw' ) ; } ,
2804- Fx . init
2805- ] , gd ) ;
2806-
2807- if ( frameWorkDone && frameWorkDone . then ) {
2808- gd . _promises . push ( frameWorkDone ) ;
2809- }
2810-
2811- return frameWorkDone ;
2812- }
2813-
2814- // create '_plots' object grouping x/y axes into subplots
2815- // to be better manage subplots
2816- function makeSubplots ( gd , subplots ) {
2817- var _plots = gd . _fullLayout . _plots = { } ;
2818- var subplot , plotinfo ;
2819-
2820- function getAxisFunc ( subplot , axLetter ) {
2821- return function ( ) {
2822- return Plotly . Axes . getFromId ( gd , subplot , axLetter ) ;
2823- } ;
2824- }
2825-
2826- for ( var i = 0 ; i < subplots . length ; i ++ ) {
2827- subplot = subplots [ i ] ;
2828- plotinfo = _plots [ subplot ] = { } ;
2829-
2830- plotinfo . id = subplot ;
2831-
2832- // references to the axis objects controlling this subplot
2833- plotinfo . x = getAxisFunc ( subplot , 'x' ) ;
2834- plotinfo . y = getAxisFunc ( subplot , 'y' ) ;
2835-
2836- // TODO investigate why replacing calls to .x and .y
2837- // for .xaxis and .yaxis makes the `pseudo_html`
2838- // test image fail
2839- plotinfo . xaxis = plotinfo . x ( ) ;
2840- plotinfo . yaxis = plotinfo . y ( ) ;
2841- }
2842- }
2843-
2844- function makeCartesianPlotFramwork ( gd , subplots ) {
2845- var fullLayout = gd . _fullLayout ;
2846-
2847- // Layers to keep plot types in the right order.
2848- // from back to front:
2849- // 1. heatmaps, 2D histos and contour maps
2850- // 2. bars / 1D histos
2851- // 3. errorbars for bars and scatter
2852- // 4. scatter
2853- // 5. box plots
2854- function plotLayers ( svg ) {
2855- svg . append ( 'g' ) . classed ( 'imagelayer' , true ) ;
2856- svg . append ( 'g' ) . classed ( 'maplayer' , true ) ;
2857- svg . append ( 'g' ) . classed ( 'barlayer' , true ) ;
2858- svg . append ( 'g' ) . classed ( 'boxlayer' , true ) ;
2859- svg . append ( 'g' ) . classed ( 'scatterlayer' , true ) ;
2860- }
2861-
2862- // create all the layers in order, so we know they'll stay in order
2863- var overlays = [ ] ;
2864-
2865- fullLayout . _paper . selectAll ( 'g.subplot' ) . data ( subplots )
2866- . enter ( ) . append ( 'g' )
2867- . classed ( 'subplot' , true )
2868- . each ( function ( subplot ) {
2869- var plotinfo = fullLayout . _plots [ subplot ] ,
2870- plotgroup = plotinfo . plotgroup = d3 . select ( this ) . classed ( subplot , true ) ,
2871- xa = plotinfo . xaxis ,
2872- ya = plotinfo . yaxis ;
2873-
2874- // references to any subplots overlaid on this one
2875- plotinfo . overlays = [ ] ;
2876-
2877- // is this subplot overlaid on another?
2878- // ax.overlaying is the id of another axis of the same
2879- // dimension that this one overlays to be an overlaid subplot,
2880- // the main plot must exist make sure we're not trying to
2881- // overlay on an axis that's already overlaying another
2882- var xa2 = Plotly . Axes . getFromId ( gd , xa . overlaying ) || xa ;
2883- if ( xa2 !== xa && xa2 . overlaying ) {
2884- xa2 = xa ;
2885- xa . overlaying = false ;
2886- }
2887-
2888- var ya2 = Plotly . Axes . getFromId ( gd , ya . overlaying ) || ya ;
2889- if ( ya2 !== ya && ya2 . overlaying ) {
2890- ya2 = ya ;
2891- ya . overlaying = false ;
2892- }
2893-
2894- var mainplot = xa2 . _id + ya2 . _id ;
2895- if ( mainplot !== subplot && subplots . indexOf ( mainplot ) !== - 1 ) {
2896- plotinfo . mainplot = mainplot ;
2897- overlays . push ( plotinfo ) ;
2898-
2899- // for now force overlays to overlay completely... so they
2900- // can drag together correctly and share backgrounds.
2901- // Later perhaps we make separate axis domain and
2902- // tick/line domain or something, so they can still share
2903- // the (possibly larger) dragger and background but don't
2904- // have to both be drawn over that whole domain
2905- xa . domain = xa2 . domain . slice ( ) ;
2906- ya . domain = ya2 . domain . slice ( ) ;
2907- }
2908- else {
2909- // main subplot - make the components of
2910- // the plot and containers for overlays
2911- plotinfo . bg = plotgroup . append ( 'rect' )
2912- . style ( 'stroke-width' , 0 ) ;
2913-
2914- // back layer for shapes and images to
2915- // be drawn below a subplot
2916- var backlayer = plotgroup . append ( 'g' )
2917- . classed ( 'layer-subplot' , true ) ;
2918-
2919- plotinfo . shapelayer = backlayer . append ( 'g' )
2920- . classed ( 'shapelayer' , true ) ;
2921- plotinfo . imagelayer = backlayer . append ( 'g' )
2922- . classed ( 'imagelayer' , true ) ;
2923- plotinfo . gridlayer = plotgroup . append ( 'g' ) ;
2924- plotinfo . overgrid = plotgroup . append ( 'g' ) ;
2925- plotinfo . zerolinelayer = plotgroup . append ( 'g' ) ;
2926- plotinfo . overzero = plotgroup . append ( 'g' ) ;
2927- plotinfo . plot = plotgroup . append ( 'g' ) . call ( plotLayers ) ;
2928- plotinfo . overplot = plotgroup . append ( 'g' ) ;
2929- plotinfo . xlines = plotgroup . append ( 'path' ) ;
2930- plotinfo . ylines = plotgroup . append ( 'path' ) ;
2931- plotinfo . overlines = plotgroup . append ( 'g' ) ;
2932- plotinfo . xaxislayer = plotgroup . append ( 'g' ) ;
2933- plotinfo . yaxislayer = plotgroup . append ( 'g' ) ;
2934- plotinfo . overaxes = plotgroup . append ( 'g' ) ;
2935-
2936- // make separate drag layers for each subplot,
2937- // but append them to paper rather than the plot groups,
2938- // so they end up on top of the rest
2939- }
2940- plotinfo . draglayer = fullLayout . _draggers . append ( 'g' ) ;
2941- } ) ;
2942-
2943- // now make the components of overlaid subplots
2944- // overlays don't have backgrounds, and append all
2945- // their other components to the corresponding
2946- // extra groups of their main Plots.
2947- overlays . forEach ( function ( plotinfo ) {
2948- var mainplot = fullLayout . _plots [ plotinfo . mainplot ] ;
2949- mainplot . overlays . push ( plotinfo ) ;
2950-
2951- plotinfo . gridlayer = mainplot . overgrid . append ( 'g' ) ;
2952- plotinfo . zerolinelayer = mainplot . overzero . append ( 'g' ) ;
2953- plotinfo . plot = mainplot . overplot . append ( 'g' ) . call ( plotLayers ) ;
2954- plotinfo . xlines = mainplot . overlines . append ( 'path' ) ;
2955- plotinfo . ylines = mainplot . overlines . append ( 'path' ) ;
2956- plotinfo . xaxislayer = mainplot . overaxes . append ( 'g' ) ;
2957- plotinfo . yaxislayer = mainplot . overaxes . append ( 'g' ) ;
2958- } ) ;
2959-
2960- // common attributes for all subplots, overlays or not
2961- subplots . forEach ( function ( subplot ) {
2962- var plotinfo = fullLayout . _plots [ subplot ] ;
2963-
2964- plotinfo . xlines
2965- . style ( 'fill' , 'none' )
2966- . classed ( 'crisp' , true ) ;
2967- plotinfo . ylines
2968- . style ( 'fill' , 'none' )
2969- . classed ( 'crisp' , true ) ;
2970- } ) ;
29712801}
0 commit comments