1 | d3.scale.linear = function() { |
---|
2 | var domain = [0, 1], |
---|
3 | range = [0, 1], |
---|
4 | interpolate = d3.interpolate, |
---|
5 | clamp = false, |
---|
6 | 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 | return rescale(); |
---|
68 | }; |
---|
69 | |
---|
70 | function d3_scale_linearRebind(scale, linear) { |
---|
71 | scale.range = d3.rebind(scale, linear.range); |
---|
72 | scale.rangeRound = d3.rebind(scale, linear.rangeRound); |
---|
73 | scale.interpolate = d3.rebind(scale, linear.interpolate); |
---|
74 | scale.clamp = d3.rebind(scale, linear.clamp); |
---|
75 | return scale; |
---|
76 | } |
---|
77 | |
---|
78 | function d3_scale_linearNice(dx) { |
---|
79 | dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1); |
---|
80 | return { |
---|
81 | floor: function(x) { return Math.floor(x / dx) * dx; }, |
---|
82 | ceil: function(x) { return Math.ceil(x / dx) * dx; } |
---|
83 | }; |
---|
84 | } |
---|
85 | |
---|
86 | // TODO Dates? Ugh. |
---|
87 | function d3_scale_linearTickRange(domain, m) { |
---|
88 | var extent = d3_scaleExtent(domain), |
---|
89 | span = extent[1] - extent[0], |
---|
90 | step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), |
---|
91 | err = m / span * step; |
---|
92 | |
---|
93 | // Filter ticks to get closer to the desired count. |
---|
94 | if (err <= .15) step *= 10; |
---|
95 | else if (err <= .35) step *= 5; |
---|
96 | else if (err <= .75) step *= 2; |
---|
97 | |
---|
98 | // Round start and stop values to step interval. |
---|
99 | extent[0] = Math.ceil(extent[0] / step) * step; |
---|
100 | extent[1] = Math.floor(extent[1] / step) * step + step * .5; // inclusive |
---|
101 | extent[2] = step; |
---|
102 | return extent; |
---|
103 | } |
---|
104 | |
---|
105 | function d3_scale_linearTicks(domain, m) { |
---|
106 | return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); |
---|
107 | } |
---|
108 | |
---|
109 | function d3_scale_linearTickFormat(domain, m) { |
---|
110 | return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f"); |
---|
111 | } |
---|