@@ -611,8 +611,6 @@ axes.autoBin = function(data, ax, nbins, is2d) {
611
611
// in any case, set tickround to # of digits to round tick labels to,
612
612
// or codes to this effect for log and date scales
613
613
axes . calcTicks = function calcTicks ( ax ) {
614
- if ( ax . tickmode === 'array' ) return arrayTicks ( ax ) ;
615
-
616
614
var rng = ax . range . map ( ax . r2l ) ;
617
615
618
616
// calculate max number of (auto) ticks to display based on plot size
@@ -629,6 +627,11 @@ axes.calcTicks = function calcTicks(ax) {
629
627
nt = Lib . constrain ( ax . _length / minPx , 4 , 9 ) + 1 ;
630
628
}
631
629
}
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
+
632
635
axes . autoTicks ( ax , Math . abs ( rng [ 1 ] - rng [ 0 ] ) / nt ) ;
633
636
// check for a forced minimum dtick
634
637
if ( ax . _minDtick > 0 && ax . dtick < ax . _minDtick * 2 ) {
@@ -645,6 +648,10 @@ axes.calcTicks = function calcTicks(ax) {
645
648
// now figure out rounding of tick values
646
649
autoTickRound ( ax ) ;
647
650
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
+
648
655
// find the first tick
649
656
ax . _tmin = axes . tickFirst ( ax ) ;
650
657
@@ -672,11 +679,11 @@ axes.calcTicks = function calcTicks(ax) {
672
679
// show the exponent only on the last one
673
680
ax . _tmax = vals [ vals . length - 1 ] ;
674
681
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 = '' ;
680
687
ax . _inCalcTicks = true ;
681
688
682
689
var ticksOut = new Array ( vals . length ) ;
@@ -704,8 +711,17 @@ function arrayTicks(ax) {
704
711
// except with more precision to the numbers
705
712
if ( ! Array . isArray ( text ) ) text = [ ] ;
706
713
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
+
707
723
for ( i = 0 ; i < vals . length ; i ++ ) {
708
- vali = ax . d2l ( vals [ i ] ) ;
724
+ vali = tickVal2l ( vals [ i ] ) ;
709
725
if ( vali > tickMin && vali < tickMax ) {
710
726
if ( text [ i ] === undefined ) ticksOut [ j ] = axes . tickText ( ax , vali ) ;
711
727
else ticksOut [ j ] = tickTextObj ( ax , vali , String ( text [ i ] ) ) ;
@@ -1030,13 +1046,14 @@ axes.tickText = function(ax, x, hover) {
1030
1046
hideexp ,
1031
1047
arrayMode = ax . tickmode === 'array' ,
1032
1048
extraPrecision = hover || arrayMode ,
1033
- i ;
1049
+ i ,
1050
+ tickVal2l = ax . type === 'category' ? ax . d2l_noadd : ax . d2l ;
1034
1051
1035
1052
if ( arrayMode && Array . isArray ( ax . ticktext ) ) {
1036
1053
var rng = ax . range . map ( ax . r2l ) ,
1037
1054
minDiff = Math . abs ( rng [ 1 ] - rng [ 0 ] ) / 10000 ;
1038
1055
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 ;
1040
1057
}
1041
1058
if ( i < ax . ticktext . length ) {
1042
1059
out . text = String ( ax . ticktext [ i ] ) ;
@@ -1089,12 +1106,11 @@ function tickTextObj(ax, x, text) {
1089
1106
function formatDate ( ax , out , hover , extraPrecision ) {
1090
1107
var x = out . x ,
1091
1108
tr = ax . _tickround ,
1092
- trOriginal = tr ,
1093
1109
d = new Date ( x ) ,
1094
- // suffix completes the full date info, to be included
1110
+ // headPart completes the full date info, to be included
1095
1111
// with only the first tick or if any info before what's
1096
1112
// shown has changed
1097
- suffix ,
1113
+ headPart ,
1098
1114
tt ;
1099
1115
if ( hover && ax . hoverformat ) {
1100
1116
tt = modDateFormat ( ax . hoverformat , x ) ;
@@ -1113,12 +1129,12 @@ function formatDate(ax, out, hover, extraPrecision) {
1113
1129
else if ( tr === 'm' ) tt = monthFormat ( d ) ;
1114
1130
else {
1115
1131
if ( tr === 'd' ) {
1116
- if ( ! hover ) suffix = '<br>' + yearFormat ( d ) ;
1132
+ headPart = yearFormat ( d ) ;
1117
1133
1118
1134
tt = dayFormat ( d ) ;
1119
1135
}
1120
1136
else {
1121
- if ( ! hover ) suffix = '<br>' + yearMonthDayFormat ( d ) ;
1137
+ headPart = yearMonthDayFormat ( d ) ;
1122
1138
1123
1139
tt = minuteFormat ( d ) ;
1124
1140
if ( tr !== 'M' ) {
@@ -1128,17 +1144,34 @@ function formatDate(ax, out, hover, extraPrecision) {
1128
1144
. substr ( 1 ) ;
1129
1145
}
1130
1146
}
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
- }
1136
1147
}
1137
1148
}
1138
1149
}
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
+ }
1142
1175
}
1143
1176
out . text = tt ;
1144
1177
}
0 commit comments