Merge branch 'master' of https://github.com/danvk/dygraphs into option-consolidation
authorRobert Konigsberg <konigsberg@google.com>
Thu, 27 Dec 2012 16:08:15 +0000 (11:08 -0500)
committerRobert Konigsberg <konigsberg@google.com>
Thu, 27 Dec 2012 16:08:15 +0000 (11:08 -0500)
auto_tests/tests/range_tests.js
dygraph-tickers.js

index 4fcb822..c2ef95e 100644 (file)
@@ -161,3 +161,12 @@ RangeTestCase.prototype.testIncludeZeroIncludesZero = function() {
   g.updateOptions({ includeZero : false });
   assertEquals([450, 1050], g.yAxisRange(0));
 }
+
+/**
+ * Verify that very large Y ranges don't break things.
+ */ 
+RangeTestCase.prototype.testHugeRange = function() {
+  var g = new Dygraph("graph", [[0, -1e120], [1, 1e230]], { includeZero : true });
+  assertEqualsDelta(1, -1e229 / g.yAxisRange(0)[0], 0.001);
+  assertEqualsDelta(1, 1.1e230 / g.yAxisRange(0)[1], 0.001);
+}
index b340626..80eb291 100644 (file)
@@ -155,30 +155,40 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) {
       // The first spacing greater than pixelsPerYLabel is what we use.
       // TODO(danvk): version that works on a log scale.
       var kmg2 = opts("labelsKMG2");
-      var mults;
+      var mults, base;
       if (kmg2) {
-        mults = [1, 2, 4, 8];
+        mults = [1, 2, 4, 8, 16, 32, 64, 128, 256];
+        base = 16;
       } else {
-        mults = [1, 2, 5];
+        mults = [1, 2, 5, 10, 20, 50, 100];
+        base = 10;
       }
-      var scale, low_val, high_val;
-      for (i = -10; i < 50; i++) {
-        var base_scale;
-        if (kmg2) {
-          base_scale = pow(16, i);
-        } else {
-          base_scale = pow(10, i);
-        }
-        var spacing = 0;
-        for (j = 0; j < mults.length; j++) {
-          scale = base_scale * mults[j];
-          low_val = Math.floor(a / scale) * scale;
-          high_val = Math.ceil(b / scale) * scale;
-          nTicks = Math.abs(high_val - low_val) / scale;
-          spacing = pixels / nTicks;
-          // wish I could break out of both loops at once...
-          if (spacing > pixels_per_tick) break;
-        }
+
+      // Get the maximum number of permitted ticks based on the
+      // graph's pixel size and pixels_per_tick setting.
+      var max_ticks = Math.ceil(pixels / pixels_per_tick);
+
+      // Now calculate the data unit equivalent of this tick spacing.
+      // Use abs() since graphs may have a reversed Y axis.
+      var units_per_tick = Math.abs(b - a) / max_ticks;
+
+      // Based on this, get a starting scale which is the largest
+      // integer power of the chosen base (10 or 16) that still remains
+      // below the requested pixels_per_tick spacing.
+      var base_power = Math.floor(Math.log(units_per_tick) / Math.log(base));
+      var base_scale = Math.pow(base, base_power);
+
+      // Now try multiples of the starting scale until we find one
+      // that results in tick marks spaced sufficiently far apart.
+      // The "mults" array should cover the range 1 .. base^2 to
+      // adjust for rounding and edge effects.
+      var scale, low_val, high_val, nTicks, spacing;
+      for (j = 0; j < mults.length; j++) {
+        scale = base_scale * mults[j];
+        low_val = Math.floor(a / scale) * scale;
+        high_val = Math.ceil(b / scale) * scale;
+        nTicks = Math.abs(high_val - low_val) / scale;
+        spacing = pixels / nTicks;
         if (spacing > pixels_per_tick) break;
       }