d3_rails 2.7.4 → 2.7.5.v2
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/README.md +16 -2
- data/lib/d3_rails/version.rb +1 -1
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/javascripts/LICENSE +12 -13
- data/vendor/assets/javascripts/chart/box.js +297 -0
- data/vendor/assets/javascripts/chart/bullet.js +237 -0
- data/vendor/assets/javascripts/chart/chart.js +1 -0
- data/vendor/assets/javascripts/chart/horizon.js +203 -0
- data/vendor/assets/javascripts/chart/qq.js +245 -0
- data/vendor/assets/javascripts/d3.chart.js +0 -0
- data/vendor/assets/javascripts/d3.geo.js +0 -0
- data/vendor/assets/javascripts/d3.geom.js +0 -0
- data/vendor/assets/javascripts/d3.js +21 -18
- data/vendor/assets/javascripts/d3.layout.js +5 -4
- data/vendor/assets/javascripts/d3.time.js +0 -0
- data/vendor/assets/javascripts/d3_chart_module.js +1 -0
- data/vendor/assets/javascripts/d3_csv.js +0 -0
- data/vendor/assets/javascripts/d3_rails.js +1 -1
- metadata +18 -12
- data/vendor/assets/javascripts/package.json +0 -33
data/.DS_Store
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -14,8 +14,8 @@ or you can use it to build dynamic pages (like jQuery).
|
|
14
14
|
|
15
15
|
# D3 Version
|
16
16
|
|
17
|
-
The current release of this gem is using **D3 v=2.7.
|
18
|
-
**Last Updated 2-
|
17
|
+
The current release of this gem is using **D3 v=2.7.5**
|
18
|
+
**Last Updated 2-21-2012**
|
19
19
|
|
20
20
|
# Included Javascripts
|
21
21
|
**minified js files are not included, since the rails asset pipeline sorta necessitates the compiling (and likely minifying) your js files for production**
|
@@ -32,6 +32,20 @@ The current release of this gem is using **D3 v=2.7.4**
|
|
32
32
|
science.lin.js
|
33
33
|
science.stats.js
|
34
34
|
|
35
|
+
# D3 charting module
|
36
|
+
|
37
|
+
** D3 charts can be be included in your rails application by including the following line in your javascripts manifest **
|
38
|
+
|
39
|
+
//= require d3_chart_module
|
40
|
+
|
41
|
+
This will include the following javascripts to your application:
|
42
|
+
|
43
|
+
box.js
|
44
|
+
bullet.js
|
45
|
+
chart.js
|
46
|
+
horizon.js
|
47
|
+
qq.js
|
48
|
+
|
35
49
|
### Installation
|
36
50
|
|
37
51
|
This gem should work out of the box. All you have to do is add the gem to your Gemfile:
|
data/lib/d3_rails/version.rb
CHANGED
data/vendor/.DS_Store
ADDED
Binary file
|
@@ -1,5 +1,5 @@
|
|
1
|
-
Copyright (c) 2010,
|
2
|
-
All rights reserved
|
1
|
+
Copyright (c) 2010, Michael Bostock
|
2
|
+
All rights reserved.
|
3
3
|
|
4
4
|
Redistribution and use in source and binary forms, with or without
|
5
5
|
modification, are permitted provided that the following conditions are met:
|
@@ -11,17 +11,16 @@ modification, are permitted provided that the following conditions are met:
|
|
11
11
|
this list of conditions and the following disclaimer in the documentation
|
12
12
|
and/or other materials provided with the distribution.
|
13
13
|
|
14
|
-
*
|
15
|
-
|
16
|
-
specific prior written permission.
|
14
|
+
* The name Michael Bostock may not be used to endorse or promote products
|
15
|
+
derived from this software without specific prior written permission.
|
17
16
|
|
18
|
-
THIS SOFTWARE IS PROVIDED BY
|
19
|
-
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
-
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
-
EVENT SHALL
|
22
|
-
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
23
|
-
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
-
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
25
|
-
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
|
21
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
22
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
24
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
26
25
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,297 @@
|
|
1
|
+
// Inspired by http://informationandvisualization.de/blog/box-plot
|
2
|
+
d3.chart.box = function() {
|
3
|
+
var width = 1,
|
4
|
+
height = 1,
|
5
|
+
duration = 0,
|
6
|
+
domain = null,
|
7
|
+
value = Number,
|
8
|
+
whiskers = d3_chart_boxWhiskers,
|
9
|
+
quartiles = d3_chart_boxQuartiles,
|
10
|
+
tickFormat = null;
|
11
|
+
|
12
|
+
// For each small multiple…
|
13
|
+
function box(g) {
|
14
|
+
g.each(function(d, i) {
|
15
|
+
d = d.map(value).sort(d3.ascending);
|
16
|
+
var g = d3.select(this),
|
17
|
+
n = d.length,
|
18
|
+
min = d[0],
|
19
|
+
max = d[n - 1];
|
20
|
+
|
21
|
+
// Compute quartiles. Must return exactly 3 elements.
|
22
|
+
var quartileData = d.quartiles = quartiles(d);
|
23
|
+
|
24
|
+
// Compute whiskers. Must return exactly 2 elements, or null.
|
25
|
+
var whiskerIndices = whiskers && whiskers.call(this, d, i),
|
26
|
+
whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; });
|
27
|
+
|
28
|
+
// Compute outliers. If no whiskers are specified, all data are "outliers".
|
29
|
+
// We compute the outliers as indices, so that we can join across transitions!
|
30
|
+
var outlierIndices = whiskerIndices
|
31
|
+
? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n))
|
32
|
+
: d3.range(n);
|
33
|
+
|
34
|
+
// Compute the new x-scale.
|
35
|
+
var x1 = d3.scale.linear()
|
36
|
+
.domain(domain && domain.call(this, d, i) || [min, max])
|
37
|
+
.range([height, 0]);
|
38
|
+
|
39
|
+
// Retrieve the old x-scale, if this is an update.
|
40
|
+
var x0 = this.__chart__ || d3.scale.linear()
|
41
|
+
.domain([0, Infinity])
|
42
|
+
.range(x1.range());
|
43
|
+
|
44
|
+
// Stash the new scale.
|
45
|
+
this.__chart__ = x1;
|
46
|
+
|
47
|
+
// Note: the box, median, and box tick elements are fixed in number,
|
48
|
+
// so we only have to handle enter and update. In contrast, the outliers
|
49
|
+
// and other elements are variable, so we need to exit them! Variable
|
50
|
+
// elements also fade in and out.
|
51
|
+
|
52
|
+
// Update center line: the vertical line spanning the whiskers.
|
53
|
+
var center = g.selectAll("line.center")
|
54
|
+
.data(whiskerData ? [whiskerData] : []);
|
55
|
+
|
56
|
+
center.enter().insert("svg:line", "rect")
|
57
|
+
.attr("class", "center")
|
58
|
+
.attr("x1", width / 2)
|
59
|
+
.attr("y1", function(d) { return x0(d[0]); })
|
60
|
+
.attr("x2", width / 2)
|
61
|
+
.attr("y2", function(d) { return x0(d[1]); })
|
62
|
+
.style("opacity", 1e-6)
|
63
|
+
.transition()
|
64
|
+
.duration(duration)
|
65
|
+
.style("opacity", 1)
|
66
|
+
.attr("y1", function(d) { return x1(d[0]); })
|
67
|
+
.attr("y2", function(d) { return x1(d[1]); });
|
68
|
+
|
69
|
+
center.transition()
|
70
|
+
.duration(duration)
|
71
|
+
.style("opacity", 1)
|
72
|
+
.attr("y1", function(d) { return x1(d[0]); })
|
73
|
+
.attr("y2", function(d) { return x1(d[1]); });
|
74
|
+
|
75
|
+
center.exit().transition()
|
76
|
+
.duration(duration)
|
77
|
+
.style("opacity", 1e-6)
|
78
|
+
.attr("y1", function(d) { return x1(d[0]); })
|
79
|
+
.attr("y2", function(d) { return x1(d[1]); })
|
80
|
+
.remove();
|
81
|
+
|
82
|
+
// Update innerquartile box.
|
83
|
+
var box = g.selectAll("rect.box")
|
84
|
+
.data([quartileData]);
|
85
|
+
|
86
|
+
box.enter().append("svg:rect")
|
87
|
+
.attr("class", "box")
|
88
|
+
.attr("x", 0)
|
89
|
+
.attr("y", function(d) { return x0(d[2]); })
|
90
|
+
.attr("width", width)
|
91
|
+
.attr("height", function(d) { return x0(d[0]) - x0(d[2]); })
|
92
|
+
.transition()
|
93
|
+
.duration(duration)
|
94
|
+
.attr("y", function(d) { return x1(d[2]); })
|
95
|
+
.attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
|
96
|
+
|
97
|
+
box.transition()
|
98
|
+
.duration(duration)
|
99
|
+
.attr("y", function(d) { return x1(d[2]); })
|
100
|
+
.attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
|
101
|
+
|
102
|
+
// Update median line.
|
103
|
+
var medianLine = g.selectAll("line.median")
|
104
|
+
.data([quartileData[1]]);
|
105
|
+
|
106
|
+
medianLine.enter().append("svg:line")
|
107
|
+
.attr("class", "median")
|
108
|
+
.attr("x1", 0)
|
109
|
+
.attr("y1", x0)
|
110
|
+
.attr("x2", width)
|
111
|
+
.attr("y2", x0)
|
112
|
+
.transition()
|
113
|
+
.duration(duration)
|
114
|
+
.attr("y1", x1)
|
115
|
+
.attr("y2", x1);
|
116
|
+
|
117
|
+
medianLine.transition()
|
118
|
+
.duration(duration)
|
119
|
+
.attr("y1", x1)
|
120
|
+
.attr("y2", x1);
|
121
|
+
|
122
|
+
// Update whiskers.
|
123
|
+
var whisker = g.selectAll("line.whisker")
|
124
|
+
.data(whiskerData || []);
|
125
|
+
|
126
|
+
whisker.enter().insert("svg:line", "circle, text")
|
127
|
+
.attr("class", "whisker")
|
128
|
+
.attr("x1", 0)
|
129
|
+
.attr("y1", x0)
|
130
|
+
.attr("x2", width)
|
131
|
+
.attr("y2", x0)
|
132
|
+
.style("opacity", 1e-6)
|
133
|
+
.transition()
|
134
|
+
.duration(duration)
|
135
|
+
.attr("y1", x1)
|
136
|
+
.attr("y2", x1)
|
137
|
+
.style("opacity", 1);
|
138
|
+
|
139
|
+
whisker.transition()
|
140
|
+
.duration(duration)
|
141
|
+
.attr("y1", x1)
|
142
|
+
.attr("y2", x1)
|
143
|
+
.style("opacity", 1);
|
144
|
+
|
145
|
+
whisker.exit().transition()
|
146
|
+
.duration(duration)
|
147
|
+
.attr("y1", x1)
|
148
|
+
.attr("y2", x1)
|
149
|
+
.style("opacity", 1e-6)
|
150
|
+
.remove();
|
151
|
+
|
152
|
+
// Update outliers.
|
153
|
+
var outlier = g.selectAll("circle.outlier")
|
154
|
+
.data(outlierIndices, Number);
|
155
|
+
|
156
|
+
outlier.enter().insert("svg:circle", "text")
|
157
|
+
.attr("class", "outlier")
|
158
|
+
.attr("r", 5)
|
159
|
+
.attr("cx", width / 2)
|
160
|
+
.attr("cy", function(i) { return x0(d[i]); })
|
161
|
+
.style("opacity", 1e-6)
|
162
|
+
.transition()
|
163
|
+
.duration(duration)
|
164
|
+
.attr("cy", function(i) { return x1(d[i]); })
|
165
|
+
.style("opacity", 1);
|
166
|
+
|
167
|
+
outlier.transition()
|
168
|
+
.duration(duration)
|
169
|
+
.attr("cy", function(i) { return x1(d[i]); })
|
170
|
+
.style("opacity", 1);
|
171
|
+
|
172
|
+
outlier.exit().transition()
|
173
|
+
.duration(duration)
|
174
|
+
.attr("cy", function(i) { return x1(d[i]); })
|
175
|
+
.style("opacity", 1e-6)
|
176
|
+
.remove();
|
177
|
+
|
178
|
+
// Compute the tick format.
|
179
|
+
var format = tickFormat || x1.tickFormat(8);
|
180
|
+
|
181
|
+
// Update box ticks.
|
182
|
+
var boxTick = g.selectAll("text.box")
|
183
|
+
.data(quartileData);
|
184
|
+
|
185
|
+
boxTick.enter().append("svg:text")
|
186
|
+
.attr("class", "box")
|
187
|
+
.attr("dy", ".3em")
|
188
|
+
.attr("dx", function(d, i) { return i & 1 ? 6 : -6 })
|
189
|
+
.attr("x", function(d, i) { return i & 1 ? width : 0 })
|
190
|
+
.attr("y", x0)
|
191
|
+
.attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; })
|
192
|
+
.text(format)
|
193
|
+
.transition()
|
194
|
+
.duration(duration)
|
195
|
+
.attr("y", x1);
|
196
|
+
|
197
|
+
boxTick.transition()
|
198
|
+
.duration(duration)
|
199
|
+
.text(format)
|
200
|
+
.attr("y", x1);
|
201
|
+
|
202
|
+
// Update whisker ticks. These are handled separately from the box
|
203
|
+
// ticks because they may or may not exist, and we want don't want
|
204
|
+
// to join box ticks pre-transition with whisker ticks post-.
|
205
|
+
var whiskerTick = g.selectAll("text.whisker")
|
206
|
+
.data(whiskerData || []);
|
207
|
+
|
208
|
+
whiskerTick.enter().append("svg:text")
|
209
|
+
.attr("class", "whisker")
|
210
|
+
.attr("dy", ".3em")
|
211
|
+
.attr("dx", 6)
|
212
|
+
.attr("x", width)
|
213
|
+
.attr("y", x0)
|
214
|
+
.text(format)
|
215
|
+
.style("opacity", 1e-6)
|
216
|
+
.transition()
|
217
|
+
.duration(duration)
|
218
|
+
.attr("y", x1)
|
219
|
+
.style("opacity", 1);
|
220
|
+
|
221
|
+
whiskerTick.transition()
|
222
|
+
.duration(duration)
|
223
|
+
.text(format)
|
224
|
+
.attr("y", x1)
|
225
|
+
.style("opacity", 1);
|
226
|
+
|
227
|
+
whiskerTick.exit().transition()
|
228
|
+
.duration(duration)
|
229
|
+
.attr("y", x1)
|
230
|
+
.style("opacity", 1e-6)
|
231
|
+
.remove();
|
232
|
+
});
|
233
|
+
d3.timer.flush();
|
234
|
+
}
|
235
|
+
|
236
|
+
box.width = function(x) {
|
237
|
+
if (!arguments.length) return width;
|
238
|
+
width = x;
|
239
|
+
return box;
|
240
|
+
};
|
241
|
+
|
242
|
+
box.height = function(x) {
|
243
|
+
if (!arguments.length) return height;
|
244
|
+
height = x;
|
245
|
+
return box;
|
246
|
+
};
|
247
|
+
|
248
|
+
box.tickFormat = function(x) {
|
249
|
+
if (!arguments.length) return tickFormat;
|
250
|
+
tickFormat = x;
|
251
|
+
return box;
|
252
|
+
};
|
253
|
+
|
254
|
+
box.duration = function(x) {
|
255
|
+
if (!arguments.length) return duration;
|
256
|
+
duration = x;
|
257
|
+
return box;
|
258
|
+
};
|
259
|
+
|
260
|
+
box.domain = function(x) {
|
261
|
+
if (!arguments.length) return domain;
|
262
|
+
domain = x == null ? x : d3.functor(x);
|
263
|
+
return box;
|
264
|
+
};
|
265
|
+
|
266
|
+
box.value = function(x) {
|
267
|
+
if (!arguments.length) return value;
|
268
|
+
value = x;
|
269
|
+
return box;
|
270
|
+
};
|
271
|
+
|
272
|
+
box.whiskers = function(x) {
|
273
|
+
if (!arguments.length) return whiskers;
|
274
|
+
whiskers = x;
|
275
|
+
return box;
|
276
|
+
};
|
277
|
+
|
278
|
+
box.quartiles = function(x) {
|
279
|
+
if (!arguments.length) return quartiles;
|
280
|
+
quartiles = x;
|
281
|
+
return box;
|
282
|
+
};
|
283
|
+
|
284
|
+
return box;
|
285
|
+
};
|
286
|
+
|
287
|
+
function d3_chart_boxWhiskers(d) {
|
288
|
+
return [0, d.length - 1];
|
289
|
+
}
|
290
|
+
|
291
|
+
function d3_chart_boxQuartiles(d) {
|
292
|
+
return [
|
293
|
+
d3.quantile(d, .25),
|
294
|
+
d3.quantile(d, .5),
|
295
|
+
d3.quantile(d, .75)
|
296
|
+
];
|
297
|
+
}
|
@@ -0,0 +1,237 @@
|
|
1
|
+
// Chart design based on the recommendations of Stephen Few. Implementation
|
2
|
+
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
|
3
|
+
// http://projects.instantcognition.com/protovis/bulletchart/
|
4
|
+
d3.chart.bullet = function() {
|
5
|
+
var orient = "left", // TODO top & bottom
|
6
|
+
reverse = false,
|
7
|
+
duration = 0,
|
8
|
+
ranges = d3_chart_bulletRanges,
|
9
|
+
markers = d3_chart_bulletMarkers,
|
10
|
+
measures = d3_chart_bulletMeasures,
|
11
|
+
width = 380,
|
12
|
+
height = 30,
|
13
|
+
tickFormat = null;
|
14
|
+
|
15
|
+
// For each small multiple…
|
16
|
+
function bullet(g) {
|
17
|
+
g.each(function(d, i) {
|
18
|
+
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
|
19
|
+
markerz = markers.call(this, d, i).slice().sort(d3.descending),
|
20
|
+
measurez = measures.call(this, d, i).slice().sort(d3.descending),
|
21
|
+
g = d3.select(this);
|
22
|
+
|
23
|
+
// Compute the new x-scale.
|
24
|
+
var x1 = d3.scale.linear()
|
25
|
+
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
|
26
|
+
.range(reverse ? [width, 0] : [0, width]);
|
27
|
+
|
28
|
+
// Retrieve the old x-scale, if this is an update.
|
29
|
+
var x0 = this.__chart__ || d3.scale.linear()
|
30
|
+
.domain([0, Infinity])
|
31
|
+
.range(x1.range());
|
32
|
+
|
33
|
+
// Stash the new scale.
|
34
|
+
this.__chart__ = x1;
|
35
|
+
|
36
|
+
// Derive width-scales from the x-scales.
|
37
|
+
var w0 = d3_chart_bulletWidth(x0),
|
38
|
+
w1 = d3_chart_bulletWidth(x1);
|
39
|
+
|
40
|
+
// Update the range rects.
|
41
|
+
var range = g.selectAll("rect.range")
|
42
|
+
.data(rangez);
|
43
|
+
|
44
|
+
range.enter().append("svg:rect")
|
45
|
+
.attr("class", function(d, i) { return "range s" + i; })
|
46
|
+
.attr("width", w0)
|
47
|
+
.attr("height", height)
|
48
|
+
.attr("x", reverse ? x0 : 0)
|
49
|
+
.transition()
|
50
|
+
.duration(duration)
|
51
|
+
.attr("width", w1)
|
52
|
+
.attr("x", reverse ? x1 : 0);
|
53
|
+
|
54
|
+
range.transition()
|
55
|
+
.duration(duration)
|
56
|
+
.attr("x", reverse ? x1 : 0)
|
57
|
+
.attr("width", w1)
|
58
|
+
.attr("height", height);
|
59
|
+
|
60
|
+
// Update the measure rects.
|
61
|
+
var measure = g.selectAll("rect.measure")
|
62
|
+
.data(measurez);
|
63
|
+
|
64
|
+
measure.enter().append("svg:rect")
|
65
|
+
.attr("class", function(d, i) { return "measure s" + i; })
|
66
|
+
.attr("width", w0)
|
67
|
+
.attr("height", height / 3)
|
68
|
+
.attr("x", reverse ? x0 : 0)
|
69
|
+
.attr("y", height / 3)
|
70
|
+
.transition()
|
71
|
+
.duration(duration)
|
72
|
+
.attr("width", w1)
|
73
|
+
.attr("x", reverse ? x1 : 0);
|
74
|
+
|
75
|
+
measure.transition()
|
76
|
+
.duration(duration)
|
77
|
+
.attr("width", w1)
|
78
|
+
.attr("height", height / 3)
|
79
|
+
.attr("x", reverse ? x1 : 0)
|
80
|
+
.attr("y", height / 3);
|
81
|
+
|
82
|
+
// Update the marker lines.
|
83
|
+
var marker = g.selectAll("line.marker")
|
84
|
+
.data(markerz);
|
85
|
+
|
86
|
+
marker.enter().append("svg:line")
|
87
|
+
.attr("class", "marker")
|
88
|
+
.attr("x1", x0)
|
89
|
+
.attr("x2", x0)
|
90
|
+
.attr("y1", height / 6)
|
91
|
+
.attr("y2", height * 5 / 6)
|
92
|
+
.transition()
|
93
|
+
.duration(duration)
|
94
|
+
.attr("x1", x1)
|
95
|
+
.attr("x2", x1);
|
96
|
+
|
97
|
+
marker.transition()
|
98
|
+
.duration(duration)
|
99
|
+
.attr("x1", x1)
|
100
|
+
.attr("x2", x1)
|
101
|
+
.attr("y1", height / 6)
|
102
|
+
.attr("y2", height * 5 / 6);
|
103
|
+
|
104
|
+
// Compute the tick format.
|
105
|
+
var format = tickFormat || x1.tickFormat(8);
|
106
|
+
|
107
|
+
// Update the tick groups.
|
108
|
+
var tick = g.selectAll("g.tick")
|
109
|
+
.data(x1.ticks(8), function(d) {
|
110
|
+
return this.textContent || format(d);
|
111
|
+
});
|
112
|
+
|
113
|
+
// Initialize the ticks with the old scale, x0.
|
114
|
+
var tickEnter = tick.enter().append("svg:g")
|
115
|
+
.attr("class", "tick")
|
116
|
+
.attr("transform", d3_chart_bulletTranslate(x0))
|
117
|
+
.style("opacity", 1e-6);
|
118
|
+
|
119
|
+
tickEnter.append("svg:line")
|
120
|
+
.attr("y1", height)
|
121
|
+
.attr("y2", height * 7 / 6);
|
122
|
+
|
123
|
+
tickEnter.append("svg:text")
|
124
|
+
.attr("text-anchor", "middle")
|
125
|
+
.attr("dy", "1em")
|
126
|
+
.attr("y", height * 7 / 6)
|
127
|
+
.text(format);
|
128
|
+
|
129
|
+
// Transition the entering ticks to the new scale, x1.
|
130
|
+
tickEnter.transition()
|
131
|
+
.duration(duration)
|
132
|
+
.attr("transform", d3_chart_bulletTranslate(x1))
|
133
|
+
.style("opacity", 1);
|
134
|
+
|
135
|
+
// Transition the updating ticks to the new scale, x1.
|
136
|
+
var tickUpdate = tick.transition()
|
137
|
+
.duration(duration)
|
138
|
+
.attr("transform", d3_chart_bulletTranslate(x1))
|
139
|
+
.style("opacity", 1);
|
140
|
+
|
141
|
+
tickUpdate.select("line")
|
142
|
+
.attr("y1", height)
|
143
|
+
.attr("y2", height * 7 / 6);
|
144
|
+
|
145
|
+
tickUpdate.select("text")
|
146
|
+
.attr("y", height * 7 / 6);
|
147
|
+
|
148
|
+
// Transition the exiting ticks to the new scale, x1.
|
149
|
+
tick.exit().transition()
|
150
|
+
.duration(duration)
|
151
|
+
.attr("transform", d3_chart_bulletTranslate(x1))
|
152
|
+
.style("opacity", 1e-6)
|
153
|
+
.remove();
|
154
|
+
});
|
155
|
+
d3.timer.flush();
|
156
|
+
}
|
157
|
+
|
158
|
+
// left, right, top, bottom
|
159
|
+
bullet.orient = function(x) {
|
160
|
+
if (!arguments.length) return orient;
|
161
|
+
orient = x;
|
162
|
+
reverse = orient == "right" || orient == "bottom";
|
163
|
+
return bullet;
|
164
|
+
};
|
165
|
+
|
166
|
+
// ranges (bad, satisfactory, good)
|
167
|
+
bullet.ranges = function(x) {
|
168
|
+
if (!arguments.length) return ranges;
|
169
|
+
ranges = x;
|
170
|
+
return bullet;
|
171
|
+
};
|
172
|
+
|
173
|
+
// markers (previous, goal)
|
174
|
+
bullet.markers = function(x) {
|
175
|
+
if (!arguments.length) return markers;
|
176
|
+
markers = x;
|
177
|
+
return bullet;
|
178
|
+
};
|
179
|
+
|
180
|
+
// measures (actual, forecast)
|
181
|
+
bullet.measures = function(x) {
|
182
|
+
if (!arguments.length) return measures;
|
183
|
+
measures = x;
|
184
|
+
return bullet;
|
185
|
+
};
|
186
|
+
|
187
|
+
bullet.width = function(x) {
|
188
|
+
if (!arguments.length) return width;
|
189
|
+
width = x;
|
190
|
+
return bullet;
|
191
|
+
};
|
192
|
+
|
193
|
+
bullet.height = function(x) {
|
194
|
+
if (!arguments.length) return height;
|
195
|
+
height = x;
|
196
|
+
return bullet;
|
197
|
+
};
|
198
|
+
|
199
|
+
bullet.tickFormat = function(x) {
|
200
|
+
if (!arguments.length) return tickFormat;
|
201
|
+
tickFormat = x;
|
202
|
+
return bullet;
|
203
|
+
};
|
204
|
+
|
205
|
+
bullet.duration = function(x) {
|
206
|
+
if (!arguments.length) return duration;
|
207
|
+
duration = x;
|
208
|
+
return bullet;
|
209
|
+
};
|
210
|
+
|
211
|
+
return bullet;
|
212
|
+
};
|
213
|
+
|
214
|
+
function d3_chart_bulletRanges(d) {
|
215
|
+
return d.ranges;
|
216
|
+
}
|
217
|
+
|
218
|
+
function d3_chart_bulletMarkers(d) {
|
219
|
+
return d.markers;
|
220
|
+
}
|
221
|
+
|
222
|
+
function d3_chart_bulletMeasures(d) {
|
223
|
+
return d.measures;
|
224
|
+
}
|
225
|
+
|
226
|
+
function d3_chart_bulletTranslate(x) {
|
227
|
+
return function(d) {
|
228
|
+
return "translate(" + x(d) + ",0)";
|
229
|
+
};
|
230
|
+
}
|
231
|
+
|
232
|
+
function d3_chart_bulletWidth(x) {
|
233
|
+
var x0 = x(0);
|
234
|
+
return function(d) {
|
235
|
+
return Math.abs(x(d) - x0);
|
236
|
+
};
|
237
|
+
}
|