@@ -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
@@ -672,11 +679,11 @@ axes.calcTicks = function calcTicks(ax) {
672679 // show the exponent only on the last one
673680 ax . _tmax = vals [ vals . length - 1 ] ;
674681
675- // for showing date suffixes: ax._prevSuffix holds what we showed most
676- // recently. Start with it cleared and mark that we're in calcTicks (ie
677- // calculating a whole string of these so we should care what the previous
678- // suffix was!)
679- ax . _prevSuffix = '' ;
682+ // for showing the rest of a date when the main tick label is only the
683+ // latter part: ax._prevDateHead holds what we showed most recently.
684+ // Start with it cleared and mark that we're in calcTicks (ie calculating a
685+ // whole string of these so we should care what the previous date head was!)
686+ ax . _prevDateHead = '' ;
680687 ax . _inCalcTicks = true ;
681688
682689 var ticksOut = new Array ( vals . length ) ;
@@ -704,8 +711,17 @@ 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+
717+ // array ticks on log axes always show the full number
718+ // (if no explicit ticktext overrides it)
719+ if ( ax . type === 'log' && String ( ax . dtick ) . charAt ( 0 ) !== 'L' ) {
720+ ax . dtick = 'L' + Math . pow ( 10 , Math . floor ( Math . min ( ax . range [ 0 ] , ax . range [ 1 ] ) ) - 1 ) ;
721+ }
722+
707723 for ( i = 0 ; i < vals . length ; i ++ ) {
708- vali = ax . d2l ( vals [ i ] ) ;
724+ vali = tickVal2l ( vals [ i ] ) ;
709725 if ( vali > tickMin && vali < tickMax ) {
710726 if ( text [ i ] === undefined ) ticksOut [ j ] = axes . tickText ( ax , vali ) ;
711727 else ticksOut [ j ] = tickTextObj ( ax , vali , String ( text [ i ] ) ) ;
@@ -1030,13 +1046,14 @@ axes.tickText = function(ax, x, hover) {
10301046 hideexp ,
10311047 arrayMode = ax . tickmode === 'array' ,
10321048 extraPrecision = hover || arrayMode ,
1033- i ;
1049+ i ,
1050+ tickVal2l = ax . type === 'category' ? ax . d2l_noadd : ax . d2l ;
10341051
10351052 if ( arrayMode && Array . isArray ( ax . ticktext ) ) {
10361053 var rng = ax . range . map ( ax . r2l ) ,
10371054 minDiff = Math . abs ( rng [ 1 ] - rng [ 0 ] ) / 10000 ;
10381055 for ( i = 0 ; i < ax . ticktext . length ; i ++ ) {
1039- if ( Math . abs ( x - ax . d2l ( ax . tickvals [ i ] ) ) < minDiff ) break ;
1056+ if ( Math . abs ( x - tickVal2l ( ax . tickvals [ i ] ) ) < minDiff ) break ;
10401057 }
10411058 if ( i < ax . ticktext . length ) {
10421059 out . text = String ( ax . ticktext [ i ] ) ;
@@ -1089,12 +1106,11 @@ function tickTextObj(ax, x, text) {
10891106function formatDate ( ax , out , hover , extraPrecision ) {
10901107 var x = out . x ,
10911108 tr = ax . _tickround ,
1092- trOriginal = tr ,
10931109 d = new Date ( x ) ,
1094- // suffix completes the full date info, to be included
1110+ // headPart completes the full date info, to be included
10951111 // with only the first tick or if any info before what's
10961112 // shown has changed
1097- suffix ,
1113+ headPart ,
10981114 tt ;
10991115 if ( hover && ax . hoverformat ) {
11001116 tt = modDateFormat ( ax . hoverformat , x ) ;
@@ -1113,12 +1129,12 @@ function formatDate(ax, out, hover, extraPrecision) {
11131129 else if ( tr === 'm' ) tt = monthFormat ( d ) ;
11141130 else {
11151131 if ( tr === 'd' ) {
1116- if ( ! hover ) suffix = '<br>' + yearFormat ( d ) ;
1132+ headPart = yearFormat ( d ) ;
11171133
11181134 tt = dayFormat ( d ) ;
11191135 }
11201136 else {
1121- if ( ! hover ) suffix = '<br>' + yearMonthDayFormat ( d ) ;
1137+ headPart = yearMonthDayFormat ( d ) ;
11221138
11231139 tt = minuteFormat ( d ) ;
11241140 if ( tr !== 'M' ) {
@@ -1128,17 +1144,34 @@ function formatDate(ax, out, hover, extraPrecision) {
11281144 . substr ( 1 ) ;
11291145 }
11301146 }
1131- else if ( trOriginal === 'd' ) {
1132- // for hover on axes with day ticks, minuteFormat (which
1133- // only includes %H:%M) isn't enough, you want the date too
1134- tt = dayFormat ( d ) + ' ' + tt ;
1135- }
11361147 }
11371148 }
11381149 }
1139- if ( suffix && ( ! ax . _inCalcTicks || ( suffix !== ax . _prevSuffix ) ) ) {
1140- tt += suffix ;
1141- ax . _prevSuffix = suffix ;
1150+ if ( hover || ax . tickmode === 'array' ) {
1151+ // we get extra precision in array mode or hover,
1152+ // but it may be useless, strip it off
1153+ if ( tt === '00:00:00' || tt === '00:00' ) {
1154+ tt = headPart ;
1155+ headPart = '' ;
1156+ }
1157+ else if ( tt . length === 8 ) {
1158+ // strip off seconds if they're zero (zero fractional seconds
1159+ // are already omitted)
1160+ tt = tt . replace ( / : 0 0 $ / , '' ) ;
1161+ }
1162+ }
1163+
1164+ if ( headPart ) {
1165+ if ( hover ) {
1166+ // hover puts it all on one line, so headPart works best up front
1167+ // except for year headPart: turn this into "Jan 1, 2000" etc.
1168+ if ( tr === 'd' ) tt += ', ' + headPart ;
1169+ else tt = headPart + ( tt ? ', ' + tt : '' ) ;
1170+ }
1171+ else if ( ! ax . _inCalcTicks || ( headPart !== ax . _prevDateHead ) ) {
1172+ tt += '<br>' + headPart ;
1173+ ax . _prevDateHead = headPart ;
1174+ }
11421175 }
11431176 out . text = tt ;
11441177}
0 commit comments