|
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 } |