@@ -34,6 +34,7 @@ function handleShapeDefaults(shapeIn, fullLayout) {
34
34
attr , dflt ) ;
35
35
}
36
36
37
+ coerce ( 'layer' ) ;
37
38
coerce ( 'opacity' ) ;
38
39
coerce ( 'fillcolor' ) ;
39
40
coerce ( 'line.color' ) ;
@@ -167,7 +168,8 @@ function updateAllShapes(gd, opt, value) {
167
168
}
168
169
169
170
function deleteShape ( gd , index ) {
170
- gd . _fullLayout . _shapelayer . selectAll ( '[data-index="' + index + '"]' )
171
+ getShapeLayer ( gd , index )
172
+ . selectAll ( '[data-index="' + index + '"]' )
171
173
. remove ( ) ;
172
174
173
175
gd . _fullLayout . shapes . splice ( index , 1 ) ;
@@ -177,9 +179,9 @@ function deleteShape(gd, index) {
177
179
for ( var i = index ; i < gd . _fullLayout . shapes . length ; i ++ ) {
178
180
// redraw all shapes past the removed one,
179
181
// so they bind to the right events
180
- gd . _fullLayout . _shapelayer
181
- . selectAll ( '[data-index="' + ( i + 1 ) + '"]' )
182
- . attr ( 'data-index' , String ( i ) ) ;
182
+ getShapeLayer ( gd , i )
183
+ . selectAll ( '[data-index="' + ( i + 1 ) + '"]' )
184
+ . attr ( 'data-index' , i ) ;
183
185
shapes . draw ( gd , i ) ;
184
186
}
185
187
}
@@ -197,10 +199,13 @@ function insertShape(gd, index, newShape) {
197
199
gd . layout . shapes = [ rule ] ;
198
200
}
199
201
202
+ // there is no need to call shapes.draw(gd, index),
203
+ // because updateShape() is called from within shapes.draw()
204
+
200
205
for ( var i = gd . _fullLayout . shapes . length - 1 ; i > index ; i -- ) {
201
- gd . _fullLayout . _shapelayer
206
+ getShapeLayer ( gd , i )
202
207
. selectAll ( '[data-index="' + ( i - 1 ) + '"]' )
203
- . attr ( 'data-index' , String ( i ) ) ;
208
+ . attr ( 'data-index' , i ) ;
204
209
shapes . draw ( gd , i ) ;
205
210
}
206
211
}
@@ -209,7 +214,8 @@ function updateShape(gd, index, opt, value) {
209
214
var i ;
210
215
211
216
// remove the existing shape if there is one
212
- gd . _fullLayout . _shapelayer . selectAll ( '[data-index="' + index + '"]' )
217
+ getShapeLayer ( gd , index )
218
+ . selectAll ( '[data-index="' + index + '"]' )
213
219
. remove ( ) ;
214
220
215
221
// remember a few things about what was already there,
@@ -284,24 +290,73 @@ function updateShape(gd, index, opt, value) {
284
290
gd . _fullLayout . shapes [ index ] = options ;
285
291
286
292
var attrs = {
287
- 'data-index' : String ( index ) ,
293
+ 'data-index' : index ,
288
294
'fill-rule' : 'evenodd' ,
289
295
d : shapePath ( gd , options )
290
296
} ,
291
297
clipAxes = ( options . xref + options . yref ) . replace ( / p a p e r / g, '' ) ;
292
298
293
299
var lineColor = options . line . width ? options . line . color : 'rgba(0,0,0,0)' ;
294
300
295
- var path = gd . _fullLayout . _shapelayer . append ( 'path' )
296
- . attr ( attrs )
297
- . style ( 'opacity' , options . opacity )
298
- . call ( Plotly . Color . stroke , lineColor )
299
- . call ( Plotly . Color . fill , options . fillcolor )
300
- . call ( Plotly . Drawing . dashLine , options . line . dash , options . line . width ) ;
301
+ if ( options . layer !== 'below' ) {
302
+ drawShape ( gd . _fullLayout . _shapeUpperLayer ) ;
303
+ }
304
+ else if ( options . xref === 'paper' && options . yref === 'paper' ) {
305
+ drawShape ( gd . _fullLayout . _shapeLowerLayer ) ;
306
+ } else {
307
+ forEachSubplot ( gd , function ( plotinfo ) {
308
+ if ( isShapeInSubplot ( gd , options , plotinfo . id ) ) {
309
+ drawShape ( plotinfo . shapelayer ) ;
310
+ }
311
+ } ) ;
312
+ }
313
+
314
+ return ;
315
+
316
+ function drawShape ( shapeLayer ) {
317
+ var path = shapeLayer . append ( 'path' )
318
+ . attr ( attrs )
319
+ . style ( 'opacity' , options . opacity )
320
+ . call ( Plotly . Color . stroke , lineColor )
321
+ . call ( Plotly . Color . fill , options . fillcolor )
322
+ . call ( Plotly . Drawing . dashLine , options . line . dash ,
323
+ options . line . width ) ;
324
+
325
+ if ( clipAxes ) {
326
+ path . call ( Plotly . Drawing . setClipUrl ,
327
+ 'clip' + gd . _fullLayout . _uid + clipAxes ) ;
328
+ }
329
+ }
330
+ }
331
+
332
+ function getShapeLayer ( gd , index ) {
333
+ var shape = gd . _fullLayout . shapes [ index ] ,
334
+ shapeLayer = gd . _fullLayout . _shapeUpperLayer ;
335
+
336
+ if ( ! shape ) {
337
+ console . log ( 'getShapeLayer: undefined shape: index' , index ) ;
338
+ }
339
+ else if ( shape . layer === 'below' ) {
340
+ shapeLayer = ( shape . xref === 'paper' && shape . yref === 'paper' ) ?
341
+ gd . _fullLayout . _shapeLowerLayer :
342
+ gd . _fullLayout . _subplotShapeLayer ;
343
+ }
344
+
345
+ return shapeLayer ;
346
+ }
347
+
348
+ function isShapeInSubplot ( gd , shape , subplot ) {
349
+ var xa = Plotly . Axes . getFromId ( gd , subplot , 'x' ) . _id ,
350
+ ya = Plotly . Axes . getFromId ( gd , subplot , 'y' ) . _id ;
351
+ return shape . layer === 'below' && ( xa === shape . xref || ya === shape . yref ) ;
352
+ }
353
+
354
+ function forEachSubplot ( gd , fn ) {
355
+ var plots = gd . _fullLayout . _plots || { } ,
356
+ subplots = Object . getOwnPropertyNames ( plots ) ;
301
357
302
- if ( clipAxes ) {
303
- path . call ( Plotly . Drawing . setClipUrl ,
304
- 'clip' + gd . _fullLayout . _uid + clipAxes ) ;
358
+ for ( var i = 0 , n = subplots . length ; i < n ; i ++ ) {
359
+ fn ( plots [ subplots [ i ] ] ) ;
305
360
}
306
361
}
307
362
0 commit comments