@@ -32,9 +32,11 @@ var ONESEC = constants.ONESEC;
32
32
var MINUS_SIGN = constants . MINUS_SIGN ;
33
33
var BADNUM = constants . BADNUM ;
34
34
35
- var MID_SHIFT = require ( '../../constants/alignment' ) . MID_SHIFT ;
36
- var LINE_SPACING = require ( '../../constants/alignment' ) . LINE_SPACING ;
37
- var OPPOSITE_SIDE = require ( '../../constants/alignment' ) . OPPOSITE_SIDE ;
35
+ var alignmentConstants = require ( '../../constants/alignment' ) ;
36
+ var MID_SHIFT = alignmentConstants . MID_SHIFT ;
37
+ var CAP_SHIFT = alignmentConstants . CAP_SHIFT ;
38
+ var LINE_SPACING = alignmentConstants . LINE_SPACING ;
39
+ var OPPOSITE_SIDE = alignmentConstants . OPPOSITE_SIDE ;
38
40
39
41
var axes = module . exports = { } ;
40
42
@@ -1831,7 +1833,6 @@ axes.drawOne = function(gd, ax, opts) {
1831
1833
1832
1834
if ( ax . type === 'multicategory' ) {
1833
1835
var pad = { x : 2 , y : 10 } [ axLetter ] ;
1834
- var sgn = { l : - 1 , t : - 1 , r : 1 , b : 1 } [ ax . side . charAt ( 0 ) ] ;
1835
1836
1836
1837
seq . push ( function ( ) {
1837
1838
var bboxKey = { x : 'height' , y : 'width' } [ axLetter ] ;
@@ -1845,20 +1846,24 @@ axes.drawOne = function(gd, ax, opts) {
1845
1846
repositionOnUpdate : true ,
1846
1847
secondary : true ,
1847
1848
transFn : transFn ,
1848
- labelFns : axes . makeLabelFns ( ax , mainLinePosition + standoff * sgn )
1849
+ labelFns : axes . makeLabelFns ( ax , mainLinePosition + standoff * tickSigns [ 4 ] )
1849
1850
} ) ;
1850
1851
} ) ;
1851
1852
1852
1853
seq . push ( function ( ) {
1853
- ax . _depth = sgn * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePosition ) ;
1854
+ ax . _depth = tickSigns [ 4 ] * ( getLabelLevelBbox ( 'tick2' ) [ ax . side ] - mainLinePosition ) ;
1854
1855
1855
1856
return drawDividers ( gd , ax , {
1856
1857
vals : dividerVals ,
1857
1858
layer : mainAxLayer ,
1858
- path : axes . makeTickPath ( ax , mainLinePosition , sgn , ax . _depth ) ,
1859
+ path : axes . makeTickPath ( ax , mainLinePosition , tickSigns [ 4 ] , ax . _depth ) ,
1859
1860
transFn : transFn
1860
1861
} ) ;
1861
1862
} ) ;
1863
+ } else if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
1864
+ seq . push ( function ( ) {
1865
+ ax . _depth = tickSigns [ 4 ] * ( getLabelLevelBbox ( ) [ ax . side ] - mainLinePosition ) ;
1866
+ } ) ;
1862
1867
}
1863
1868
1864
1869
var hasRangeSlider = Registry . getComponentMethod ( 'rangeslider' , 'isVisible' ) ( ax ) ;
@@ -1936,10 +1941,7 @@ axes.drawOne = function(gd, ax, opts) {
1936
1941
ax . _anchorAxis . domain [ domainIndices [ 0 ] ] ;
1937
1942
1938
1943
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 ;
1944
+ push [ s ] += approxTitleDepth ( ax ) + ( ax . title . standoff || 0 ) ;
1943
1945
}
1944
1946
1945
1947
if ( ax . mirror && ax . anchor !== 'free' ) {
@@ -2097,6 +2099,7 @@ function calcLabelLevelBbox(ax, cls) {
2097
2099
* - [1]: sign for bottom/left ticks (i.e. positive SVG direction)
2098
2100
* - [2]: sign for ticks corresponding to 'ax.side'
2099
2101
* - [3]: sign for ticks mirroring 'ax.side'
2102
+ * - [4]: sign of arrow starting at axis pointing towards margin
2100
2103
*/
2101
2104
axes . getTickSigns = function ( ax ) {
2102
2105
var axLetter = ax . _id . charAt ( 0 ) ;
@@ -2107,6 +2110,10 @@ axes.getTickSigns = function(ax) {
2107
2110
if ( ( ax . ticks !== 'inside' ) === ( axLetter === 'x' ) ) {
2108
2111
out = out . map ( function ( v ) { return - v ; } ) ;
2109
2112
}
2113
+ // independent of `ticks`; do not flip this one
2114
+ if ( ax . side ) {
2115
+ out . push ( { l : - 1 , t : - 1 , r : 1 , b : 1 } [ ax . side . charAt ( 0 ) ] ) ;
2116
+ }
2110
2117
return out ;
2111
2118
} ;
2112
2119
@@ -2699,42 +2706,84 @@ axes.getPxPosition = function(gd, ax) {
2699
2706
}
2700
2707
} ;
2701
2708
2709
+ /**
2710
+ * Approximate axis title depth (w/o computing its bounding box)
2711
+ *
2712
+ * @param {object } ax (full) axis object
2713
+ * - {string} title.text
2714
+ * - {number} title.font.size
2715
+ * - {number} title.standoff
2716
+ * @return {number } (in px)
2717
+ */
2718
+ function approxTitleDepth ( ax ) {
2719
+ var fontSize = ax . title . font . size ;
2720
+ var extraLines = ( ax . title . text . match ( svgTextUtils . BR_TAG_ALL ) || [ ] ) . length ;
2721
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2722
+ return extraLines ?
2723
+ fontSize * ( CAP_SHIFT + ( extraLines * LINE_SPACING ) ) :
2724
+ fontSize * CAP_SHIFT ;
2725
+ } else {
2726
+ return extraLines ?
2727
+ fontSize * ( extraLines + 1 ) * LINE_SPACING :
2728
+ fontSize ;
2729
+ }
2730
+ }
2731
+
2732
+ /**
2733
+ * Draw axis title, compute default standoff if necessary
2734
+ *
2735
+ * @param {DOM element } gd
2736
+ * @param {object } ax (full) axis object
2737
+ * - {string} _id
2738
+ * - {string} _name
2739
+ * - {string} side
2740
+ * - {number} title.font.size
2741
+ * - {object} _selections
2742
+ *
2743
+ * - {number} _depth
2744
+ * - {number} title.standoff
2745
+ * OR
2746
+ * - {number} linewidth
2747
+ * - {boolean} showticklabels
2748
+ */
2702
2749
function drawTitle ( gd , ax ) {
2703
2750
var fullLayout = gd . _fullLayout ;
2704
2751
var axId = ax . _id ;
2705
2752
var axLetter = axId . charAt ( 0 ) ;
2706
2753
var fontSize = ax . title . font . size ;
2707
2754
2708
2755
var titleStandoff ;
2709
- if ( ax . type === 'multicategory' ) {
2710
- titleStandoff = ax . _depth ;
2756
+
2757
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2758
+ titleStandoff = ax . _depth + ax . title . standoff + approxTitleDepth ( ax ) ;
2711
2759
} else {
2712
- var offsetBase = 1.5 ;
2713
- titleStandoff = 10 + fontSize * offsetBase + ( ax . linewidth ? ax . linewidth - 1 : 0 ) ;
2760
+ if ( ax . type === 'multicategory' ) {
2761
+ titleStandoff = ax . _depth ;
2762
+ } else {
2763
+ var offsetBase = 1.5 ;
2764
+ titleStandoff = 10 + fontSize * offsetBase + ( ax . linewidth ? ax . linewidth - 1 : 0 ) ;
2765
+ }
2766
+
2767
+ if ( axLetter === 'x' ) {
2768
+ titleStandoff += ax . side === 'top' ?
2769
+ fontSize * ( ax . showticklabels ? 1 : 0 ) :
2770
+ fontSize * ( ax . showticklabels ? 1.5 : 0.5 ) ;
2771
+ } else {
2772
+ titleStandoff += ax . side === 'right' ?
2773
+ fontSize * ( ax . showticklabels ? 1 : 0.5 ) :
2774
+ fontSize * ( ax . showticklabels ? 0.5 : 0 ) ;
2775
+ }
2714
2776
}
2715
2777
2716
2778
var pos = axes . getPxPosition ( gd , ax ) ;
2717
2779
var transform , x , y ;
2718
2780
2719
2781
if ( axLetter === 'x' ) {
2720
2782
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 ;
2783
+ y = ( ax . side === 'top' ) ? pos - titleStandoff : pos + titleStandoff ;
2728
2784
} else {
2729
2785
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
-
2786
+ x = ( ax . side === 'right' ) ? pos + titleStandoff : pos - titleStandoff ;
2738
2787
transform = { rotate : '-90' , offset : 0 } ;
2739
2788
}
2740
2789
@@ -2753,6 +2802,10 @@ function drawTitle(gd, ax) {
2753
2802
avoid . offsetLeft = translation . x ;
2754
2803
avoid . offsetTop = translation . y ;
2755
2804
}
2805
+
2806
+ if ( ax . title . hasOwnProperty ( 'standoff' ) ) {
2807
+ avoid . pad = 0 ;
2808
+ }
2756
2809
}
2757
2810
2758
2811
return Titles . draw ( gd , axId + 'title' , {
0 commit comments