9
9
10
10
'use strict' ;
11
11
12
- var Plotly = require ( '../../plotly' ) ;
13
12
var d3 = require ( 'd3' ) ;
14
13
var isNumeric = require ( 'fast-isnumeric' ) ;
15
14
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
+
17
23
18
24
var Titles = module . exports = { } ;
19
25
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
+ */
23
30
Titles . 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
-
32
31
var fullLayout = gd . _fullLayout ,
33
32
gs = fullLayout . _size ,
34
33
axletter = title . charAt ( 0 ) ,
35
- colorbar = title . substr ( 1 , 2 ) === 'cb' ;
34
+ colorbar = ( title . substr ( 1 , 2 ) === 'cb' ) ;
36
35
37
36
var cbnum , cont , options ;
38
37
39
38
if ( colorbar ) {
40
- var uid = title . substr ( 3 ) . replace ( 'title' , '' ) ;
39
+ var uid = title . substr ( 3 ) . replace ( 'title' , '' ) ;
41
40
gd . _fullData . some ( function ( trace , i ) {
42
- if ( trace . uid === uid ) {
41
+ if ( trace . uid === uid ) {
43
42
cbnum = i ;
44
43
cont = gd . calcdata [ i ] [ 0 ] . t . cb . axis ;
45
44
return true ;
46
45
}
47
46
} ) ;
48
47
}
49
- else cont = fullLayout [ Plotly . Axes . id2name ( title . replace ( 'title' , '' ) ) ] || fullLayout ;
48
+ else cont = fullLayout [ axisIds . id2name ( title . replace ( 'title' , '' ) ) ] || fullLayout ;
50
49
51
- var prop = cont === fullLayout ? 'title' : cont . _name + '.title' ,
50
+ var prop = ( cont === fullLayout ) ? 'title' : cont . _name + '.title' ,
52
51
name = colorbar ? 'colorscale' :
53
- ( ( cont . _id || axletter ) . toUpperCase ( ) + ' axis' ) ,
52
+ ( ( cont . _id || axletter ) . toUpperCase ( ) + ' axis' ) ,
54
53
font = cont . titlefont . family ,
55
54
fontSize = cont . titlefont . size ,
56
55
fontColor = cont . titlefont . color ,
@@ -68,7 +67,7 @@ Titles.draw = function(gd, title) {
68
67
avoidTransform ;
69
68
70
69
// 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
72
71
if ( colorbar ) {
73
72
avoid . offsetLeft = gs . l ;
74
73
avoid . offsetTop = gs . t ;
@@ -86,57 +85,61 @@ Titles.draw = function(gd, title) {
86
85
if ( colorbar && cont . titleside ) {
87
86
// argh, we only make it here if the title is on top or bottom,
88
87
// 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' } ;
93
92
avoid = { } ;
94
93
95
94
// convertToTspans rotates any 'y...' by 90 degrees...
96
95
// TODO: need a better solution than this hack
97
- title = 'h' + title ;
96
+ title = 'h' + title ;
98
97
}
99
- else if ( axletter === 'x' ) {
98
+ else if ( axletter === 'x' ) {
100
99
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' ) ?
106
106
- 10 - fontSize * ( offsetBase + ( xa . showticklabels ? 1 : 0 ) ) :
107
107
ya . _length + 10 +
108
108
fontSize * ( offsetBase + ( xa . showticklabels ? 1.5 : 0.5 ) ) ) ;
109
+
109
110
options = { x : x , y : y , 'text-anchor' : 'middle' } ;
110
- if ( ! avoid . side ) { avoid . side = 'bottom' ; }
111
+ if ( ! avoid . side ) avoid . side = 'bottom' ;
111
112
}
112
- else if ( axletter === 'y' ) {
113
+ else if ( axletter === 'y' ) {
113
114
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' ) ?
119
121
xa . _length + 10 +
120
122
fontSize * ( offsetBase + ( ya . showticklabels ? 1 : 0.5 ) ) :
121
123
- 10 - fontSize * ( offsetBase + ( ya . showticklabels ? 0.5 : 0 ) ) ) ;
124
+
122
125
options = { x : x , y : y , 'text-anchor' : 'middle' } ;
123
126
transform = { rotate : '-90' , offset : 0 } ;
124
- if ( ! avoid . side ) { avoid . side = 'left' ; }
127
+ if ( ! avoid . side ) avoid . side = 'left' ;
125
128
}
126
- else {
129
+ else {
127
130
// plot title
128
131
name = 'Plot' ;
129
132
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 ;
132
135
options = { x : x , y : y , 'text-anchor' : 'middle' } ;
133
136
avoid = { } ;
134
137
}
135
138
136
139
var opacity = 1 ,
137
140
isplaceholder = false ,
138
141
txt = cont . title . trim ( ) ;
139
- if ( txt === '' ) { opacity = 0 ; }
142
+ if ( txt === '' ) opacity = 0 ;
140
143
if ( txt . match ( / C l i c k t o e n t e r .+ t i t l e / ) ) {
141
144
opacity = 0.2 ;
142
145
isplaceholder = true ;
@@ -145,20 +148,20 @@ Titles.draw = function(gd, title) {
145
148
var group ;
146
149
if ( colorbar ) {
147
150
group = d3 . select ( gd )
148
- . selectAll ( '.' + cont . _id . substr ( 1 ) + ' .cbtitle' ) ;
151
+ . selectAll ( '.' + cont . _id . substr ( 1 ) + ' .cbtitle' ) ;
149
152
// this class-to-rotate thing with convertToTspans is
150
153
// getting hackier and hackier... delete groups with the
151
154
// 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' )
155
158
. remove ( ) ;
156
159
}
157
160
else {
158
- group = fullLayout . _infolayer . selectAll ( '.g-' + title )
161
+ group = fullLayout . _infolayer . selectAll ( '.g-' + title )
159
162
. data ( [ 0 ] ) ;
160
163
group . enter ( ) . append ( 'g' )
161
- . classed ( 'g-' + title , true ) ;
164
+ . classed ( 'g-' + title , true ) ;
162
165
}
163
166
164
167
var el = group . selectAll ( 'text' )
@@ -173,36 +176,36 @@ Titles.draw = function(gd, title) {
173
176
. attr ( 'class' , title ) ;
174
177
175
178
function titleLayout ( titleEl ) {
176
- Plotly . Lib . syncOrAsync ( [ drawTitle , scootTitle ] , titleEl ) ;
179
+ Lib . syncOrAsync ( [ drawTitle , scootTitle ] , titleEl ) ;
177
180
}
178
181
179
182
function drawTitle ( titleEl ) {
180
183
titleEl . attr ( 'transform' , transform ?
181
184
'rotate(' + [ transform . rotate , options . x , options . y ] +
182
- ') translate(0, ' + transform . offset + ')' :
185
+ ') translate(0, ' + transform . offset + ')' :
183
186
null ) ;
184
187
185
188
titleEl . style ( {
186
189
'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
191
194
} )
192
195
. attr ( options )
193
- . call ( Plotly . util . convertToTspans )
196
+ . call ( svgTextUtils . convertToTspans )
194
197
. attr ( options ) ;
195
198
196
199
titleEl . selectAll ( 'tspan.line' )
197
200
. attr ( options ) ;
198
- return plots . previousPromises ( gd ) ;
201
+ return Plots . previousPromises ( gd ) ;
199
202
}
200
203
201
204
function scootTitle ( titleElIn ) {
202
205
var titleGroup = d3 . select ( titleElIn . node ( ) . parentNode ) ;
203
206
204
207
if ( avoid && avoid . selection && avoid . side && txt ) {
205
- titleGroup . attr ( 'transform' , null ) ;
208
+ titleGroup . attr ( 'transform' , null ) ;
206
209
207
210
// move toward avoid.side (= left, right, top, bottom) if needed
208
211
// can include pad (pixels, default 2)
@@ -213,10 +216,10 @@ Titles.draw = function(gd, title) {
213
216
top : 'bottom' ,
214
217
bottom : 'top'
215
218
} [ avoid . side ] ,
216
- shiftSign = ( [ 'left' , 'top' ] . indexOf ( avoid . side ) !== - 1 ) ?
219
+ shiftSign = ( [ 'left' , 'top' ] . indexOf ( avoid . side ) !== - 1 ) ?
217
220
- 1 : 1 ,
218
221
pad = isNumeric ( avoid . pad ) ? avoid . pad : 2 ,
219
- titlebb = Plotly . Drawing . bBox ( titleGroup . node ( ) ) ,
222
+ titlebb = Drawing . bBox ( titleGroup . node ( ) ) ,
220
223
paperbb = {
221
224
left : 0 ,
222
225
top : 0 ,
@@ -225,9 +228,9 @@ Titles.draw = function(gd, title) {
225
228
} ,
226
229
maxshift = colorbar ? fullLayout . width :
227
230
( paperbb [ avoid . side ] - titlebb [ avoid . side ] ) *
228
- ( ( avoid . side === 'left' || avoid . side === 'top' ) ? - 1 : 1 ) ;
231
+ ( ( avoid . side === 'left' || avoid . side === 'top' ) ? - 1 : 1 ) ;
229
232
// Prevent the title going off the paper
230
- if ( maxshift < 0 ) shift = maxshift ;
233
+ if ( maxshift < 0 ) shift = maxshift ;
231
234
else {
232
235
// so we don't have to offset each avoided element,
233
236
// give the title the opposite offset
@@ -239,16 +242,16 @@ Titles.draw = function(gd, title) {
239
242
// iterate over a set of elements (avoid.selection)
240
243
// to avoid collisions with
241
244
avoid . selection . each ( function ( ) {
242
- var avoidbb = Plotly . Drawing . bBox ( this ) ;
245
+ var avoidbb = Drawing . bBox ( this ) ;
243
246
244
- if ( Plotly . Lib . bBoxIntersect ( titlebb , avoidbb , pad ) ) {
247
+ if ( Lib . bBoxIntersect ( titlebb , avoidbb , pad ) ) {
245
248
shift = Math . max ( shift , shiftSign * (
246
249
avoidbb [ avoid . side ] - titlebb [ backside ] ) + pad ) ;
247
250
}
248
251
} ) ;
249
252
shift = Math . min ( maxshift , shift ) ;
250
253
}
251
- if ( shift > 0 || maxshift < 0 ) {
254
+ if ( shift > 0 || maxshift < 0 ) {
252
255
var shiftTemplate = {
253
256
left : [ - shift , 0 ] ,
254
257
right : [ shift , 0 ] ,
@@ -264,43 +267,44 @@ Titles.draw = function(gd, title) {
264
267
el . attr ( { 'data-unformatted' : txt } )
265
268
. call ( titleLayout ) ;
266
269
267
- var placeholderText = 'Click to enter ' + name . replace ( / \d + / , '' ) + ' title' ;
270
+ var placeholderText = 'Click to enter ' + name . replace ( / \d + / , '' ) + ' title' ;
268
271
269
- function setPlaceholder ( ) {
272
+ function setPlaceholder ( ) {
270
273
opacity = 0 ;
271
274
isplaceholder = true ;
272
275
txt = placeholderText ;
273
- fullLayout . _infolayer . select ( '.' + title )
276
+ fullLayout . _infolayer . select ( '.' + title )
274
277
. attr ( { 'data-unformatted' : txt } )
275
278
. text ( txt )
276
- . on ( 'mouseover.opacity' , function ( ) {
279
+ . on ( 'mouseover.opacity' , function ( ) {
277
280
d3 . select ( this ) . transition ( )
278
- . duration ( 100 ) . style ( 'opacity' , 1 ) ;
281
+ . duration ( 100 ) . style ( 'opacity' , 1 ) ;
279
282
} )
280
- . on ( 'mouseout.opacity' , function ( ) {
283
+ . on ( 'mouseout.opacity' , function ( ) {
281
284
d3 . select ( this ) . transition ( )
282
- . duration ( 1000 ) . style ( 'opacity' , 0 ) ;
285
+ . duration ( 1000 ) . style ( 'opacity' , 0 ) ;
283
286
} ) ;
284
287
}
285
288
286
289
if ( gd . _context . editable ) {
287
290
if ( ! txt ) setPlaceholder ( ) ;
288
291
289
- el . call ( Plotly . util . makeEditable )
290
- . on ( 'edit' , function ( text ) {
292
+ el . call ( svgTextUtils . makeEditable )
293
+ . on ( 'edit' , function ( text ) {
291
294
if ( colorbar ) {
292
295
var trace = gd . _fullData [ cbnum ] ;
293
- if ( plots . traceIs ( trace , 'markerColorscale' ) ) {
296
+ if ( Plots . traceIs ( trace , 'markerColorscale' ) ) {
294
297
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 ) ;
296
300
}
297
301
else Plotly . relayout ( gd , prop , text ) ;
298
302
} )
299
- . on ( 'cancel' , function ( ) {
303
+ . on ( 'cancel' , function ( ) {
300
304
this . text ( this . attr ( 'data-unformatted' ) )
301
305
. call ( titleLayout ) ;
302
306
} )
303
- . on ( 'input' , function ( d ) {
307
+ . on ( 'input' , function ( d ) {
304
308
this . text ( d || ' ' ) . attr ( options )
305
309
. selectAll ( 'tspan.line' )
306
310
. attr ( options ) ;
@@ -309,5 +313,5 @@ Titles.draw = function(gd, title) {
309
313
else if ( ! txt || txt . match ( / C l i c k t o e n t e r .+ t i t l e / ) ) {
310
314
el . remove ( ) ;
311
315
}
312
- el . classed ( 'js-placeholder' , isplaceholder ) ;
316
+ el . classed ( 'js-placeholder' , isplaceholder ) ;
313
317
} ;
0 commit comments