@@ -183,22 +183,40 @@ export default class Range {
183
183
}
184
184
185
185
logarithmicScale ( yMin , yMax , base ) {
186
+ // Basic validation to avoid for loop starting at -inf.
187
+ if ( yMax <= 0 ) yMax = Math . max ( yMin , base )
188
+ if ( yMin <= 0 ) yMin = Math . min ( yMax , base )
189
+
186
190
const logs = [ ]
187
191
188
- const ticks = Math . ceil ( Math . log ( yMax ) / Math . log ( base ) ) + 1 // Get powers of base up to our max, and then one more
192
+ // Get the logarithmic range.
193
+ const logMax = Math . log ( yMax ) / Math . log ( base )
194
+ const logMin = Math . log ( yMin ) / Math . log ( base )
189
195
190
- for ( let i = 0 ; i < ticks ; i ++ ) {
191
- logs . push ( Math . pow ( base , i ) )
192
- }
196
+ // Get the exact logarithmic range.
197
+ // (This is the exact number of multiples of the base there are between yMin and yMax).
198
+ const logRange = logMax - logMin
193
199
194
- if ( yMin === 0 ) {
195
- logs . unshift ( yMin )
200
+ // Round the logarithmic range to get the number of ticks we will create.
201
+ // If the chosen min/max values are multiples of each other WRT the base, this will be neat.
202
+ // If the chosen min/max aren't, we will at least still provide USEFUL ticks.
203
+ const ticks = Math . round ( logRange )
204
+
205
+ // Get the logarithmic spacing between ticks.
206
+ const logTickSpacing = logRange / ticks
207
+
208
+ // Create as many ticks as there is range in the logs.
209
+ for ( let i = 0 , logTick = logMin ; i < ticks ; i ++ , logTick += logTickSpacing ) {
210
+ logs . push ( Math . pow ( base , logTick ) )
196
211
}
197
212
213
+ // Add a final tick at the yMax.
214
+ logs . push ( Math . pow ( base , logMax ) )
215
+
198
216
return {
199
217
result : logs ,
200
- niceMin : logs [ 0 ] ,
201
- niceMax : logs [ logs . length - 1 ]
218
+ niceMin : yMin ,
219
+ niceMax : yMax
202
220
}
203
221
}
204
222
0 commit comments