|
1 d3.svg.axis = function() { |
|
2 var scale = d3.scale.linear(), |
|
3 orient = "bottom", |
|
4 tickMajorSize = 6, |
|
5 tickMinorSize = 6, |
|
6 tickEndSize = 6, |
|
7 tickPadding = 3, |
|
8 tickArguments_ = [10], |
|
9 tickFormat_, |
|
10 tickSubdivide = 0; |
|
11 |
|
12 function axis(selection) { |
|
13 selection.each(function(d, i, j) { |
|
14 var g = d3.select(this); |
|
15 |
|
16 // If selection is a transition, create subtransitions. |
|
17 var transition = selection.delay ? function(o) { |
|
18 var id = d3_transitionInheritId; |
|
19 try { |
|
20 d3_transitionInheritId = selection.id; |
|
21 return o.transition() |
|
22 .delay(selection[j][i].delay) |
|
23 .duration(selection[j][i].duration) |
|
24 .ease(selection.ease()); |
|
25 } finally { |
|
26 d3_transitionInheritId = id; |
|
27 } |
|
28 } : Object; |
|
29 |
|
30 // Ticks. |
|
31 var ticks = scale.ticks.apply(scale, tickArguments_), |
|
32 tickFormat = tickFormat_ == null ? scale.tickFormat.apply(scale, tickArguments_) : tickFormat_; |
|
33 |
|
34 // Minor ticks. |
|
35 var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), |
|
36 subtick = g.selectAll(".minor").data(subticks, String), |
|
37 subtickEnter = subtick.enter().insert("svg:line", "g").attr("class", "tick minor").style("opacity", 1e-6), |
|
38 subtickExit = transition(subtick.exit()).style("opacity", 1e-6).remove(), |
|
39 subtickUpdate = transition(subtick).style("opacity", 1); |
|
40 |
|
41 // Major ticks. |
|
42 var tick = g.selectAll("g").data(ticks, String), |
|
43 tickEnter = tick.enter().insert("svg:g", "path").style("opacity", 1e-6), |
|
44 tickExit = transition(tick.exit()).style("opacity", 1e-6).remove(), |
|
45 tickUpdate = transition(tick).style("opacity", 1), |
|
46 tickTransform; |
|
47 |
|
48 // Domain. |
|
49 var range = d3_scaleExtent(scale.range()), |
|
50 path = g.selectAll(".domain").data([0]), |
|
51 pathEnter = path.enter().append("svg:path").attr("class", "domain"), |
|
52 pathUpdate = transition(path); |
|
53 |
|
54 // Stash the new scale and grab the old scale. |
|
55 var scale0 = this.__chart__ || scale; |
|
56 this.__chart__ = scale.copy(); |
|
57 |
|
58 tickEnter.append("svg:line").attr("class", "tick"); |
|
59 tickEnter.append("svg:text"); |
|
60 tickUpdate.select("text").text(tickFormat); |
|
61 |
|
62 switch (orient) { |
|
63 case "bottom": { |
|
64 tickTransform = d3_svg_axisX; |
|
65 subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); |
|
66 tickUpdate.select("line").attr("x2", 0).attr("y2", tickMajorSize); |
|
67 tickUpdate.select("text").attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding).attr("dy", ".71em").attr("text-anchor", "middle"); |
|
68 pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); |
|
69 break; |
|
70 } |
|
71 case "top": { |
|
72 tickTransform = d3_svg_axisX; |
|
73 subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); |
|
74 tickUpdate.select("line").attr("x2", 0).attr("y2", -tickMajorSize); |
|
75 tickUpdate.select("text").attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("dy", "0em").attr("text-anchor", "middle"); |
|
76 pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); |
|
77 break; |
|
78 } |
|
79 case "left": { |
|
80 tickTransform = d3_svg_axisY; |
|
81 subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); |
|
82 tickUpdate.select("line").attr("x2", -tickMajorSize).attr("y2", 0); |
|
83 tickUpdate.select("text").attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "end"); |
|
84 pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); |
|
85 break; |
|
86 } |
|
87 case "right": { |
|
88 tickTransform = d3_svg_axisY; |
|
89 subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); |
|
90 tickUpdate.select("line").attr("x2", tickMajorSize).attr("y2", 0); |
|
91 tickUpdate.select("text").attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "start"); |
|
92 pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); |
|
93 break; |
|
94 } |
|
95 } |
|
96 |
|
97 tickEnter.call(tickTransform, scale0); |
|
98 tickUpdate.call(tickTransform, scale); |
|
99 tickExit.call(tickTransform, scale); |
|
100 |
|
101 subtickEnter.call(tickTransform, scale0); |
|
102 subtickUpdate.call(tickTransform, scale); |
|
103 subtickExit.call(tickTransform, scale); |
|
104 }); |
|
105 } |
|
106 |
|
107 axis.scale = function(x) { |
|
108 if (!arguments.length) return scale; |
|
109 scale = x; |
|
110 return axis; |
|
111 }; |
|
112 |
|
113 axis.orient = function(x) { |
|
114 if (!arguments.length) return orient; |
|
115 orient = x; |
|
116 return axis; |
|
117 }; |
|
118 |
|
119 axis.ticks = function() { |
|
120 if (!arguments.length) return tickArguments_; |
|
121 tickArguments_ = arguments; |
|
122 return axis; |
|
123 }; |
|
124 |
|
125 axis.tickFormat = function(x) { |
|
126 if (!arguments.length) return tickFormat_; |
|
127 tickFormat_ = x; |
|
128 return axis; |
|
129 }; |
|
130 |
|
131 axis.tickSize = function(x, y, z) { |
|
132 if (!arguments.length) return tickMajorSize; |
|
133 var n = arguments.length - 1; |
|
134 tickMajorSize = +x; |
|
135 tickMinorSize = n > 1 ? +y : tickMajorSize; |
|
136 tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; |
|
137 return axis; |
|
138 }; |
|
139 |
|
140 axis.tickPadding = function(x) { |
|
141 if (!arguments.length) return tickPadding; |
|
142 tickPadding = +x; |
|
143 return axis; |
|
144 }; |
|
145 |
|
146 axis.tickSubdivide = function(x) { |
|
147 if (!arguments.length) return tickSubdivide; |
|
148 tickSubdivide = +x; |
|
149 return axis; |
|
150 }; |
|
151 |
|
152 return axis; |
|
153 }; |
|
154 |
|
155 function d3_svg_axisX(selection, x) { |
|
156 selection.attr("transform", function(d) { return "translate(" + x(d) + ",0)"; }); |
|
157 } |
|
158 |
|
159 function d3_svg_axisY(selection, y) { |
|
160 selection.attr("transform", function(d) { return "translate(0," + y(d) + ")"; }); |
|
161 } |
|
162 |
|
163 function d3_svg_axisSubdivide(scale, ticks, m) { |
|
164 subticks = []; |
|
165 if (m && ticks.length > 1) { |
|
166 var extent = d3_scaleExtent(scale.domain()), |
|
167 subticks, |
|
168 i = -1, |
|
169 n = ticks.length, |
|
170 d = (ticks[1] - ticks[0]) / ++m, |
|
171 j, |
|
172 v; |
|
173 while (++i < n) { |
|
174 for (j = m; --j > 0;) { |
|
175 if ((v = +ticks[i] - j * d) >= extent[0]) { |
|
176 subticks.push(v); |
|
177 } |
|
178 } |
|
179 } |
|
180 for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) { |
|
181 subticks.push(v); |
|
182 } |
|
183 } |
|
184 return subticks; |
|
185 } |