@@ -603,7 +603,7 @@ function autoShiftMonthBins(binStart, data, dtick, dataMin, calendar) {
603603
604604// ensure we have minor tick0 and dtick calculated
605605axes . prepMinorTicks = function ( mockAx , ax , opts ) {
606- if ( ! ax . minor . dtick ) {
606+ if ( ! ax . minor ? .dtick ) {
607607 delete mockAx . dtick ;
608608 var hasMajor = ax . dtick && isNumeric ( ax . _tmin ) ;
609609 var mockMinorRange ;
@@ -690,7 +690,7 @@ axes.prepMinorTicks = function(mockAx, ax, opts) {
690690 // put back the original range, to use to find the full set of minor ticks
691691 mockAx . range = ax . range ;
692692 }
693- if ( ax . minor . _tick0Init === undefined ) {
693+ if ( ax . minor ? ._tick0Init === undefined ) {
694694 // ensure identical tick0
695695 mockAx . tick0 = ax . tick0 ;
696696 }
@@ -973,21 +973,23 @@ axes.calcTicks = function calcTicks(ax, opts) {
973973 var allTicklabelVals = [ ] ;
974974
975975 var hasMinor = ax . minor && ( ax . minor . ticks || ax . minor . showgrid ) ;
976+ // minor ticks should be calculated if they are visible or if ticklabelindex is set because then
977+ // the labels are placed at minor ticks (even if invisible) instead of major ticks.
978+ var calcMinor = hasMinor || ticklabelIndex ;
976979
977980 // calc major first
978- for ( var major = 1 ; major >= ( hasMinor ? 0 : 1 ) ; major -- ) {
981+ for ( var major = 1 ; major >= ( calcMinor ? 0 : 1 ) ; major -- ) {
979982 var isMinor = ! major ;
980983
981984 if ( major ) {
982985 ax . _dtickInit = ax . dtick ;
983986 ax . _tick0Init = ax . tick0 ;
984- } else {
987+ } else if ( calcMinor ) {
985988 ax . minor . _dtickInit = ax . minor . dtick ;
986989 ax . minor . _tick0Init = ax . minor . tick0 ;
987990 }
988991
989- var mockAx = major ? ax : Lib . extendFlat ( { } , ax , ax . minor ) ;
990-
992+ var mockAx = major ? ax : Lib . extendFlat ( { } , ax , calcMinor ? ax . minor : { "minor" : { } } ) ;
991993 if ( isMinor ) {
992994 axes . prepMinorTicks ( mockAx , ax , opts ) ;
993995 } else {
@@ -1074,10 +1076,13 @@ axes.calcTicks = function calcTicks(ax, opts) {
10741076 }
10751077 }
10761078
1077- if ( major && isPeriod ) {
1078- // add one item to label period before tick0
1079+ if ( ( major || ticklabelIndex ) && isPeriod ) {
1080+ // if major: add one item to label period before tick0
1081+ // if minor: add one item for ticklabelindex positioning. positionPeriodTicks requires
1082+ // at least 2 ticks to calculate the period length, so we add a dummy tick, ensuring
1083+ // that if a tick is labeled, there are always at least 2 ticks.
10791084 x = axes . tickIncrement ( x , dtick , ! axrev , calendar ) ;
1080- majorId -- ;
1085+ if ( major ) majorId -- ;
10811086 }
10821087
10831088 for ( ;
@@ -1125,13 +1130,17 @@ axes.calcTicks = function calcTicks(ax, opts) {
11251130 }
11261131 }
11271132
1128- // check if ticklabelIndex makes sense, otherwise ignore it
1129- if ( ! minorTickVals || minorTickVals . length < 2 ) {
1133+ // check if ticklabelIndex makes sense, otherwise ignore it.
1134+ // It makes sense if in addition to the always present dummy, there are at least 2 minor ticks
1135+ // with the required distance to each other.
1136+ if ( ! minorTickVals || minorTickVals . length < 3 ) {
11301137 ticklabelIndex = false ;
11311138 } else {
1132- var diff = ( minorTickVals [ 1 ] . value - minorTickVals [ 0 ] . value ) * ( isReversed ? - 1 : 1 ) ;
1139+ var diff = ( minorTickVals [ 2 ] . value - minorTickVals [ 1 ] . value ) * ( isReversed ? - 1 : 1 ) ;
11331140 if ( ! periodCompatibleWithTickformat ( diff , ax . tickformat ) ) {
11341141 ticklabelIndex = false ;
1142+ // remove previously added tick before tick0 for handling ticklabelindex positioning
1143+ minorTickVals = minorTickVals . slice ( 1 ) ;
11351144 }
11361145 }
11371146 // Determine for which ticks to draw labels
@@ -1169,6 +1178,9 @@ axes.calcTicks = function calcTicks(ax, opts) {
11691178 }
11701179 } ) ;
11711180 } ) ;
1181+ tickVals . forEach ( function ( tick ) {
1182+ tick . skipLabel = allTicklabelVals . indexOf ( tick ) === - 1 ;
1183+ } ) ;
11721184 }
11731185
11741186 if ( hasMinor ) {
@@ -1298,14 +1310,18 @@ axes.calcTicks = function calcTicks(ax, opts) {
12981310 } else {
12991311 lastVisibleHead = ax . _prevDateHead ;
13001312 t = setTickLabel ( ax , tickVals [ i ] ) ;
1301- if ( tickVals [ i ] . skipLabel ||
1302- ticklabelIndex && allTicklabelVals . indexOf ( tickVals [ i ] ) === - 1 ) {
1313+ if ( tickVals [ i ] . skipLabel ) {
13031314 hideLabel ( t ) ;
13041315 }
13051316
13061317 ticksOut . push ( t ) ;
13071318 }
13081319 }
1320+
1321+ if ( isPeriod && ticklabelIndex && minorTicks . length ) {
1322+ // drop very first minor tick that we added to handle ticklabelindex
1323+ minorTicks [ 0 ] . noTick = true ;
1324+ }
13091325 ticksOut = ticksOut . concat ( minorTicks ) ;
13101326
13111327 ax . _inCalcTicks = false ;
0 commit comments