toolkit/javascript/d3/src/scale/linear.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 d3.scale.linear = function() {
       
     2   return d3_scale_linear([0, 1], [0, 1], d3.interpolate, false);
       
     3 };
       
     4 
       
     5 function d3_scale_linear(domain, range, interpolate, clamp) {
       
     6   var output,
       
     7       input;
       
     8 
       
     9   function rescale() {
       
    10     var linear = domain.length == 2 ? d3_scale_bilinear : d3_scale_polylinear,
       
    11         uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
       
    12     output = linear(domain, range, uninterpolate, interpolate);
       
    13     input = linear(range, domain, uninterpolate, d3.interpolate);
       
    14     return scale;
       
    15   }
       
    16 
       
    17   function scale(x) {
       
    18     return output(x);
       
    19   }
       
    20 
       
    21   // Note: requires range is coercible to number!
       
    22   scale.invert = function(y) {
       
    23     return input(y);
       
    24   };
       
    25 
       
    26   scale.domain = function(x) {
       
    27     if (!arguments.length) return domain;
       
    28     domain = x.map(Number);
       
    29     return rescale();
       
    30   };
       
    31 
       
    32   scale.range = function(x) {
       
    33     if (!arguments.length) return range;
       
    34     range = x;
       
    35     return rescale();
       
    36   };
       
    37 
       
    38   scale.rangeRound = function(x) {
       
    39     return scale.range(x).interpolate(d3.interpolateRound);
       
    40   };
       
    41 
       
    42   scale.clamp = function(x) {
       
    43     if (!arguments.length) return clamp;
       
    44     clamp = x;
       
    45     return rescale();
       
    46   };
       
    47 
       
    48   scale.interpolate = function(x) {
       
    49     if (!arguments.length) return interpolate;
       
    50     interpolate = x;
       
    51     return rescale();
       
    52   };
       
    53 
       
    54   scale.ticks = function(m) {
       
    55     return d3_scale_linearTicks(domain, m);
       
    56   };
       
    57 
       
    58   scale.tickFormat = function(m) {
       
    59     return d3_scale_linearTickFormat(domain, m);
       
    60   };
       
    61 
       
    62   scale.nice = function() {
       
    63     d3_scale_nice(domain, d3_scale_linearNice);
       
    64     return rescale();
       
    65   };
       
    66 
       
    67   scale.copy = function() {
       
    68     return d3_scale_linear(domain, range, interpolate, clamp);
       
    69   };
       
    70 
       
    71   return rescale();
       
    72 };
       
    73 
       
    74 function d3_scale_linearRebind(scale, linear) {
       
    75   scale.range = d3.rebind(scale, linear.range);
       
    76   scale.rangeRound = d3.rebind(scale, linear.rangeRound);
       
    77   scale.interpolate = d3.rebind(scale, linear.interpolate);
       
    78   scale.clamp = d3.rebind(scale, linear.clamp);
       
    79   return scale;
       
    80 }
       
    81 
       
    82 function d3_scale_linearNice(dx) {
       
    83   dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
       
    84   return {
       
    85     floor: function(x) { return Math.floor(x / dx) * dx; },
       
    86     ceil: function(x) { return Math.ceil(x / dx) * dx; }
       
    87   };
       
    88 }
       
    89 
       
    90 // TODO Dates? Ugh.
       
    91 function d3_scale_linearTickRange(domain, m) {
       
    92   var extent = d3_scaleExtent(domain),
       
    93       span = extent[1] - extent[0],
       
    94       step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)),
       
    95       err = m / span * step;
       
    96 
       
    97   // Filter ticks to get closer to the desired count.
       
    98   if (err <= .15) step *= 10;
       
    99   else if (err <= .35) step *= 5;
       
   100   else if (err <= .75) step *= 2;
       
   101 
       
   102   // Round start and stop values to step interval.
       
   103   extent[0] = Math.ceil(extent[0] / step) * step;
       
   104   extent[1] = Math.floor(extent[1] / step) * step + step * .5; // inclusive
       
   105   extent[2] = step;
       
   106   return extent;
       
   107 }
       
   108 
       
   109 function d3_scale_linearTicks(domain, m) {
       
   110   return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
       
   111 }
       
   112 
       
   113 function d3_scale_linearTickFormat(domain, m) {
       
   114   return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
       
   115 }