@@ -16,6 +16,7 @@ var Plots = require('../../plots/plots');
16
16
var Axes = require ( '../../plots/cartesian/axes' ) ;
17
17
var dragElement = require ( '../dragelement' ) ;
18
18
var Lib = require ( '../../lib' ) ;
19
+ var extendFlat = require ( '../../lib/extend' ) . extendFlat ;
19
20
var setCursor = require ( '../../lib/setcursor' ) ;
20
21
var Drawing = require ( '../drawing' ) ;
21
22
var Color = require ( '../color' ) ;
@@ -52,7 +53,8 @@ module.exports = function draw(gd, id) {
52
53
opts . filllevels = null ;
53
54
54
55
function component ( ) {
55
- var fullLayout = gd . _fullLayout ;
56
+ var fullLayout = gd . _fullLayout ,
57
+ gs = fullLayout . _size ;
56
58
if ( ( typeof opts . fillcolor !== 'function' ) &&
57
59
( typeof opts . line . color !== 'function' ) ) {
58
60
fullLayout . _infolayer . selectAll ( 'g.' + id ) . remove ( ) ;
@@ -116,25 +118,25 @@ module.exports = function draw(gd, id) {
116
118
originalPlotWidth = fullLayout . width - fullLayout . margin . l - fullLayout . margin . r ,
117
119
thickPx = Math . round ( opts . thickness *
118
120
( opts . thicknessmode === 'fraction' ? originalPlotWidth : 1 ) ) ,
119
- thickFrac = thickPx / fullLayout . _size . w ,
121
+ thickFrac = thickPx / gs . w ,
120
122
lenPx = Math . round ( opts . len *
121
123
( opts . lenmode === 'fraction' ? originalPlotHeight : 1 ) ) ,
122
- lenFrac = lenPx / fullLayout . _size . h ,
123
- xpadFrac = opts . xpad / fullLayout . _size . w ,
124
+ lenFrac = lenPx / gs . h ,
125
+ xpadFrac = opts . xpad / gs . w ,
124
126
yExtraPx = ( opts . borderwidth + opts . outlinewidth ) / 2 ,
125
- ypadFrac = opts . ypad / fullLayout . _size . h ,
127
+ ypadFrac = opts . ypad / gs . h ,
126
128
127
129
// x positioning: do it initially just for left anchor,
128
130
// then fix at the end (since we don't know the width yet)
129
- xLeft = Math . round ( opts . x * fullLayout . _size . w + opts . xpad ) ,
131
+ xLeft = Math . round ( opts . x * gs . w + opts . xpad ) ,
130
132
// for dragging... this is getting a little muddled...
131
133
xLeftFrac = opts . x - thickFrac *
132
134
( { middle : 0.5 , right : 1 } [ opts . xanchor ] || 0 ) ,
133
135
134
136
// y positioning we can do correctly from the start
135
137
yBottomFrac = opts . y + lenFrac *
136
138
( ( { top : - 0.5 , bottom : 0.5 } [ opts . yanchor ] || 0 ) - 0.5 ) ,
137
- yBottomPx = Math . round ( fullLayout . _size . h * ( 1 - yBottomFrac ) ) ,
139
+ yBottomPx = Math . round ( gs . h * ( 1 - yBottomFrac ) ) ,
138
140
yTopPx = yBottomPx - lenPx ,
139
141
titleEl ,
140
142
cbAxisIn = {
@@ -243,22 +245,38 @@ module.exports = function draw(gd, id) {
243
245
s . append ( 'g' ) . classed ( 'cbtitleunshift' , true )
244
246
. append ( 'g' ) . classed ( 'cbtitle' , true ) ;
245
247
s . append ( 'rect' ) . classed ( 'cboutline' , true ) ;
248
+ s . select ( '.cbtitle' ) . datum ( 0 ) ;
246
249
} ) ;
247
- container . attr ( 'transform' , 'translate(' + Math . round ( fullLayout . _size . l ) +
248
- ',' + Math . round ( fullLayout . _size . t ) + ')' ) ;
250
+ container . attr ( 'transform' , 'translate(' + Math . round ( gs . l ) +
251
+ ',' + Math . round ( gs . t ) + ')' ) ;
249
252
// TODO: this opposite transform is a hack until we make it
250
253
// more rational which items get this offset
251
254
var titleCont = container . select ( '.cbtitleunshift' )
252
255
. attr ( 'transform' , 'translate(-' +
253
- Math . round ( fullLayout . _size . l ) + ',-' +
254
- Math . round ( fullLayout . _size . t ) + ')' ) ;
256
+ Math . round ( gs . l ) + ',-' +
257
+ Math . round ( gs . t ) + ')' ) ;
255
258
256
259
cbAxisOut . _axislayer = container . select ( '.cbaxis' ) ;
257
260
var titleHeight = 0 ;
258
261
if ( [ 'top' , 'bottom' ] . indexOf ( opts . titleside ) !== - 1 ) {
259
262
// draw the title so we know how much room it needs
260
- // when we squish the axis
261
- Titles . draw ( gd , cbAxisOut . _id + 'title' ) ;
263
+ // when we squish the axis. This one only applies to
264
+ // top or bottom titles, not right side.
265
+ var x = gs . l + ( opts . x + xpadFrac ) * gs . w ,
266
+ fontSize = cbAxisOut . titlefont . size ,
267
+ y ;
268
+
269
+ if ( opts . titleside === 'top' ) {
270
+ y = ( 1 - ( yBottomFrac + lenFrac - ypadFrac ) ) * gs . h +
271
+ gs . t + 3 + fontSize * 0.75 ;
272
+ }
273
+ else {
274
+ y = ( 1 - ( yBottomFrac + ypadFrac ) ) * gs . h +
275
+ gs . t - 3 - fontSize * 0.25 ;
276
+ }
277
+ drawTitle ( cbAxisOut . _id + 'title' , {
278
+ attributes : { x : x , y : y , 'text-anchor' : 'start' }
279
+ } ) ;
262
280
}
263
281
264
282
function drawAxis ( ) {
@@ -295,11 +313,11 @@ module.exports = function draw(gd, id) {
295
313
titleHeight += 5 ;
296
314
297
315
if ( opts . titleside === 'top' ) {
298
- cbAxisOut . domain [ 1 ] -= titleHeight / fullLayout . _size . h ;
316
+ cbAxisOut . domain [ 1 ] -= titleHeight / gs . h ;
299
317
titleTrans [ 1 ] *= - 1 ;
300
318
}
301
319
else {
302
- cbAxisOut . domain [ 0 ] += titleHeight / fullLayout . _size . h ;
320
+ cbAxisOut . domain [ 0 ] += titleHeight / gs . h ;
303
321
var nlines = Math . max ( 1 ,
304
322
titleText . selectAll ( 'tspan.line' ) . size ( ) ) ;
305
323
titleTrans [ 1 ] += ( 1 - nlines ) * lineSize ;
@@ -314,7 +332,7 @@ module.exports = function draw(gd, id) {
314
332
315
333
container . selectAll ( '.cbfills,.cblines,.cbaxis' )
316
334
. attr ( 'transform' , 'translate(0,' +
317
- Math . round ( fullLayout . _size . h * ( 1 - cbAxisOut . domain [ 1 ] ) ) + ')' ) ;
335
+ Math . round ( gs . h * ( 1 - cbAxisOut . domain [ 1 ] ) ) + ')' ) ;
318
336
319
337
var fills = container . select ( '.cbfills' )
320
338
. selectAll ( 'rect.cbfill' )
@@ -371,7 +389,67 @@ module.exports = function draw(gd, id) {
371
389
( opts . outlinewidth || 0 ) / 2 - ( opts . ticks === 'outside' ? 1 : 0 ) ;
372
390
cbAxisOut . side = 'right' ;
373
391
374
- return Axes . doTicks ( gd , cbAxisOut ) ;
392
+ // separate out axis and title drawing,
393
+ // so we don't need such complicated logic in Titles.draw
394
+ // if title is on the top or bottom, we've already drawn it
395
+ // this title call only handles side=right
396
+ return Lib . syncOrAsync ( [
397
+ function ( ) {
398
+ return Axes . doTicks ( gd , cbAxisOut , true ) ;
399
+ } ,
400
+ function ( ) {
401
+ if ( [ 'top' , 'bottom' ] . indexOf ( opts . titleside ) === - 1 ) {
402
+ var fontSize = cbAxisOut . titlefont . size ,
403
+ y = cbAxisOut . _offset + cbAxisOut . _length / 2 ,
404
+ x = gs . l + ( cbAxisOut . position || 0 ) * gs . w + ( ( cbAxisOut . side === 'right' ) ?
405
+ 10 + fontSize * ( ( cbAxisOut . showticklabels ? 1 : 0.5 ) ) :
406
+ - 10 - fontSize * ( ( cbAxisOut . showticklabels ? 0.5 : 0 ) ) ) ;
407
+
408
+ // the 'h' + is a hack to get around the fact that
409
+ // convertToTspans rotates any 'y...' class by 90 degrees.
410
+ // TODO: find a better way to control this.
411
+ drawTitle ( 'h' + cbAxisOut . _id + 'title' , {
412
+ avoid : {
413
+ selection : d3 . select ( gd ) . selectAll ( 'g.' + cbAxisOut . _id + 'tick' ) ,
414
+ side : opts . titleside ,
415
+ offsetLeft : gs . l ,
416
+ offsetTop : gs . t ,
417
+ maxShift : fullLayout . width
418
+ } ,
419
+ attributes : { x : x , y : y , 'text-anchor' : 'middle' } ,
420
+ transform : { rotate : '-90' , offset : 0 }
421
+ } ) ;
422
+ }
423
+ } ] ) ;
424
+ }
425
+
426
+ function drawTitle ( titleClass , titleOpts ) {
427
+ var trace = getTrace ( ) ,
428
+ propName ;
429
+ if ( Plots . traceIs ( trace , 'markerColorscale' ) ) {
430
+ propName = 'marker.colorbar.title' ;
431
+ }
432
+ else propName = 'colorbar.title' ;
433
+
434
+ var dfltTitleOpts = {
435
+ propContainer : cbAxisOut ,
436
+ propName : propName ,
437
+ traceIndex : trace . index ,
438
+ dfltName : 'colorscale' ,
439
+ containerGroup : container . select ( '.cbtitle' )
440
+ } ;
441
+
442
+ // this class-to-rotate thing with convertToTspans is
443
+ // getting hackier and hackier... delete groups with the
444
+ // wrong class (in case earlier the colorbar was drawn on
445
+ // a different side, I think?)
446
+ var otherClass = titleClass . charAt ( 0 ) === 'h' ?
447
+ titleClass . substr ( 1 ) : ( 'h' + titleClass ) ;
448
+ container . selectAll ( '.' + otherClass + ',.' + otherClass + '-math-group' )
449
+ . remove ( ) ;
450
+
451
+ Titles . draw ( gd , titleClass ,
452
+ extendFlat ( dfltTitleOpts , titleOpts || { } ) ) ;
375
453
}
376
454
377
455
function positionCB ( ) {
@@ -394,11 +472,11 @@ module.exports = function draw(gd, id) {
394
472
else {
395
473
// note: the formula below works for all titlesides,
396
474
// (except for top/bottom mathjax, above)
397
- // but the weird fullLayout._size .l is because the titleunshift
475
+ // but the weird gs .l is because the titleunshift
398
476
// transform gets removed by Drawing.bBox
399
477
titleWidth =
400
478
Drawing . bBox ( titleCont . node ( ) ) . right -
401
- xLeft - fullLayout . _size . l ;
479
+ xLeft - gs . l ;
402
480
}
403
481
innerWidth = Math . max ( innerWidth , titleWidth ) ;
404
482
}
@@ -435,7 +513,7 @@ module.exports = function draw(gd, id) {
435
513
var xoffset = ( { center : 0.5 , right : 1 } [ opts . xanchor ] || 0 ) *
436
514
outerwidth ;
437
515
container . attr ( 'transform' ,
438
- 'translate(' + ( fullLayout . _size . l - xoffset ) + ',' + fullLayout . _size . t + ')' ) ;
516
+ 'translate(' + ( gs . l - xoffset ) + ',' + gs . t + ')' ) ;
439
517
440
518
//auto margin adjustment
441
519
Plots . autoMargin ( gd , id , {
@@ -470,8 +548,6 @@ module.exports = function draw(gd, id) {
470
548
setCursor ( container ) ;
471
549
} ,
472
550
moveFn : function ( dx , dy ) {
473
- var gs = gd . _fullLayout . _size ;
474
-
475
551
container . attr ( 'transform' ,
476
552
t0 + ' ' + 'translate(' + dx + ',' + dy + ')' ) ;
477
553
@@ -480,33 +556,34 @@ module.exports = function draw(gd, id) {
480
556
yf = dragElement . align ( yBottomFrac - ( dy / gs . h ) , lenFrac ,
481
557
0 , 1 , opts . yanchor ) ;
482
558
483
- var csr = dragElement . cursor ( xf , yf ,
559
+ var csr = dragElement . getCursor ( xf , yf ,
484
560
opts . xanchor , opts . yanchor ) ;
485
561
setCursor ( container , csr ) ;
486
562
} ,
487
563
doneFn : function ( dragged ) {
488
564
setCursor ( container ) ;
489
565
490
566
if ( dragged && xf !== undefined && yf !== undefined ) {
491
- var idNum = id . substr ( 2 ) ,
492
- traceNum ;
493
- gd . _fullData . some ( function ( trace ) {
494
- if ( trace . uid === idNum ) {
495
- traceNum = trace . index ;
496
- return true ;
497
- }
498
- } ) ;
499
-
500
567
Plotly . restyle ( gd ,
501
568
{ 'colorbar.x' : xf , 'colorbar.y' : yf } ,
502
- traceNum ) ;
569
+ getTrace ( ) . index ) ;
503
570
}
504
571
}
505
572
} ) ;
506
573
}
507
574
return cbDone ;
508
575
}
509
576
577
+ function getTrace ( ) {
578
+ var idNum = id . substr ( 2 ) ,
579
+ i ,
580
+ trace ;
581
+ for ( i = 0 ; i < gd . _fullData . length ; i ++ ) {
582
+ trace = gd . _fullData [ i ] ;
583
+ if ( trace . uid === idNum ) return trace ;
584
+ }
585
+ }
586
+
510
587
// setter/getters for every item defined in opts
511
588
Object . keys ( opts ) . forEach ( function ( name ) {
512
589
component [ name ] = function ( v ) {
0 commit comments