@@ -33,6 +33,7 @@ var MINUS_SIGN = constants.MINUS_SIGN;
33
33
var BADNUM = constants . BADNUM ;
34
34
35
35
var MID_SHIFT = require ( '../../constants/alignment' ) . MID_SHIFT ;
36
+ var CAP_SHIFT = require ( '../../constants/alignment' ) . CAP_SHIFT ;
36
37
var LINE_SPACING = require ( '../../constants/alignment' ) . LINE_SPACING ;
37
38
var OPPOSITE_SIDE = require ( '../../constants/alignment' ) . OPPOSITE_SIDE ;
38
39
@@ -1859,6 +1860,11 @@ axes.drawOne = function(gd, ax, opts) {
1859
1860
transFn : transFn
1860
1861
} ) ;
1861
1862
} ) ;
1863
+ } else if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
1864
+ seq . push ( function ( ) {
1865
+ var sgn = { l : - 1 , t : - 1 , r : 1 , b : 1 } [ ax . side . charAt ( 0 ) ] ;
1866
+ ax . _depth = sgn * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePosition ) ;
1867
+ } ) ;
1862
1868
}
1863
1869
1864
1870
var hasRangeSlider = Registry . getComponentMethod ( 'rangeslider' , 'isVisible' ) ( ax ) ;
@@ -1936,10 +1942,7 @@ axes.drawOne = function(gd, ax, opts) {
1936
1942
ax . _anchorAxis . domain [ domainIndices [ 0 ] ] ;
1937
1943
1938
1944
if ( ax . title . text !== fullLayout . _dfltTitle [ axLetter ] ) {
1939
- var extraLines = ( ax . title . text . match ( svgTextUtils . BR_TAG_ALL ) || [ ] ) . length ;
1940
- push [ s ] += extraLines ?
1941
- ax . title . font . size * ( extraLines + 1 ) * LINE_SPACING :
1942
- ax . title . font . size ;
1945
+ push [ s ] += approxTitleDepth ( ax ) + ( ax . title . standoff || 0 ) ;
1943
1946
}
1944
1947
1945
1948
if ( ax . mirror && ax . anchor !== 'free' ) {
@@ -2699,42 +2702,84 @@ axes.getPxPosition = function(gd, ax) {
2699
2702
}
2700
2703
} ;
2701
2704
2705
+ /**
2706
+ * Approximate axis title depth (w/o computing its bounding box)
2707
+ *
2708
+ * @param {object } ax (full) axis object
2709
+ * - {string} title.text
2710
+ * - {number} title.font.size
2711
+ * - {number} title.standoff
2712
+ * @return {number } (in px)
2713
+ */
2714
+ function approxTitleDepth ( ax ) {
2715
+ var fontSize = ax . title . font . size ;
2716
+ var extraLines = ( ax . title . text . match ( svgTextUtils . BR_TAG_ALL ) || [ ] ) . length ;
2717
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2718
+ return extraLines ?
2719
+ fontSize * ( CAP_SHIFT + ( extraLines * LINE_SPACING ) ) :
2720
+ fontSize * CAP_SHIFT ;
2721
+ } else {
2722
+ return extraLines ?
2723
+ fontSize * ( extraLines + 1 ) * LINE_SPACING :
2724
+ fontSize ;
2725
+ }
2726
+ }
2727
+
2728
+ /**
2729
+ * Draw axis title, compute default standoff if necessary
2730
+ *
2731
+ * @param {DOM element } gd
2732
+ * @param {object } ax (full) axis object
2733
+ * - {string} _id
2734
+ * - {string} _name
2735
+ * - {string} side
2736
+ * - {number} title.font.size
2737
+ * - {object} _selections
2738
+ *
2739
+ * - {number} _depth
2740
+ * - {number} title.standoff
2741
+ * OR
2742
+ * - {number} linewidth
2743
+ * - {boolean} showticklabels
2744
+ */
2702
2745
function drawTitle ( gd , ax ) {
2703
2746
var fullLayout = gd . _fullLayout ;
2704
2747
var axId = ax . _id ;
2705
2748
var axLetter = axId . charAt ( 0 ) ;
2706
2749
var fontSize = ax . title . font . size ;
2707
2750
2708
2751
var titleStandoff ;
2709
- if ( ax . type === 'multicategory' ) {
2710
- titleStandoff = ax . _depth ;
2752
+
2753
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2754
+ titleStandoff = ax . _depth + ax . title . standoff + approxTitleDepth ( ax ) ;
2711
2755
} else {
2712
- var offsetBase = 1.5 ;
2713
- titleStandoff = 10 + fontSize * offsetBase + ( ax . linewidth ? ax . linewidth - 1 : 0 ) ;
2756
+ if ( ax . type === 'multicategory' ) {
2757
+ titleStandoff = ax . _depth ;
2758
+ } else {
2759
+ var offsetBase = 1.5 ;
2760
+ titleStandoff = 10 + fontSize * offsetBase + ( ax . linewidth ? ax . linewidth - 1 : 0 ) ;
2761
+ }
2762
+
2763
+ if ( axLetter === 'x' ) {
2764
+ titleStandoff += ax . side === 'top' ?
2765
+ fontSize * ( ax . showticklabels ? 1 : 0 ) :
2766
+ fontSize * ( ax . showticklabels ? 1.5 : 0.5 ) ;
2767
+ } else {
2768
+ titleStandoff += ax . side === 'right' ?
2769
+ fontSize * ( ax . showticklabels ? 1 : 0.5 ) :
2770
+ fontSize * ( ax . showticklabels ? 0.5 : 0 ) ;
2771
+ }
2714
2772
}
2715
2773
2716
2774
var pos = axes . getPxPosition ( gd , ax ) ;
2717
2775
var transform , x , y ;
2718
2776
2719
2777
if ( axLetter === 'x' ) {
2720
2778
x = ax . _offset + ax . _length / 2 ;
2721
-
2722
- if ( ax . side === 'top' ) {
2723
- y = - titleStandoff - fontSize * ( ax . showticklabels ? 1 : 0 ) ;
2724
- } else {
2725
- y = titleStandoff + fontSize * ( ax . showticklabels ? 1.5 : 0.5 ) ;
2726
- }
2727
- y += pos ;
2779
+ y = ( ax . side === 'top' ) ? pos - titleStandoff : pos + titleStandoff ;
2728
2780
} else {
2729
2781
y = ax . _offset + ax . _length / 2 ;
2730
-
2731
- if ( ax . side === 'right' ) {
2732
- x = titleStandoff + fontSize * ( ax . showticklabels ? 1 : 0.5 ) ;
2733
- } else {
2734
- x = - titleStandoff - fontSize * ( ax . showticklabels ? 0.5 : 0 ) ;
2735
- }
2736
- x += pos ;
2737
-
2782
+ x = ( ax . side === 'right' ) ? pos + titleStandoff : pos - titleStandoff ;
2738
2783
transform = { rotate : '-90' , offset : 0 } ;
2739
2784
}
2740
2785
@@ -2753,6 +2798,10 @@ function drawTitle(gd, ax) {
2753
2798
avoid . offsetLeft = translation . x ;
2754
2799
avoid . offsetTop = translation . y ;
2755
2800
}
2801
+
2802
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2803
+ avoid . pad = 0 ;
2804
+ }
2756
2805
}
2757
2806
2758
2807
return Titles . draw ( gd , axId + 'title' , {
0 commit comments