99
1010'use strict' ;
1111
12- var Plotly = require ( '../../plotly' ) ;
1312var d3 = require ( 'd3' ) ;
1413var isNumeric = require ( 'fast-isnumeric' ) ;
1514
16- var plots = Plotly . Plots ;
15+ var Plotly = require ( '../../plotly' ) ;
16+ var Plots = require ( '../../plots/plots' ) ;
17+ var Lib = require ( '../../lib' ) ;
18+ var Drawing = require ( '../drawing' ) ;
19+ var Color = require ( '../color' ) ;
20+ var svgTextUtils = require ( '../../lib/svg_text_utils' ) ;
21+ var axisIds = require ( '../../plots/cartesian/axis_ids' ) ;
22+
1723
1824var Titles = module . exports = { } ;
1925
20- // titles - (re)draw titles on the axes and plot
21- // title can be 'xtitle', 'ytitle', 'gtitle',
22- // or empty to draw all
26+ /**
27+ * Titles - (re)draw titles on the axes and plot:
28+ * title can be 'xtitle', 'ytitle', 'gtitle'
29+ */
2330Titles . draw = function ( gd , title ) {
24- if ( ! title ) {
25- Plotly . Axes . listIds ( gd ) . forEach ( function ( axId ) {
26- Titles . draw ( gd , axId + 'title' ) ;
27- } ) ;
28- Titles . draw ( gd , 'gtitle' ) ;
29- return ;
30- }
31-
3231 var fullLayout = gd . _fullLayout ,
3332 gs = fullLayout . _size ,
3433 axletter = title . charAt ( 0 ) ,
35- colorbar = title . substr ( 1 , 2 ) === 'cb' ;
34+ colorbar = ( title . substr ( 1 , 2 ) === 'cb' ) ;
3635
3736 var cbnum , cont , options ;
3837
3938 if ( colorbar ) {
40- var uid = title . substr ( 3 ) . replace ( 'title' , '' ) ;
39+ var uid = title . substr ( 3 ) . replace ( 'title' , '' ) ;
4140 gd . _fullData . some ( function ( trace , i ) {
42- if ( trace . uid === uid ) {
41+ if ( trace . uid === uid ) {
4342 cbnum = i ;
4443 cont = gd . calcdata [ i ] [ 0 ] . t . cb . axis ;
4544 return true ;
4645 }
4746 } ) ;
4847 }
49- else cont = fullLayout [ Plotly . Axes . id2name ( title . replace ( 'title' , '' ) ) ] || fullLayout ;
48+ else cont = fullLayout [ axisIds . id2name ( title . replace ( 'title' , '' ) ) ] || fullLayout ;
5049
51- var prop = cont === fullLayout ? 'title' : cont . _name + '.title' ,
50+ var prop = ( cont === fullLayout ) ? 'title' : cont . _name + '.title' ,
5251 name = colorbar ? 'colorscale' :
53- ( ( cont . _id || axletter ) . toUpperCase ( ) + ' axis' ) ,
52+ ( ( cont . _id || axletter ) . toUpperCase ( ) + ' axis' ) ,
5453 font = cont . titlefont . family ,
5554 fontSize = cont . titlefont . size ,
5655 fontColor = cont . titlefont . color ,
@@ -68,7 +67,7 @@ Titles.draw = function(gd, title) {
6867 avoidTransform ;
6968
7069 // find the transform applied to the parents of the avoid selection
71- // which doesn't get picked up by Plotly. Drawing.bBox
70+ // which doesn't get picked up by Drawing.bBox
7271 if ( colorbar ) {
7372 avoid . offsetLeft = gs . l ;
7473 avoid . offsetTop = gs . t ;
@@ -86,57 +85,61 @@ Titles.draw = function(gd, title) {
8685 if ( colorbar && cont . titleside ) {
8786 // argh, we only make it here if the title is on top or bottom,
8887 // not right
89- x = gs . l + cont . titlex * gs . w ;
90- y = gs . t + ( 1 - cont . titley ) * gs . h + ( ( cont . titleside === 'top' ) ?
91- 3 + fontSize * 0.75 : - 3 - fontSize * 0.25 ) ;
92- options = { x : x , y : y , 'text-anchor' :'start' } ;
88+ x = gs . l + cont . titlex * gs . w ;
89+ y = gs . t + ( 1 - cont . titley ) * gs . h + ( ( cont . titleside === 'top' ) ?
90+ 3 + fontSize * 0.75 : - 3 - fontSize * 0.25 ) ;
91+ options = { x : x , y : y , 'text-anchor' : 'start' } ;
9392 avoid = { } ;
9493
9594 // convertToTspans rotates any 'y...' by 90 degrees...
9695 // TODO: need a better solution than this hack
97- title = 'h' + title ;
96+ title = 'h' + title ;
9897 }
99- else if ( axletter === 'x' ) {
98+ else if ( axletter === 'x' ) {
10099 xa = cont ;
101- ya = ( xa . anchor === 'free' ) ?
102- { _offset :gs . t + ( 1 - ( xa . position || 0 ) ) * gs . h , _length :0 } :
103- Plotly . Axes . getFromId ( gd , xa . anchor ) ;
104- x = xa . _offset + xa . _length / 2 ;
105- y = ya . _offset + ( ( xa . side === 'top' ) ?
100+ ya = ( xa . anchor === 'free' ) ?
101+ { _offset : gs . t + ( 1 - ( xa . position || 0 ) ) * gs . h , _length : 0 } :
102+ axisIds . getFromId ( gd , xa . anchor ) ;
103+
104+ x = xa . _offset + xa . _length / 2 ;
105+ y = ya . _offset + ( ( xa . side === 'top' ) ?
106106 - 10 - fontSize * ( offsetBase + ( xa . showticklabels ? 1 : 0 ) ) :
107107 ya . _length + 10 +
108108 fontSize * ( offsetBase + ( xa . showticklabels ? 1.5 : 0.5 ) ) ) ;
109+
109110 options = { x : x , y : y , 'text-anchor' : 'middle' } ;
110- if ( ! avoid . side ) { avoid . side = 'bottom' ; }
111+ if ( ! avoid . side ) avoid . side = 'bottom' ;
111112 }
112- else if ( axletter === 'y' ) {
113+ else if ( axletter === 'y' ) {
113114 ya = cont ;
114- xa = ( ya . anchor === 'free' ) ?
115- { _offset :gs . l + ( ya . position || 0 ) * gs . w , _length :0 } :
116- Plotly . Axes . getFromId ( gd , ya . anchor ) ;
117- y = ya . _offset + ya . _length / 2 ;
118- x = xa . _offset + ( ( ya . side === 'right' ) ?
115+ xa = ( ya . anchor === 'free' ) ?
116+ { _offset : gs . l + ( ya . position || 0 ) * gs . w , _length : 0 } :
117+ axisIds . getFromId ( gd , ya . anchor ) ;
118+
119+ y = ya . _offset + ya . _length / 2 ;
120+ x = xa . _offset + ( ( ya . side === 'right' ) ?
119121 xa . _length + 10 +
120122 fontSize * ( offsetBase + ( ya . showticklabels ? 1 : 0.5 ) ) :
121123 - 10 - fontSize * ( offsetBase + ( ya . showticklabels ? 0.5 : 0 ) ) ) ;
124+
122125 options = { x : x , y : y , 'text-anchor' : 'middle' } ;
123126 transform = { rotate : '-90' , offset : 0 } ;
124- if ( ! avoid . side ) { avoid . side = 'left' ; }
127+ if ( ! avoid . side ) avoid . side = 'left' ;
125128 }
126- else {
129+ else {
127130 // plot title
128131 name = 'Plot' ;
129132 fontSize = fullLayout . titlefont . size ;
130- x = fullLayout . width / 2 ;
131- y = fullLayout . _size . t / 2 ;
133+ x = fullLayout . width / 2 ;
134+ y = fullLayout . _size . t / 2 ;
132135 options = { x : x , y : y , 'text-anchor' : 'middle' } ;
133136 avoid = { } ;
134137 }
135138
136139 var opacity = 1 ,
137140 isplaceholder = false ,
138141 txt = cont . title . trim ( ) ;
139- if ( txt === '' ) { opacity = 0 ; }
142+ if ( txt === '' ) opacity = 0 ;
140143 if ( txt . match ( / C l i c k t o e n t e r .+ t i t l e / ) ) {
141144 opacity = 0.2 ;
142145 isplaceholder = true ;
@@ -145,20 +148,20 @@ Titles.draw = function(gd, title) {
145148 var group ;
146149 if ( colorbar ) {
147150 group = d3 . select ( gd )
148- . selectAll ( '.' + cont . _id . substr ( 1 ) + ' .cbtitle' ) ;
151+ . selectAll ( '.' + cont . _id . substr ( 1 ) + ' .cbtitle' ) ;
149152 // this class-to-rotate thing with convertToTspans is
150153 // getting hackier and hackier... delete groups with the
151154 // wrong class
152- var otherClass = title . charAt ( 0 ) === 'h' ?
153- title . substr ( 1 ) : ( 'h' + title ) ;
154- group . selectAll ( '.' + otherClass + ',.' + otherClass + '-math-group' )
155+ var otherClass = title . charAt ( 0 ) === 'h' ?
156+ title . substr ( 1 ) : ( 'h' + title ) ;
157+ group . selectAll ( '.' + otherClass + ',.' + otherClass + '-math-group' )
155158 . remove ( ) ;
156159 }
157160 else {
158- group = fullLayout . _infolayer . selectAll ( '.g-' + title )
161+ group = fullLayout . _infolayer . selectAll ( '.g-' + title )
159162 . data ( [ 0 ] ) ;
160163 group . enter ( ) . append ( 'g' )
161- . classed ( 'g-' + title , true ) ;
164+ . classed ( 'g-' + title , true ) ;
162165 }
163166
164167 var el = group . selectAll ( 'text' )
@@ -173,36 +176,36 @@ Titles.draw = function(gd, title) {
173176 . attr ( 'class' , title ) ;
174177
175178 function titleLayout ( titleEl ) {
176- Plotly . Lib . syncOrAsync ( [ drawTitle , scootTitle ] , titleEl ) ;
179+ Lib . syncOrAsync ( [ drawTitle , scootTitle ] , titleEl ) ;
177180 }
178181
179182 function drawTitle ( titleEl ) {
180183 titleEl . attr ( 'transform' , transform ?
181184 'rotate(' + [ transform . rotate , options . x , options . y ] +
182- ') translate(0, ' + transform . offset + ')' :
185+ ') translate(0, ' + transform . offset + ')' :
183186 null ) ;
184187
185188 titleEl . style ( {
186189 'font-family' : font ,
187- 'font-size' : d3 . round ( fontSize , 2 ) + 'px' ,
188- fill : Plotly . Color . rgb ( fontColor ) ,
189- opacity : opacity * Plotly . Color . opacity ( fontColor ) ,
190- 'font-weight' : plots . fontWeight
190+ 'font-size' : d3 . round ( fontSize , 2 ) + 'px' ,
191+ fill : Color . rgb ( fontColor ) ,
192+ opacity : opacity * Color . opacity ( fontColor ) ,
193+ 'font-weight' : Plots . fontWeight
191194 } )
192195 . attr ( options )
193- . call ( Plotly . util . convertToTspans )
196+ . call ( svgTextUtils . convertToTspans )
194197 . attr ( options ) ;
195198
196199 titleEl . selectAll ( 'tspan.line' )
197200 . attr ( options ) ;
198- return plots . previousPromises ( gd ) ;
201+ return Plots . previousPromises ( gd ) ;
199202 }
200203
201204 function scootTitle ( titleElIn ) {
202205 var titleGroup = d3 . select ( titleElIn . node ( ) . parentNode ) ;
203206
204207 if ( avoid && avoid . selection && avoid . side && txt ) {
205- titleGroup . attr ( 'transform' , null ) ;
208+ titleGroup . attr ( 'transform' , null ) ;
206209
207210 // move toward avoid.side (= left, right, top, bottom) if needed
208211 // can include pad (pixels, default 2)
@@ -213,10 +216,10 @@ Titles.draw = function(gd, title) {
213216 top : 'bottom' ,
214217 bottom : 'top'
215218 } [ avoid . side ] ,
216- shiftSign = ( [ 'left' , 'top' ] . indexOf ( avoid . side ) !== - 1 ) ?
219+ shiftSign = ( [ 'left' , 'top' ] . indexOf ( avoid . side ) !== - 1 ) ?
217220 - 1 : 1 ,
218221 pad = isNumeric ( avoid . pad ) ? avoid . pad : 2 ,
219- titlebb = Plotly . Drawing . bBox ( titleGroup . node ( ) ) ,
222+ titlebb = Drawing . bBox ( titleGroup . node ( ) ) ,
220223 paperbb = {
221224 left : 0 ,
222225 top : 0 ,
@@ -225,9 +228,9 @@ Titles.draw = function(gd, title) {
225228 } ,
226229 maxshift = colorbar ? fullLayout . width :
227230 ( paperbb [ avoid . side ] - titlebb [ avoid . side ] ) *
228- ( ( avoid . side === 'left' || avoid . side === 'top' ) ? - 1 : 1 ) ;
231+ ( ( avoid . side === 'left' || avoid . side === 'top' ) ? - 1 : 1 ) ;
229232 // Prevent the title going off the paper
230- if ( maxshift < 0 ) shift = maxshift ;
233+ if ( maxshift < 0 ) shift = maxshift ;
231234 else {
232235 // so we don't have to offset each avoided element,
233236 // give the title the opposite offset
@@ -239,16 +242,16 @@ Titles.draw = function(gd, title) {
239242 // iterate over a set of elements (avoid.selection)
240243 // to avoid collisions with
241244 avoid . selection . each ( function ( ) {
242- var avoidbb = Plotly . Drawing . bBox ( this ) ;
245+ var avoidbb = Drawing . bBox ( this ) ;
243246
244- if ( Plotly . Lib . bBoxIntersect ( titlebb , avoidbb , pad ) ) {
247+ if ( Lib . bBoxIntersect ( titlebb , avoidbb , pad ) ) {
245248 shift = Math . max ( shift , shiftSign * (
246249 avoidbb [ avoid . side ] - titlebb [ backside ] ) + pad ) ;
247250 }
248251 } ) ;
249252 shift = Math . min ( maxshift , shift ) ;
250253 }
251- if ( shift > 0 || maxshift < 0 ) {
254+ if ( shift > 0 || maxshift < 0 ) {
252255 var shiftTemplate = {
253256 left : [ - shift , 0 ] ,
254257 right : [ shift , 0 ] ,
@@ -264,43 +267,44 @@ Titles.draw = function(gd, title) {
264267 el . attr ( { 'data-unformatted' : txt } )
265268 . call ( titleLayout ) ;
266269
267- var placeholderText = 'Click to enter ' + name . replace ( / \d + / , '' ) + ' title' ;
270+ var placeholderText = 'Click to enter ' + name . replace ( / \d + / , '' ) + ' title' ;
268271
269- function setPlaceholder ( ) {
272+ function setPlaceholder ( ) {
270273 opacity = 0 ;
271274 isplaceholder = true ;
272275 txt = placeholderText ;
273- fullLayout . _infolayer . select ( '.' + title )
276+ fullLayout . _infolayer . select ( '.' + title )
274277 . attr ( { 'data-unformatted' : txt } )
275278 . text ( txt )
276- . on ( 'mouseover.opacity' , function ( ) {
279+ . on ( 'mouseover.opacity' , function ( ) {
277280 d3 . select ( this ) . transition ( )
278- . duration ( 100 ) . style ( 'opacity' , 1 ) ;
281+ . duration ( 100 ) . style ( 'opacity' , 1 ) ;
279282 } )
280- . on ( 'mouseout.opacity' , function ( ) {
283+ . on ( 'mouseout.opacity' , function ( ) {
281284 d3 . select ( this ) . transition ( )
282- . duration ( 1000 ) . style ( 'opacity' , 0 ) ;
285+ . duration ( 1000 ) . style ( 'opacity' , 0 ) ;
283286 } ) ;
284287 }
285288
286289 if ( gd . _context . editable ) {
287290 if ( ! txt ) setPlaceholder ( ) ;
288291
289- el . call ( Plotly . util . makeEditable )
290- . on ( 'edit' , function ( text ) {
292+ el . call ( svgTextUtils . makeEditable )
293+ . on ( 'edit' , function ( text ) {
291294 if ( colorbar ) {
292295 var trace = gd . _fullData [ cbnum ] ;
293- if ( plots . traceIs ( trace , 'markerColorscale' ) ) {
296+ if ( Plots . traceIs ( trace , 'markerColorscale' ) ) {
294297 Plotly . restyle ( gd , 'marker.colorbar.title' , text , cbnum ) ;
295- } else Plotly . restyle ( gd , 'colorbar.title' , text , cbnum ) ;
298+ }
299+ else Plotly . restyle ( gd , 'colorbar.title' , text , cbnum ) ;
296300 }
297301 else Plotly . relayout ( gd , prop , text ) ;
298302 } )
299- . on ( 'cancel' , function ( ) {
303+ . on ( 'cancel' , function ( ) {
300304 this . text ( this . attr ( 'data-unformatted' ) )
301305 . call ( titleLayout ) ;
302306 } )
303- . on ( 'input' , function ( d ) {
307+ . on ( 'input' , function ( d ) {
304308 this . text ( d || ' ' ) . attr ( options )
305309 . selectAll ( 'tspan.line' )
306310 . attr ( options ) ;
@@ -309,5 +313,5 @@ Titles.draw = function(gd, title) {
309313 else if ( ! txt || txt . match ( / C l i c k t o e n t e r .+ t i t l e / ) ) {
310314 el . remove ( ) ;
311315 }
312- el . classed ( 'js-placeholder' , isplaceholder ) ;
316+ el . classed ( 'js-placeholder' , isplaceholder ) ;
313317} ;
0 commit comments