@@ -72,9 +72,14 @@ function drawOne(gd, index) {
7272 var optionsIn = ( layout . annotations || [ ] ) [ index ] ,
7373 options = fullLayout . annotations [ index ] ;
7474
75+ var annClipID = 'clip' + fullLayout . _uid + '_ann' + index ;
76+
7577 // this annotation is gone - quit now after deleting it
7678 // TODO: use d3 idioms instead of deleting and redrawing every time
77- if ( ! optionsIn || options . visible === false ) return ;
79+ if ( ! optionsIn || options . visible === false ) {
80+ d3 . selectAll ( '#' + annClipID ) . remove ( ) ;
81+ return ;
82+ }
7883
7984 var xa = Axes . getFromId ( gd , options . xref ) ,
8085 ya = Axes . getFromId ( gd , options . yref ) ,
@@ -118,6 +123,18 @@ function drawOne(gd, index) {
118123 . call ( Color . stroke , options . bordercolor )
119124 . call ( Color . fill , options . bgcolor ) ;
120125
126+ var isSizeConstrained = options . width || options . height ;
127+
128+ var annTextClip = fullLayout . _defs . select ( '.clips' )
129+ . selectAll ( '#' + annClipID )
130+ . data ( isSizeConstrained ? [ 0 ] : [ ] ) ;
131+
132+ annTextClip . enter ( ) . append ( 'clipPath' )
133+ . classed ( 'annclip' , true )
134+ . attr ( 'id' , annClipID )
135+ . append ( 'rect' ) ;
136+ annTextClip . exit ( ) . remove ( ) ;
137+
121138 var font = options . font ;
122139
123140 var annText = annTextGroupInner . append ( 'text' )
@@ -144,19 +161,21 @@ function drawOne(gd, index) {
144161 // at the end, even if their position changes
145162 annText . selectAll ( 'tspan.line' ) . attr ( { y : 0 , x : 0 } ) ;
146163
147- var mathjaxGroup = annTextGroupInner . select ( '.annotation-math-group' ) ,
148- hasMathjax = ! mathjaxGroup . empty ( ) ,
149- anntextBB = Drawing . bBox (
150- ( hasMathjax ? mathjaxGroup : annText ) . node ( ) ) ,
151- annwidth = anntextBB . width ,
152- annheight = anntextBB . height ,
153- outerwidth = Math . round ( annwidth + 2 * borderfull ) ,
154- outerheight = Math . round ( annheight + 2 * borderfull ) ;
164+ var mathjaxGroup = annTextGroupInner . select ( '.annotation-math-group' ) ;
165+ var hasMathjax = ! mathjaxGroup . empty ( ) ;
166+ var anntextBB = Drawing . bBox (
167+ ( hasMathjax ? mathjaxGroup : annText ) . node ( ) ) ;
168+ var textWidth = anntextBB . width ;
169+ var textHeight = anntextBB . height ;
170+ var annWidth = options . width || textWidth ;
171+ var annHeight = options . height || textHeight ;
172+ var outerWidth = Math . round ( annWidth + 2 * borderfull ) ;
173+ var outerHeight = Math . round ( annHeight + 2 * borderfull ) ;
155174
156175
157176 // save size in the annotation object for use by autoscale
158- options . _w = annwidth ;
159- options . _h = annheight ;
177+ options . _w = annWidth ;
178+ options . _h = annHeight ;
160179
161180 function shiftFraction ( v , anchor ) {
162181 if ( anchor === 'auto' ) {
@@ -181,8 +200,8 @@ function drawOne(gd, index) {
181200 ax = Axes . getFromId ( gd , axRef ) ,
182201 dimAngle = ( textangle + ( axLetter === 'x' ? 0 : - 90 ) ) * Math . PI / 180 ,
183202 // note that these two can be either positive or negative
184- annSizeFromWidth = outerwidth * Math . cos ( dimAngle ) ,
185- annSizeFromHeight = outerheight * Math . sin ( dimAngle ) ,
203+ annSizeFromWidth = outerWidth * Math . cos ( dimAngle ) ,
204+ annSizeFromHeight = outerHeight * Math . sin ( dimAngle ) ,
186205 // but this one is the positive total size
187206 annSize = Math . abs ( annSizeFromWidth ) + Math . abs ( annSizeFromHeight ) ,
188207 anchor = options [ axLetter + 'anchor' ] ,
@@ -299,22 +318,43 @@ function drawOne(gd, index) {
299318 return ;
300319 }
301320
321+ var xShift = 0 ;
322+ var yShift = 0 ;
323+
324+ if ( options . align !== 'left' ) {
325+ xShift = ( annWidth - textWidth ) * ( options . align === 'center' ? 0.5 : 1 ) ;
326+ }
327+ if ( options . valign !== 'top' ) {
328+ yShift = ( annHeight - textHeight ) * ( options . valign === 'middle' ? 0.5 : 1 ) ;
329+ }
330+
302331 if ( hasMathjax ) {
303- mathjaxGroup . select ( 'svg' ) . attr ( { x : borderfull - 1 , y : borderfull } ) ;
332+ mathjaxGroup . select ( 'svg' ) . attr ( {
333+ x : borderfull + xShift - 1 ,
334+ y : borderfull + yShift
335+ } )
336+ . call ( Drawing . setClipUrl , isSizeConstrained ? annClipID : null ) ;
304337 }
305338 else {
306- var texty = borderfull - anntextBB . top ,
307- textx = borderfull - anntextBB . left ;
308- annText . attr ( { x : textx , y : texty } ) ;
339+ var texty = borderfull + yShift - anntextBB . top ,
340+ textx = borderfull + xShift - anntextBB . left ;
341+ annText . attr ( {
342+ x : textx ,
343+ y : texty
344+ } )
345+ . call ( Drawing . setClipUrl , isSizeConstrained ? annClipID : null ) ;
309346 annText . selectAll ( 'tspan.line' ) . attr ( { y : texty , x : textx } ) ;
310347 }
311348
349+ annTextClip . select ( 'rect' ) . call ( Drawing . setRect , borderfull , borderfull ,
350+ annWidth , annHeight ) ;
351+
312352 annTextBG . call ( Drawing . setRect , borderwidth / 2 , borderwidth / 2 ,
313- outerwidth - borderwidth , outerheight - borderwidth ) ;
353+ outerWidth - borderwidth , outerHeight - borderwidth ) ;
314354
315355 annTextGroupInner . call ( Drawing . setTranslate ,
316- Math . round ( annPosPx . x . text - outerwidth / 2 ) ,
317- Math . round ( annPosPx . y . text - outerheight / 2 ) ) ;
356+ Math . round ( annPosPx . x . text - outerWidth / 2 ) ,
357+ Math . round ( annPosPx . y . text - outerHeight / 2 ) ) ;
318358
319359 /*
320360 * rotate text and background
0 commit comments