@@ -611,8 +611,6 @@ axes.autoBin = function(data, ax, nbins, is2d) {
611611// in any case, set tickround to # of digits to round tick labels to,
612612// or codes to this effect for log and date scales
613613axes . calcTicks = function calcTicks ( ax ) {
614- if ( ax . tickmode === 'array' ) return arrayTicks ( ax ) ;
615-
616614 var rng = ax . range . map ( ax . r2l ) ;
617615
618616 // calculate max number of (auto) ticks to display based on plot size
@@ -629,6 +627,11 @@ axes.calcTicks = function calcTicks(ax) {
629627 nt = Lib . constrain ( ax . _length / minPx , 4 , 9 ) + 1 ;
630628 }
631629 }
630+
631+ // add a couple of extra digits for filling in ticks when we
632+ // have explicit tickvals without tick text
633+ if ( ax . tickmode === 'array' ) nt *= 100 ;
634+
632635 axes . autoTicks ( ax , Math . abs ( rng [ 1 ] - rng [ 0 ] ) / nt ) ;
633636 // check for a forced minimum dtick
634637 if ( ax . _minDtick > 0 && ax . dtick < ax . _minDtick * 2 ) {
@@ -645,6 +648,10 @@ axes.calcTicks = function calcTicks(ax) {
645648 // now figure out rounding of tick values
646649 autoTickRound ( ax ) ;
647650
651+ // now that we've figured out the auto values for formatting
652+ // in case we're missing some ticktext, we can break out for array ticks
653+ if ( ax . tickmode === 'array' ) return arrayTicks ( ax ) ;
654+
648655 // find the first tick
649656 ax . _tmin = axes . tickFirst ( ax ) ;
650657
@@ -704,8 +711,11 @@ function arrayTicks(ax) {
704711 // except with more precision to the numbers
705712 if ( ! Array . isArray ( text ) ) text = [ ] ;
706713
714+ // make sure showing ticks doesn't accidentally add new categories
715+ var tickVal2l = ax . type === 'category' ? ax . d2l_noadd : ax . d2l ;
716+
707717 for ( i = 0 ; i < vals . length ; i ++ ) {
708- vali = ax . d2l ( vals [ i ] ) ;
718+ vali = tickVal2l ( vals [ i ] ) ;
709719 if ( vali > tickMin && vali < tickMax ) {
710720 if ( text [ i ] === undefined ) ticksOut [ j ] = axes . tickText ( ax , vali ) ;
711721 else ticksOut [ j ] = tickTextObj ( ax , vali , String ( text [ i ] ) ) ;
@@ -856,7 +866,7 @@ function autoTickRound(ax) {
856866 // not necessarily *all* the information in tick0 though, if it's really odd
857867 // minimal string length for tick0: 'd' is 10, 'M' is 16, 'S' is 19
858868 // take off a leading minus (year < 0 so length is consistent)
859- var tick0ms = Lib . dateTime2ms ( ax . tick0 ) ,
869+ var tick0ms = Lib . dateTime2ms ( ax . tick0 ) || 0 ,
860870 tick0str = Lib . ms2DateTime ( tick0ms ) . replace ( / ^ - / , '' ) ,
861871 tick0len = tick0str . length ;
862872
@@ -1030,13 +1040,14 @@ axes.tickText = function(ax, x, hover) {
10301040 hideexp ,
10311041 arrayMode = ax . tickmode === 'array' ,
10321042 extraPrecision = hover || arrayMode ,
1033- i ;
1043+ i ,
1044+ tickVal2l = ax . type === 'category' ? ax . d2l_noadd : ax . d2l ;
10341045
10351046 if ( arrayMode && Array . isArray ( ax . ticktext ) ) {
10361047 var rng = ax . range . map ( ax . r2l ) ,
10371048 minDiff = Math . abs ( rng [ 1 ] - rng [ 0 ] ) / 10000 ;
10381049 for ( i = 0 ; i < ax . ticktext . length ; i ++ ) {
1039- if ( Math . abs ( x - ax . d2l ( ax . tickvals [ i ] ) ) < minDiff ) break ;
1050+ if ( Math . abs ( x - tickVal2l ( ax . tickvals [ i ] ) ) < minDiff ) break ;
10401051 }
10411052 if ( i < ax . ticktext . length ) {
10421053 out . text = String ( ax . ticktext [ i ] ) ;
@@ -1113,12 +1124,12 @@ function formatDate(ax, out, hover, extraPrecision) {
11131124 else if ( tr === 'm' ) tt = monthFormat ( d ) ;
11141125 else {
11151126 if ( tr === 'd' ) {
1116- if ( ! hover ) suffix = '<br>' + yearFormat ( d ) ;
1127+ suffix = yearFormat ( d ) ;
11171128
11181129 tt = dayFormat ( d ) ;
11191130 }
11201131 else {
1121- if ( ! hover ) suffix = '<br>' + yearMonthDayFormat ( d ) ;
1132+ suffix = yearMonthDayFormat ( d ) ;
11221133
11231134 tt = minuteFormat ( d ) ;
11241135 if ( tr !== 'M' ) {
@@ -1136,9 +1147,26 @@ function formatDate(ax, out, hover, extraPrecision) {
11361147 }
11371148 }
11381149 }
1139- if ( suffix && ( ! ax . _inCalcTicks || ( suffix !== ax . _prevSuffix ) ) ) {
1140- tt += suffix ;
1141- ax . _prevSuffix = suffix ;
1150+ if ( ax . tickmode === 'array' ) {
1151+ // we get extra precision in array mode, but it may be useless, strip it off
1152+ if ( tt === '00:00:00' ) {
1153+ tt = suffix ;
1154+ suffix = '' ;
1155+ }
1156+ else {
1157+ tt = tt . replace ( / : 0 0 $ / , '' ) ;
1158+ }
1159+ }
1160+
1161+ if ( suffix ) {
1162+ if ( hover ) {
1163+ // hover puts it all on one line, so suffix works best up front
1164+ tt = suffix + ( tt ? ' ' + tt : '' ) ;
1165+ }
1166+ else if ( ! ax . _inCalcTicks || ( suffix !== ax . _prevSuffix ) ) {
1167+ tt += '<br>' + suffix ;
1168+ ax . _prevSuffix = suffix ;
1169+ }
11421170 }
11431171 out . text = tt ;
11441172}
0 commit comments