@@ -35,8 +35,6 @@ var subroutines = require('./subroutines');
35
35
/**
36
36
* Main plot-creation function
37
37
*
38
- * Note: will call makePlotFramework if necessary to create the framework
39
- *
40
38
* @param {string id or DOM element } gd
41
39
* the id or DOM element of the graph container div
42
40
* @param {array of objects } data
@@ -123,28 +121,15 @@ Plotly.plot = function(gd, data, layout, config) {
123
121
// so we don't try to re-call Plotly.plot from inside
124
122
// legend and colorbar, if margins changed
125
123
gd . _replotting = true ;
126
- var hasData = gd . _fullData . length > 0 ;
127
124
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 ) ;
131
127
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 ) {
144
130
gd . framework = makePlotFramework ;
145
131
makePlotFramework ( gd ) ;
146
132
}
147
- else if ( graphWasEmpty ) makePlotFramework ( gd ) ;
148
133
149
134
// save initial axis range once per graph
150
135
if ( graphWasEmpty ) Plotly . Axes . saveRangeInitial ( gd ) ;
@@ -169,6 +154,24 @@ Plotly.plot = function(gd, data, layout, config) {
169
154
170
155
var oldmargins = JSON . stringify ( fullLayout . _size ) ;
171
156
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
+
172
175
// draw anything that can affect margins.
173
176
// currently this is legend and colorbars
174
177
function marginPushers ( ) {
@@ -195,8 +198,10 @@ Plotly.plot = function(gd, data, layout, config) {
195
198
function marginPushersAgain ( ) {
196
199
// in case the margins changed, draw margin pushers again
197
200
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 ) ;
200
205
}
201
206
202
207
function positionAndAutorange ( ) {
@@ -220,7 +225,6 @@ Plotly.plot = function(gd, data, layout, config) {
220
225
}
221
226
}
222
227
223
-
224
228
// calc and autorange for errorbars
225
229
ErrorBars . calc ( gd ) ;
226
230
@@ -234,14 +238,15 @@ Plotly.plot = function(gd, data, layout, config) {
234
238
235
239
function doAutoRange ( ) {
236
240
if ( gd . _transitioning ) return ;
241
+
237
242
var axList = Plotly . Axes . list ( gd , '' , true ) ;
238
243
for ( var i = 0 ; i < axList . length ; i ++ ) {
239
244
Plotly . Axes . doAutoRange ( axList [ i ] ) ;
240
245
}
241
246
}
242
247
248
+ // draw ticks, titles, and calculate axis scaling (._b, ._m)
243
249
function drawAxes ( ) {
244
- // draw ticks, titles, and calculate axis scaling (._b, ._m)
245
250
return Plotly . Axes . doTicks ( gd , 'redraw' ) ;
246
251
}
247
252
@@ -276,6 +281,11 @@ Plotly.plot = function(gd, data, layout, config) {
276
281
basePlotModules [ i ] . plot ( gd ) ;
277
282
}
278
283
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
+
279
289
// styling separate from drawing
280
290
Plots . style ( gd ) ;
281
291
@@ -313,6 +323,7 @@ Plotly.plot = function(gd, data, layout, config) {
313
323
314
324
Lib . syncOrAsync ( [
315
325
Plots . previousPromises ,
326
+ drawFramework ,
316
327
marginPushers ,
317
328
marginPushersAgain ,
318
329
positionAndAutorange ,
@@ -2757,21 +2768,12 @@ function makePlotFramework(gd) {
2757
2768
fullLayout . _shapeLowerLayer = layerBelow . append ( 'g' )
2758
2769
. classed ( 'shapelayer' , true ) ;
2759
2770
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 ) ;
2766
2773
2767
2774
// single ternary layer for the whole plot
2768
2775
fullLayout . _ternarylayer = fullLayout . _paper . append ( 'g' ) . classed ( 'ternarylayer' , true ) ;
2769
2776
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
-
2775
2777
// upper shape layer
2776
2778
// (only for shapes to be drawn above the whole plot, including subplots)
2777
2779
var layerAbove = fullLayout . _paper . append ( 'g' )
@@ -2796,176 +2798,4 @@ function makePlotFramework(gd) {
2796
2798
fullLayout . _hoverlayer = fullLayout . _toppaper . append ( 'g' ) . classed ( 'hoverlayer' , true ) ;
2797
2799
2798
2800
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
- } ) ;
2971
2801
}
0 commit comments