@@ -1163,6 +1163,20 @@ function formatCategory(ax, out) {
1163
1163
var tt = ax . _categories [ Math . round ( out . x ) ] ;
1164
1164
if ( tt === undefined ) tt = '' ;
1165
1165
out . text = String ( tt ) ;
1166
+
1167
+ // Setup ticks and grid lines boundaries
1168
+ // at 1/2 a 'category' to the left/bottom
1169
+ if ( ax . tickson === 'boundaries' ) {
1170
+ var inbounds = function ( v ) {
1171
+ var p = ax . l2p ( v ) ;
1172
+ return p >= 0 && p <= ax . _length ? v : null ;
1173
+ } ;
1174
+
1175
+ out . xbnd = [
1176
+ inbounds ( out . x - 0.5 ) ,
1177
+ inbounds ( out . x + ax . dtick - 0.5 )
1178
+ ] ;
1179
+ }
1166
1180
}
1167
1181
1168
1182
function formatLinear ( ax , out , hover , extraPrecision , hideexp ) {
@@ -1610,14 +1624,41 @@ axes.drawOne = function(gd, ax, opts) {
1610
1624
var subplotsWithAx = axes . getSubplots ( gd , ax ) ;
1611
1625
1612
1626
var vals = ax . _vals = axes . calcTicks ( ax ) ;
1613
- // We remove zero lines, grid lines, and inside ticks if they're within 1px of the end
1614
- // The key case here is removing zero lines when the axis bound is zero
1615
- var valsClipped = ax . _valsClipped = axes . clipEnds ( ax , vals ) ;
1616
1627
1617
1628
if ( ! ax . visible ) return ;
1618
1629
1619
1630
var transFn = axes . makeTransFn ( ax ) ;
1620
1631
1632
+ // We remove zero lines, grid lines, and inside ticks if they're within 1px of the end
1633
+ // The key case here is removing zero lines when the axis bound is zero
1634
+ var valsClipped ;
1635
+ var tickVals ;
1636
+ var gridVals ;
1637
+
1638
+ if ( ax . tickson === 'boundaries' && vals . length ) {
1639
+ // valsBoundaries is not used for labels;
1640
+ // no need to worry about the other tickTextObj keys
1641
+ var valsBoundaries = [ ] ;
1642
+ var _push = function ( d , bndIndex ) {
1643
+ var xb = d . xbnd [ bndIndex ] ;
1644
+ if ( xb !== null ) {
1645
+ valsBoundaries . push ( Lib . extendFlat ( { } , d , { x : xb } ) ) ;
1646
+ }
1647
+ } ;
1648
+ for ( i = 0 ; i < vals . length ; i ++ ) _push ( vals [ i ] , 0 ) ;
1649
+ _push ( vals [ i - 1 ] , 1 ) ;
1650
+
1651
+ valsClipped = axes . clipEnds ( ax , valsBoundaries ) ;
1652
+ tickVals = ax . ticks === 'inside' ? valsClipped : valsBoundaries ;
1653
+ gridVals = valsClipped ;
1654
+ } else {
1655
+ valsClipped = axes . clipEnds ( ax , vals ) ;
1656
+ tickVals = ax . ticks === 'inside' ? valsClipped : vals ;
1657
+ gridVals = valsClipped ;
1658
+ }
1659
+
1660
+ ax . _valsClipped = valsClipped ;
1661
+
1621
1662
if ( ! fullLayout . _hasOnlyLargeSploms ) {
1622
1663
// keep track of which subplots (by main conteraxis) we've already
1623
1664
// drawn grids for, so we don't overdraw overlaying subplots
@@ -1637,7 +1678,7 @@ axes.drawOne = function(gd, ax, opts) {
1637
1678
'M' + counterAxis . _offset + ',0h' + counterAxis . _length ;
1638
1679
1639
1680
axes . drawGrid ( gd , ax , {
1640
- vals : valsClipped ,
1681
+ vals : gridVals ,
1641
1682
layer : plotinfo . gridlayer . select ( '.' + axId ) ,
1642
1683
path : gridPath ,
1643
1684
transFn : transFn
@@ -1652,7 +1693,6 @@ axes.drawOne = function(gd, ax, opts) {
1652
1693
}
1653
1694
1654
1695
var tickSigns = axes . getTickSigns ( ax ) ;
1655
- var tickVals = ax . ticks === 'inside' ? valsClipped : vals ;
1656
1696
var tickSubplots = [ ] ;
1657
1697
1658
1698
if ( ax . ticks ) {
@@ -1920,8 +1960,9 @@ axes.makeTickPath = function(ax, shift, sgn) {
1920
1960
axes . makeLabelFns = function ( ax , shift , angle ) {
1921
1961
var axLetter = ax . _id . charAt ( 0 ) ;
1922
1962
var pad = ( ax . linewidth || 1 ) / 2 ;
1963
+ var ticksOnOutsideLabels = ax . tickson !== 'boundaries' && ax . ticks === 'outside' ;
1923
1964
1924
- var labelStandoff = ax . ticks === 'outside' ? ax . ticklen : 0 ;
1965
+ var labelStandoff = ticksOnOutsideLabels ? ax . ticklen : 0 ;
1925
1966
var labelShift = 0 ;
1926
1967
1927
1968
if ( angle && ax . ticks === 'outside' ) {
@@ -1930,7 +1971,7 @@ axes.makeLabelFns = function(ax, shift, angle) {
1930
1971
labelShift = ax . ticklen * Math . sin ( rad ) ;
1931
1972
}
1932
1973
1933
- if ( ax . showticklabels && ( ax . ticks === 'outside' || ax . showline ) ) {
1974
+ if ( ax . showticklabels && ( ticksOnOutsideLabels || ax . showline ) ) {
1934
1975
labelStandoff += 0.2 * ax . tickfont . size ;
1935
1976
}
1936
1977
@@ -2018,7 +2059,6 @@ axes.drawTicks = function(gd, ax, opts) {
2018
2059
ticks . attr ( 'transform' , opts . transFn ) ;
2019
2060
} ;
2020
2061
2021
-
2022
2062
/**
2023
2063
* Draw axis grid
2024
2064
*
@@ -2151,8 +2191,6 @@ axes.drawLabels = function(gd, ax, opts) {
2151
2191
var tickLabels = opts . layer . selectAll ( 'g.' + cls )
2152
2192
. data ( ax . showticklabels ? vals : [ ] , makeDataFn ( ax ) ) ;
2153
2193
2154
- var maxFontSize = 0 ;
2155
- var autoangle = 0 ;
2156
2194
var labelsReady = [ ] ;
2157
2195
2158
2196
tickLabels . enter ( ) . append ( 'g' )
@@ -2187,10 +2225,6 @@ axes.drawLabels = function(gd, ax, opts) {
2187
2225
2188
2226
tickLabels . exit ( ) . remove ( ) ;
2189
2227
2190
- tickLabels . each ( function ( d ) {
2191
- maxFontSize = Math . max ( maxFontSize , d . fontSize ) ;
2192
- } ) ;
2193
-
2194
2228
ax . _tickLabels = tickLabels ;
2195
2229
2196
2230
// TODO ??
@@ -2273,16 +2307,20 @@ axes.drawLabels = function(gd, ax, opts) {
2273
2307
// check for auto-angling if x labels overlap
2274
2308
// don't auto-angle at all for log axes with
2275
2309
// base and digit format
2276
- if ( axLetter === 'x' && ! isNumeric ( ax . tickangle ) &&
2310
+ if ( vals . length && axLetter === 'x' && ! isNumeric ( ax . tickangle ) &&
2277
2311
( ax . type !== 'log' || String ( ax . dtick ) . charAt ( 0 ) !== 'D' )
2278
2312
) {
2313
+ var maxFontSize = 0 ;
2279
2314
var lbbArray = [ ] ;
2315
+ var i ;
2280
2316
2281
2317
tickLabels . each ( function ( d ) {
2282
2318
var s = d3 . select ( this ) ;
2283
2319
var thisLabel = s . select ( '.text-math-group' ) ;
2284
2320
if ( thisLabel . empty ( ) ) thisLabel = s . select ( 'text' ) ;
2285
2321
2322
+ maxFontSize = Math . max ( maxFontSize , d . fontSize ) ;
2323
+
2286
2324
var x = ax . l2p ( d . x ) ;
2287
2325
var bb = Drawing . bBox ( thisLabel . node ( ) ) ;
2288
2326
@@ -2298,21 +2336,38 @@ axes.drawLabels = function(gd, ax, opts) {
2298
2336
} ) ;
2299
2337
} ) ;
2300
2338
2301
- for ( var i = 0 ; i < lbbArray . length - 1 ; i ++ ) {
2302
- if ( Lib . bBoxIntersect ( lbbArray [ i ] , lbbArray [ i + 1 ] ) ) {
2303
- // any overlap at all - set 30 degrees
2304
- autoangle = 30 ;
2305
- break ;
2339
+ var autoangle = 0 ;
2340
+
2341
+ if ( ax . tickson === 'boundaries' ) {
2342
+ var gap = 2 ;
2343
+ if ( ax . ticks ) gap += ax . tickwidth / 2 ;
2344
+
2345
+ for ( i = 0 ; i < lbbArray . length ; i ++ ) {
2346
+ var xbnd = vals [ i ] . xbnd ;
2347
+ var lbb = lbbArray [ i ] ;
2348
+ if (
2349
+ ( xbnd [ 0 ] !== null && ( lbb . left - ax . l2p ( xbnd [ 0 ] ) ) < gap ) ||
2350
+ ( xbnd [ 1 ] !== null && ( ax . l2p ( xbnd [ 1 ] ) - lbb . right ) < gap )
2351
+ ) {
2352
+ autoangle = 90 ;
2353
+ break ;
2354
+ }
2355
+ }
2356
+ } else {
2357
+ var vLen = vals . length ;
2358
+ var tickSpacing = Math . abs ( ( vals [ vLen - 1 ] . x - vals [ 0 ] . x ) * ax . _m ) / ( vLen - 1 ) ;
2359
+ var fitBetweenTicks = tickSpacing < maxFontSize * 2.5 ;
2360
+
2361
+ // any overlap at all - set 30 degrees or 90 degrees
2362
+ for ( i = 0 ; i < lbbArray . length - 1 ; i ++ ) {
2363
+ if ( Lib . bBoxIntersect ( lbbArray [ i ] , lbbArray [ i + 1 ] ) ) {
2364
+ autoangle = fitBetweenTicks ? 90 : 30 ;
2365
+ break ;
2366
+ }
2306
2367
}
2307
2368
}
2308
2369
2309
2370
if ( autoangle ) {
2310
- var tickspacing = Math . abs (
2311
- ( vals [ vals . length - 1 ] . x - vals [ 0 ] . x ) * ax . _m
2312
- ) / ( vals . length - 1 ) ;
2313
- if ( tickspacing < maxFontSize * 2.5 ) {
2314
- autoangle = 90 ;
2315
- }
2316
2371
positionLabels ( tickLabels , autoangle ) ;
2317
2372
}
2318
2373
ax . _lastangle = autoangle ;
0 commit comments