wiki 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +10 -2
  4. data/bin/wiki +4 -0
  5. data/default-data/pages/how-to-wiki +1069 -0
  6. data/default-data/pages/welcome-visitors +336 -0
  7. data/default-data/status/favicon.png +0 -0
  8. data/default-data/status/local-identity +7 -0
  9. data/lib/wiki/favicon.rb +0 -1
  10. data/lib/wiki/page.rb +3 -6
  11. data/lib/wiki/server.rb +7 -3
  12. data/lib/wiki/version.rb +1 -1
  13. data/package.json +70 -0
  14. data/wiki.gemspec +20 -13
  15. metadata +205 -58
  16. data/lib/wiki/views/client/Gruntfile.js +0 -50
  17. data/lib/wiki/views/client/ReadMe.md +0 -67
  18. data/lib/wiki/views/client/build-test.bat +0 -10
  19. data/lib/wiki/views/client/build.bat +0 -8
  20. data/lib/wiki/views/client/builder.pl +0 -41
  21. data/lib/wiki/views/client/client.coffee +0 -3
  22. data/lib/wiki/views/client/client.js +0 -3607
  23. data/lib/wiki/views/client/crosses.png +0 -0
  24. data/lib/wiki/views/client/images/external-link-ltr-icon.png +0 -0
  25. data/lib/wiki/views/client/images/noise.png +0 -0
  26. data/lib/wiki/views/client/images/oops.jpg +0 -0
  27. data/lib/wiki/views/client/js/d3/d3.behavior.js +0 -198
  28. data/lib/wiki/views/client/js/d3/d3.chart.js +0 -984
  29. data/lib/wiki/views/client/js/d3/d3.csv.js +0 -92
  30. data/lib/wiki/views/client/js/d3/d3.geo.js +0 -566
  31. data/lib/wiki/views/client/js/d3/d3.geom.js +0 -825
  32. data/lib/wiki/views/client/js/d3/d3.js +0 -3597
  33. data/lib/wiki/views/client/js/d3/d3.layout.js +0 -1923
  34. data/lib/wiki/views/client/js/d3/d3.time.js +0 -660
  35. data/lib/wiki/views/client/js/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  36. data/lib/wiki/views/client/js/images/ui-icons_222222_256x240.png +0 -0
  37. data/lib/wiki/views/client/js/jquery-1.6.2.min.js +0 -18
  38. data/lib/wiki/views/client/js/jquery-1.7.1.min.js +0 -4
  39. data/lib/wiki/views/client/js/jquery-1.9.1.min.js +0 -5
  40. data/lib/wiki/views/client/js/jquery-migrate-1.1.1.min.js +0 -3
  41. data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.css +0 -5
  42. data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.js +0 -6
  43. data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.css +0 -339
  44. data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.min.js +0 -315
  45. data/lib/wiki/views/client/js/jquery.ie.cors.js +0 -310
  46. data/lib/wiki/views/client/js/jquery.ui.touch-punch.min.js +0 -11
  47. data/lib/wiki/views/client/js/modernizr.custom.63710.js +0 -824
  48. data/lib/wiki/views/client/js/sockjs-0.3.min.js +0 -27
  49. data/lib/wiki/views/client/js/underscore-min.js +0 -30
  50. data/lib/wiki/views/client/mkplugin.sh +0 -97
  51. data/lib/wiki/views/client/package.json +0 -36
  52. data/lib/wiki/views/client/runtests.html +0 -26
  53. data/lib/wiki/views/client/style.css +0 -339
  54. data/lib/wiki/views/client/test/mocha.css +0 -231
  55. data/lib/wiki/views/client/test/mocha.js +0 -5340
  56. data/lib/wiki/views/client/test/testclient.js +0 -17133
  57. data/lib/wiki/views/client/testclient.coffee +0 -18
  58. data/lib/wiki/views/client/theme/granite.css +0 -59
  59. data/lib/wiki/views/client/theme/stoneSeamless.jpg +0 -0
  60. data/lib/wiki/views/client/twitter-maintainance.jpg +0 -0
@@ -1,198 +0,0 @@
1
- (function(){d3.behavior = {};
2
- // TODO unbind zoom behavior?
3
- // TODO unbind listener?
4
- d3.behavior.zoom = function() {
5
- var xyz = [0, 0, 0],
6
- event = d3.dispatch("zoom");
7
-
8
- function zoom() {
9
- this
10
- .on("mousedown.zoom", mousedown)
11
- .on("mousewheel.zoom", mousewheel)
12
- .on("DOMMouseScroll.zoom", dblclick)
13
- .on("dblclick.zoom", dblclick)
14
- .on("touchstart.zoom", touchstart);
15
-
16
- d3.select(window)
17
- .on("mousemove.zoom", d3_behavior_zoomMousemove)
18
- .on("mouseup.zoom", d3_behavior_zoomMouseup)
19
- .on("touchmove.zoom", d3_behavior_zoomTouchmove)
20
- .on("touchend.zoom", d3_behavior_zoomTouchup);
21
- }
22
-
23
- // snapshot the local context for subsequent dispatch
24
- function start() {
25
- d3_behavior_zoomXyz = xyz;
26
- d3_behavior_zoomDispatch = event.zoom.dispatch;
27
- d3_behavior_zoomTarget = this;
28
- d3_behavior_zoomArguments = arguments;
29
- }
30
-
31
- function mousedown() {
32
- start.apply(this, arguments);
33
- d3_behavior_zoomPanning = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
34
- d3.event.preventDefault();
35
- window.focus();
36
- }
37
-
38
- // store starting mouse location
39
- function mousewheel() {
40
- start.apply(this, arguments);
41
- if (!d3_behavior_zoomZooming) d3_behavior_zoomZooming = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
42
- d3_behavior_zoomTo(d3_behavior_zoomDelta() + xyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomZooming);
43
- }
44
-
45
- function dblclick() {
46
- start.apply(this, arguments);
47
- var mouse = d3.svg.mouse(d3_behavior_zoomTarget);
48
- d3_behavior_zoomTo(d3.event.shiftKey ? Math.ceil(xyz[2] - 1) : Math.floor(xyz[2] + 1), mouse, d3_behavior_zoomLocation(mouse));
49
- }
50
-
51
- // doubletap detection
52
- function touchstart() {
53
- start.apply(this, arguments);
54
- var touches = d3_behavior_zoomTouchup(),
55
- touch,
56
- now = Date.now();
57
- if ((touches.length === 1) && (now - d3_behavior_zoomLast < 300)) {
58
- d3_behavior_zoomTo(1 + Math.floor(xyz[2]), touch = touches[0], d3_behavior_zoomLocations[touch.identifier]);
59
- }
60
- d3_behavior_zoomLast = now;
61
- }
62
-
63
- zoom.on = function(type, listener) {
64
- event[type].add(listener);
65
- return zoom;
66
- };
67
-
68
- return zoom;
69
- };
70
-
71
- var d3_behavior_zoomDiv,
72
- d3_behavior_zoomPanning,
73
- d3_behavior_zoomZooming,
74
- d3_behavior_zoomLocations = {}, // identifier -> location
75
- d3_behavior_zoomLast = 0,
76
- d3_behavior_zoomXyz,
77
- d3_behavior_zoomDispatch,
78
- d3_behavior_zoomTarget,
79
- d3_behavior_zoomArguments;
80
-
81
- function d3_behavior_zoomLocation(point) {
82
- return [
83
- point[0] - d3_behavior_zoomXyz[0],
84
- point[1] - d3_behavior_zoomXyz[1],
85
- d3_behavior_zoomXyz[2]
86
- ];
87
- }
88
-
89
- // detect the pixels that would be scrolled by this wheel event
90
- function d3_behavior_zoomDelta() {
91
-
92
- // mousewheel events are totally broken!
93
- // https://bugs.webkit.org/show_bug.cgi?id=40441
94
- // not only that, but Chrome and Safari differ in re. to acceleration!
95
- if (!d3_behavior_zoomDiv) {
96
- d3_behavior_zoomDiv = d3.select("body").append("div")
97
- .style("visibility", "hidden")
98
- .style("top", 0)
99
- .style("height", 0)
100
- .style("width", 0)
101
- .style("overflow-y", "scroll")
102
- .append("div")
103
- .style("height", "2000px")
104
- .node().parentNode;
105
- }
106
-
107
- var e = d3.event, delta;
108
- try {
109
- d3_behavior_zoomDiv.scrollTop = 1000;
110
- d3_behavior_zoomDiv.dispatchEvent(e);
111
- delta = 1000 - d3_behavior_zoomDiv.scrollTop;
112
- } catch (error) {
113
- delta = e.wheelDelta || -e.detail;
114
- }
115
-
116
- return delta * .005;
117
- }
118
-
119
- // Note: Since we don't rotate, it's possible for the touches to become
120
- // slightly detached from their original positions. Thus, we recompute the
121
- // touch points on touchend as well as touchstart!
122
- function d3_behavior_zoomTouchup() {
123
- var touches = d3.svg.touches(d3_behavior_zoomTarget),
124
- i = -1,
125
- n = touches.length,
126
- touch;
127
- while (++i < n) d3_behavior_zoomLocations[(touch = touches[i]).identifier] = d3_behavior_zoomLocation(touch);
128
- return touches;
129
- }
130
-
131
- function d3_behavior_zoomTouchmove() {
132
- var touches = d3.svg.touches(d3_behavior_zoomTarget);
133
- switch (touches.length) {
134
-
135
- // single-touch pan
136
- case 1: {
137
- var touch = touches[0];
138
- d3_behavior_zoomTo(d3_behavior_zoomXyz[2], touch, d3_behavior_zoomLocations[touch.identifier]);
139
- break;
140
- }
141
-
142
- // double-touch pan + zoom
143
- case 2: {
144
- var p0 = touches[0],
145
- p1 = touches[1],
146
- p2 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2],
147
- l0 = d3_behavior_zoomLocations[p0.identifier],
148
- l1 = d3_behavior_zoomLocations[p1.identifier],
149
- l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2, l0[2]];
150
- d3_behavior_zoomTo(Math.log(d3.event.scale) / Math.LN2 + l0[2], p2, l2);
151
- break;
152
- }
153
- }
154
- }
155
-
156
- function d3_behavior_zoomMousemove() {
157
- d3_behavior_zoomZooming = null;
158
- if (d3_behavior_zoomPanning) d3_behavior_zoomTo(d3_behavior_zoomXyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomPanning);
159
- }
160
-
161
- function d3_behavior_zoomMouseup() {
162
- if (d3_behavior_zoomPanning) {
163
- d3_behavior_zoomMousemove();
164
- d3_behavior_zoomPanning = null;
165
- }
166
- }
167
-
168
- function d3_behavior_zoomTo(z, x0, x1) {
169
- var K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
170
- x = d3_behavior_zoomXyz[0] = x0[0] - K * x1[0],
171
- y = d3_behavior_zoomXyz[1] = x0[1] - K * x1[1],
172
- o = d3.event, // Events can be reentrant (e.g., focus).
173
- k = Math.pow(2, z);
174
-
175
- d3.event = {
176
- scale: k,
177
- translate: [x, y],
178
- transform: function(sx, sy) {
179
- if (sx) transform(sx, x);
180
- if (sy) transform(sy, y);
181
- }
182
- };
183
-
184
- function transform(scale, o) {
185
- var domain = scale.__domain || (scale.__domain = scale.domain()),
186
- range = scale.range().map(function(v) { return (v - o) / k; });
187
- scale.domain(domain).domain(range.map(scale.invert));
188
- }
189
-
190
- try {
191
- d3_behavior_zoomDispatch.apply(d3_behavior_zoomTarget, d3_behavior_zoomArguments);
192
- } finally {
193
- d3.event = o;
194
- }
195
-
196
- o.preventDefault();
197
- }
198
- })();
@@ -1,984 +0,0 @@
1
- (function(){d3.chart = {};
2
- // Inspired by http://informationandvisualization.de/blog/box-plot
3
- d3.chart.box = function() {
4
- var width = 1,
5
- height = 1,
6
- duration = 0,
7
- domain = null,
8
- value = Number,
9
- whiskers = d3_chart_boxWhiskers,
10
- quartiles = d3_chart_boxQuartiles,
11
- tickFormat = null;
12
-
13
- // For each small multiple…
14
- function box(g) {
15
- g.each(function(d, i) {
16
- d = d.map(value).sort(d3.ascending);
17
- var g = d3.select(this),
18
- n = d.length,
19
- min = d[0],
20
- max = d[n - 1];
21
-
22
- // Compute quartiles. Must return exactly 3 elements.
23
- var quartileData = d.quartiles = quartiles(d);
24
-
25
- // Compute whiskers. Must return exactly 2 elements, or null.
26
- var whiskerIndices = whiskers && whiskers.call(this, d, i),
27
- whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; });
28
-
29
- // Compute outliers. If no whiskers are specified, all data are "outliers".
30
- // We compute the outliers as indices, so that we can join across transitions!
31
- var outlierIndices = whiskerIndices
32
- ? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n))
33
- : d3.range(n);
34
-
35
- // Compute the new x-scale.
36
- var x1 = d3.scale.linear()
37
- .domain(domain && domain.call(this, d, i) || [min, max])
38
- .range([height, 0]);
39
-
40
- // Retrieve the old x-scale, if this is an update.
41
- var x0 = this.__chart__ || d3.scale.linear()
42
- .domain([0, Infinity])
43
- .range(x1.range());
44
-
45
- // Stash the new scale.
46
- this.__chart__ = x1;
47
-
48
- // Note: the box, median, and box tick elements are fixed in number,
49
- // so we only have to handle enter and update. In contrast, the outliers
50
- // and other elements are variable, so we need to exit them! Variable
51
- // elements also fade in and out.
52
-
53
- // Update center line: the vertical line spanning the whiskers.
54
- var center = g.selectAll("line.center")
55
- .data(whiskerData ? [whiskerData] : []);
56
-
57
- center.enter().insert("svg:line", "rect")
58
- .attr("class", "center")
59
- .attr("x1", width / 2)
60
- .attr("y1", function(d) { return x0(d[0]); })
61
- .attr("x2", width / 2)
62
- .attr("y2", function(d) { return x0(d[1]); })
63
- .style("opacity", 1e-6)
64
- .transition()
65
- .duration(duration)
66
- .style("opacity", 1)
67
- .attr("y1", function(d) { return x1(d[0]); })
68
- .attr("y2", function(d) { return x1(d[1]); });
69
-
70
- center.transition()
71
- .duration(duration)
72
- .style("opacity", 1)
73
- .attr("y1", function(d) { return x1(d[0]); })
74
- .attr("y2", function(d) { return x1(d[1]); });
75
-
76
- center.exit().transition()
77
- .duration(duration)
78
- .style("opacity", 1e-6)
79
- .attr("y1", function(d) { return x1(d[0]); })
80
- .attr("y2", function(d) { return x1(d[1]); })
81
- .remove();
82
-
83
- // Update innerquartile box.
84
- var box = g.selectAll("rect.box")
85
- .data([quartileData]);
86
-
87
- box.enter().append("svg:rect")
88
- .attr("class", "box")
89
- .attr("x", 0)
90
- .attr("y", function(d) { return x0(d[2]); })
91
- .attr("width", width)
92
- .attr("height", function(d) { return x0(d[0]) - x0(d[2]); })
93
- .transition()
94
- .duration(duration)
95
- .attr("y", function(d) { return x1(d[2]); })
96
- .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
97
-
98
- box.transition()
99
- .duration(duration)
100
- .attr("y", function(d) { return x1(d[2]); })
101
- .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
102
-
103
- // Update median line.
104
- var medianLine = g.selectAll("line.median")
105
- .data([quartileData[1]]);
106
-
107
- medianLine.enter().append("svg:line")
108
- .attr("class", "median")
109
- .attr("x1", 0)
110
- .attr("y1", x0)
111
- .attr("x2", width)
112
- .attr("y2", x0)
113
- .transition()
114
- .duration(duration)
115
- .attr("y1", x1)
116
- .attr("y2", x1);
117
-
118
- medianLine.transition()
119
- .duration(duration)
120
- .attr("y1", x1)
121
- .attr("y2", x1);
122
-
123
- // Update whiskers.
124
- var whisker = g.selectAll("line.whisker")
125
- .data(whiskerData || []);
126
-
127
- whisker.enter().insert("svg:line", "circle, text")
128
- .attr("class", "whisker")
129
- .attr("x1", 0)
130
- .attr("y1", x0)
131
- .attr("x2", width)
132
- .attr("y2", x0)
133
- .style("opacity", 1e-6)
134
- .transition()
135
- .duration(duration)
136
- .attr("y1", x1)
137
- .attr("y2", x1)
138
- .style("opacity", 1);
139
-
140
- whisker.transition()
141
- .duration(duration)
142
- .attr("y1", x1)
143
- .attr("y2", x1)
144
- .style("opacity", 1);
145
-
146
- whisker.exit().transition()
147
- .duration(duration)
148
- .attr("y1", x1)
149
- .attr("y2", x1)
150
- .style("opacity", 1e-6)
151
- .remove();
152
-
153
- // Update outliers.
154
- var outlier = g.selectAll("circle.outlier")
155
- .data(outlierIndices, Number);
156
-
157
- outlier.enter().insert("svg:circle", "text")
158
- .attr("class", "outlier")
159
- .attr("r", 5)
160
- .attr("cx", width / 2)
161
- .attr("cy", function(i) { return x0(d[i]); })
162
- .style("opacity", 1e-6)
163
- .transition()
164
- .duration(duration)
165
- .attr("cy", function(i) { return x1(d[i]); })
166
- .style("opacity", 1);
167
-
168
- outlier.transition()
169
- .duration(duration)
170
- .attr("cy", function(i) { return x1(d[i]); })
171
- .style("opacity", 1);
172
-
173
- outlier.exit().transition()
174
- .duration(duration)
175
- .attr("cy", function(i) { return x1(d[i]); })
176
- .style("opacity", 1e-6)
177
- .remove();
178
-
179
- // Compute the tick format.
180
- var format = tickFormat || x1.tickFormat(8);
181
-
182
- // Update box ticks.
183
- var boxTick = g.selectAll("text.box")
184
- .data(quartileData);
185
-
186
- boxTick.enter().append("svg:text")
187
- .attr("class", "box")
188
- .attr("dy", ".3em")
189
- .attr("dx", function(d, i) { return i & 1 ? 6 : -6 })
190
- .attr("x", function(d, i) { return i & 1 ? width : 0 })
191
- .attr("y", x0)
192
- .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; })
193
- .text(format)
194
- .transition()
195
- .duration(duration)
196
- .attr("y", x1);
197
-
198
- boxTick.transition()
199
- .duration(duration)
200
- .text(format)
201
- .attr("y", x1);
202
-
203
- // Update whisker ticks. These are handled separately from the box
204
- // ticks because they may or may not exist, and we want don't want
205
- // to join box ticks pre-transition with whisker ticks post-.
206
- var whiskerTick = g.selectAll("text.whisker")
207
- .data(whiskerData || []);
208
-
209
- whiskerTick.enter().append("svg:text")
210
- .attr("class", "whisker")
211
- .attr("dy", ".3em")
212
- .attr("dx", 6)
213
- .attr("x", width)
214
- .attr("y", x0)
215
- .text(format)
216
- .style("opacity", 1e-6)
217
- .transition()
218
- .duration(duration)
219
- .attr("y", x1)
220
- .style("opacity", 1);
221
-
222
- whiskerTick.transition()
223
- .duration(duration)
224
- .text(format)
225
- .attr("y", x1)
226
- .style("opacity", 1);
227
-
228
- whiskerTick.exit().transition()
229
- .duration(duration)
230
- .attr("y", x1)
231
- .style("opacity", 1e-6)
232
- .remove();
233
- });
234
- d3.timer.flush();
235
- }
236
-
237
- box.width = function(x) {
238
- if (!arguments.length) return width;
239
- width = x;
240
- return box;
241
- };
242
-
243
- box.height = function(x) {
244
- if (!arguments.length) return height;
245
- height = x;
246
- return box;
247
- };
248
-
249
- box.tickFormat = function(x) {
250
- if (!arguments.length) return tickFormat;
251
- tickFormat = x;
252
- return box;
253
- };
254
-
255
- box.duration = function(x) {
256
- if (!arguments.length) return duration;
257
- duration = x;
258
- return box;
259
- };
260
-
261
- box.domain = function(x) {
262
- if (!arguments.length) return domain;
263
- domain = x == null ? x : d3.functor(x);
264
- return box;
265
- };
266
-
267
- box.value = function(x) {
268
- if (!arguments.length) return value;
269
- value = x;
270
- return box;
271
- };
272
-
273
- box.whiskers = function(x) {
274
- if (!arguments.length) return whiskers;
275
- whiskers = x;
276
- return box;
277
- };
278
-
279
- box.quartiles = function(x) {
280
- if (!arguments.length) return quartiles;
281
- quartiles = x;
282
- return box;
283
- };
284
-
285
- return box;
286
- };
287
-
288
- function d3_chart_boxWhiskers(d) {
289
- return [0, d.length - 1];
290
- }
291
-
292
- function d3_chart_boxQuartiles(d) {
293
- return [
294
- d3.quantile(d, .25),
295
- d3.quantile(d, .5),
296
- d3.quantile(d, .75)
297
- ];
298
- }
299
- // Chart design based on the recommendations of Stephen Few. Implementation
300
- // based on the work of Clint Ivy, Jamie Love, and Jason Davies.
301
- // http://projects.instantcognition.com/protovis/bulletchart/
302
- d3.chart.bullet = function() {
303
- var orient = "left", // TODO top & bottom
304
- reverse = false,
305
- duration = 0,
306
- ranges = d3_chart_bulletRanges,
307
- markers = d3_chart_bulletMarkers,
308
- measures = d3_chart_bulletMeasures,
309
- width = 380,
310
- height = 30,
311
- tickFormat = null;
312
-
313
- // For each small multiple…
314
- function bullet(g) {
315
- g.each(function(d, i) {
316
- var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
317
- markerz = markers.call(this, d, i).slice().sort(d3.descending),
318
- measurez = measures.call(this, d, i).slice().sort(d3.descending),
319
- g = d3.select(this);
320
-
321
- // Compute the new x-scale.
322
- var x1 = d3.scale.linear()
323
- .domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
324
- .range(reverse ? [width, 0] : [0, width]);
325
-
326
- // Retrieve the old x-scale, if this is an update.
327
- var x0 = this.__chart__ || d3.scale.linear()
328
- .domain([0, Infinity])
329
- .range(x1.range());
330
-
331
- // Stash the new scale.
332
- this.__chart__ = x1;
333
-
334
- // Derive width-scales from the x-scales.
335
- var w0 = d3_chart_bulletWidth(x0),
336
- w1 = d3_chart_bulletWidth(x1);
337
-
338
- // Update the range rects.
339
- var range = g.selectAll("rect.range")
340
- .data(rangez);
341
-
342
- range.enter().append("svg:rect")
343
- .attr("class", function(d, i) { return "range s" + i; })
344
- .attr("width", w0)
345
- .attr("height", height)
346
- .attr("x", reverse ? x0 : 0)
347
- .transition()
348
- .duration(duration)
349
- .attr("width", w1)
350
- .attr("x", reverse ? x1 : 0);
351
-
352
- range.transition()
353
- .duration(duration)
354
- .attr("x", reverse ? x1 : 0)
355
- .attr("width", w1)
356
- .attr("height", height);
357
-
358
- // Update the measure rects.
359
- var measure = g.selectAll("rect.measure")
360
- .data(measurez);
361
-
362
- measure.enter().append("svg:rect")
363
- .attr("class", function(d, i) { return "measure s" + i; })
364
- .attr("width", w0)
365
- .attr("height", height / 3)
366
- .attr("x", reverse ? x0 : 0)
367
- .attr("y", height / 3)
368
- .transition()
369
- .duration(duration)
370
- .attr("width", w1)
371
- .attr("x", reverse ? x1 : 0);
372
-
373
- measure.transition()
374
- .duration(duration)
375
- .attr("width", w1)
376
- .attr("height", height / 3)
377
- .attr("x", reverse ? x1 : 0)
378
- .attr("y", height / 3);
379
-
380
- // Update the marker lines.
381
- var marker = g.selectAll("line.marker")
382
- .data(markerz);
383
-
384
- marker.enter().append("svg:line")
385
- .attr("class", "marker")
386
- .attr("x1", x0)
387
- .attr("x2", x0)
388
- .attr("y1", height / 6)
389
- .attr("y2", height * 5 / 6)
390
- .transition()
391
- .duration(duration)
392
- .attr("x1", x1)
393
- .attr("x2", x1);
394
-
395
- marker.transition()
396
- .duration(duration)
397
- .attr("x1", x1)
398
- .attr("x2", x1)
399
- .attr("y1", height / 6)
400
- .attr("y2", height * 5 / 6);
401
-
402
- // Compute the tick format.
403
- var format = tickFormat || x1.tickFormat(8);
404
-
405
- // Update the tick groups.
406
- var tick = g.selectAll("g.tick")
407
- .data(x1.ticks(8), function(d) {
408
- return this.textContent || format(d);
409
- });
410
-
411
- // Initialize the ticks with the old scale, x0.
412
- var tickEnter = tick.enter().append("svg:g")
413
- .attr("class", "tick")
414
- .attr("transform", d3_chart_bulletTranslate(x0))
415
- .style("opacity", 1e-6);
416
-
417
- tickEnter.append("svg:line")
418
- .attr("y1", height)
419
- .attr("y2", height * 7 / 6);
420
-
421
- tickEnter.append("svg:text")
422
- .attr("text-anchor", "middle")
423
- .attr("dy", "1em")
424
- .attr("y", height * 7 / 6)
425
- .text(format);
426
-
427
- // Transition the entering ticks to the new scale, x1.
428
- tickEnter.transition()
429
- .duration(duration)
430
- .attr("transform", d3_chart_bulletTranslate(x1))
431
- .style("opacity", 1);
432
-
433
- // Transition the updating ticks to the new scale, x1.
434
- var tickUpdate = tick.transition()
435
- .duration(duration)
436
- .attr("transform", d3_chart_bulletTranslate(x1))
437
- .style("opacity", 1);
438
-
439
- tickUpdate.select("line")
440
- .attr("y1", height)
441
- .attr("y2", height * 7 / 6);
442
-
443
- tickUpdate.select("text")
444
- .attr("y", height * 7 / 6);
445
-
446
- // Transition the exiting ticks to the new scale, x1.
447
- tick.exit().transition()
448
- .duration(duration)
449
- .attr("transform", d3_chart_bulletTranslate(x1))
450
- .style("opacity", 1e-6)
451
- .remove();
452
- });
453
- d3.timer.flush();
454
- }
455
-
456
- // left, right, top, bottom
457
- bullet.orient = function(x) {
458
- if (!arguments.length) return orient;
459
- orient = x;
460
- reverse = orient == "right" || orient == "bottom";
461
- return bullet;
462
- };
463
-
464
- // ranges (bad, satisfactory, good)
465
- bullet.ranges = function(x) {
466
- if (!arguments.length) return ranges;
467
- ranges = x;
468
- return bullet;
469
- };
470
-
471
- // markers (previous, goal)
472
- bullet.markers = function(x) {
473
- if (!arguments.length) return markers;
474
- markers = x;
475
- return bullet;
476
- };
477
-
478
- // measures (actual, forecast)
479
- bullet.measures = function(x) {
480
- if (!arguments.length) return measures;
481
- measures = x;
482
- return bullet;
483
- };
484
-
485
- bullet.width = function(x) {
486
- if (!arguments.length) return width;
487
- width = x;
488
- return bullet;
489
- };
490
-
491
- bullet.height = function(x) {
492
- if (!arguments.length) return height;
493
- height = x;
494
- return bullet;
495
- };
496
-
497
- bullet.tickFormat = function(x) {
498
- if (!arguments.length) return tickFormat;
499
- tickFormat = x;
500
- return bullet;
501
- };
502
-
503
- bullet.duration = function(x) {
504
- if (!arguments.length) return duration;
505
- duration = x;
506
- return bullet;
507
- };
508
-
509
- return bullet;
510
- };
511
-
512
- function d3_chart_bulletRanges(d) {
513
- return d.ranges;
514
- }
515
-
516
- function d3_chart_bulletMarkers(d) {
517
- return d.markers;
518
- }
519
-
520
- function d3_chart_bulletMeasures(d) {
521
- return d.measures;
522
- }
523
-
524
- function d3_chart_bulletTranslate(x) {
525
- return function(d) {
526
- return "translate(" + x(d) + ",0)";
527
- };
528
- }
529
-
530
- function d3_chart_bulletWidth(x) {
531
- var x0 = x(0);
532
- return function(d) {
533
- return Math.abs(x(d) - x0);
534
- };
535
- }
536
- // Implements a horizon layout, which is a variation of a single-series
537
- // area chart where the area is folded into multiple bands. Color is used to
538
- // encode band, allowing the size of the chart to be reduced significantly
539
- // without impeding readability. This layout algorithm is based on the work of
540
- // J. Heer, N. Kong and M. Agrawala in "Sizing the Horizon: The Effects of Chart
541
- // Size and Layering on the Graphical Perception of Time Series Visualizations",
542
- // CHI 2009. http://hci.stanford.edu/publications/2009/heer-horizon-chi09.pdf
543
- d3.chart.horizon = function() {
544
- var bands = 1, // between 1 and 5, typically
545
- mode = "offset", // or mirror
546
- interpolate = "linear", // or basis, monotone, step-before, etc.
547
- x = d3_chart_horizonX,
548
- y = d3_chart_horizonY,
549
- w = 960,
550
- h = 40,
551
- duration = 0;
552
-
553
- var color = d3.scale.linear()
554
- .domain([-1, 0, 1])
555
- .range(["#d62728", "#fff", "#1f77b4"]);
556
-
557
- // For each small multiple…
558
- function horizon(g) {
559
- g.each(function(d, i) {
560
- var g = d3.select(this),
561
- n = 2 * bands + 1,
562
- xMin = Infinity,
563
- xMax = -Infinity,
564
- yMax = -Infinity,
565
- x0, // old x-scale
566
- y0, // old y-scale
567
- id; // unique id for paths
568
-
569
- // Compute x- and y-values along with extents.
570
- var data = d.map(function(d, i) {
571
- var xv = x.call(this, d, i),
572
- yv = y.call(this, d, i);
573
- if (xv < xMin) xMin = xv;
574
- if (xv > xMax) xMax = xv;
575
- if (-yv > yMax) yMax = -yv;
576
- if (yv > yMax) yMax = yv;
577
- return [xv, yv];
578
- });
579
-
580
- // Compute the new x- and y-scales.
581
- var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, w]),
582
- y1 = d3.scale.linear().domain([0, yMax]).range([0, h * bands]);
583
-
584
- // Retrieve the old scales, if this is an update.
585
- if (this.__chart__) {
586
- x0 = this.__chart__.x;
587
- y0 = this.__chart__.y;
588
- id = this.__chart__.id;
589
- } else {
590
- x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
591
- y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
592
- id = ++d3_chart_horizonId;
593
- }
594
-
595
- // We'll use a defs to store the area path and the clip path.
596
- var defs = g.selectAll("defs")
597
- .data([data]);
598
-
599
- var defsEnter = defs.enter().append("svg:defs");
600
-
601
- // The clip path is a simple rect.
602
- defsEnter.append("svg:clipPath")
603
- .attr("id", "d3_chart_horizon_clip" + id)
604
- .append("svg:rect")
605
- .attr("width", w)
606
- .attr("height", h);
607
-
608
- defs.select("rect").transition()
609
- .duration(duration)
610
- .attr("width", w)
611
- .attr("height", h);
612
-
613
- // The area path is rendered with our resuable d3.svg.area.
614
- defsEnter.append("svg:path")
615
- .attr("id", "d3_chart_horizon_path" + id)
616
- .attr("d", d3_chart_horizonArea
617
- .interpolate(interpolate)
618
- .x(function(d) { return x0(d[0]); })
619
- .y0(h * bands)
620
- .y1(function(d) { return h * bands - y0(d[1]); }))
621
- .transition()
622
- .duration(duration)
623
- .attr("d", d3_chart_horizonArea
624
- .x(function(d) { return x1(d[0]); })
625
- .y1(function(d) { return h * bands - y1(d[1]); }));
626
-
627
- defs.select("path").transition()
628
- .duration(duration)
629
- .attr("d", d3_chart_horizonArea);
630
-
631
- // We'll use a container to clip all horizon layers at once.
632
- g.selectAll("g")
633
- .data([null])
634
- .enter().append("svg:g")
635
- .attr("clip-path", "url(#d3_chart_horizon_clip" + id + ")");
636
-
637
- // Define the transform function based on the mode.
638
- var transform = mode == "offset"
639
- ? function(d) { return "translate(0," + (d + (d < 0) - bands) * h + ")"; }
640
- : function(d) { return (d < 0 ? "scale(1,-1)" : "") + "translate(0," + (d - bands) * h + ")"; };
641
-
642
- // Instantiate each copy of the path with different transforms.
643
- var u = g.select("g").selectAll("use")
644
- .data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
645
-
646
- // TODO don't fudge the enter transition
647
- u.enter().append("svg:use")
648
- .attr("xlink:href", "#d3_chart_horizon_path" + id)
649
- .attr("transform", function(d) { return transform(d + (d > 0 ? 1 : -1)); })
650
- .style("fill", color)
651
- .transition()
652
- .duration(duration)
653
- .attr("transform", transform);
654
-
655
- u.transition()
656
- .duration(duration)
657
- .attr("transform", transform)
658
- .style("fill", color);
659
-
660
- u.exit().transition()
661
- .duration(duration)
662
- .attr("transform", transform)
663
- .remove();
664
-
665
- // Stash the new scales.
666
- this.__chart__ = {x: x1, y: y1, id: id};
667
- });
668
- d3.timer.flush();
669
- }
670
-
671
- horizon.duration = function(x) {
672
- if (!arguments.length) return duration;
673
- duration = +x;
674
- return horizon;
675
- };
676
-
677
- horizon.bands = function(x) {
678
- if (!arguments.length) return bands;
679
- bands = +x;
680
- color.domain([-bands, 0, bands]);
681
- return horizon;
682
- };
683
-
684
- horizon.mode = function(x) {
685
- if (!arguments.length) return mode;
686
- mode = x + "";
687
- return horizon;
688
- };
689
-
690
- horizon.colors = function(x) {
691
- if (!arguments.length) return color.range();
692
- color.range(x);
693
- return horizon;
694
- };
695
-
696
- horizon.interpolate = function(x) {
697
- if (!arguments.length) return interpolate;
698
- interpolate = x + "";
699
- return horizon;
700
- };
701
-
702
- horizon.x = function(z) {
703
- if (!arguments.length) return x;
704
- x = z;
705
- return horizon;
706
- };
707
-
708
- horizon.y = function(z) {
709
- if (!arguments.length) return y;
710
- y = z;
711
- return horizon;
712
- };
713
-
714
- horizon.width = function(x) {
715
- if (!arguments.length) return w;
716
- w = +x;
717
- return horizon;
718
- };
719
-
720
- horizon.height = function(x) {
721
- if (!arguments.length) return h;
722
- h = +x;
723
- return horizon;
724
- };
725
-
726
- return horizon;
727
- };
728
-
729
- var d3_chart_horizonArea = d3.svg.area(),
730
- d3_chart_horizonId = 0;
731
-
732
- function d3_chart_horizonX(d) {
733
- return d[0];
734
- }
735
-
736
- function d3_chart_horizonY(d) {
737
- return d[1];
738
- }
739
- // Based on http://vis.stanford.edu/protovis/ex/qqplot.html
740
- d3.chart.qq = function() {
741
- var width = 1,
742
- height = 1,
743
- duration = 0,
744
- domain = null,
745
- tickFormat = null,
746
- n = 100,
747
- x = d3_chart_qqX,
748
- y = d3_chart_qqY;
749
-
750
- // For each small multiple…
751
- function qq(g) {
752
- g.each(function(d, i) {
753
- var g = d3.select(this),
754
- qx = d3_chart_qqQuantiles(n, x.call(this, d, i)),
755
- qy = d3_chart_qqQuantiles(n, y.call(this, d, i)),
756
- xd = domain && domain.call(this, d, i) || [d3.min(qx), d3.max(qx)], // new x-domain
757
- yd = domain && domain.call(this, d, i) || [d3.min(qy), d3.max(qy)], // new y-domain
758
- x0, // old x-scale
759
- y0; // old y-scale
760
-
761
- // Compute the new x-scale.
762
- var x1 = d3.scale.linear()
763
- .domain(xd)
764
- .range([0, width]);
765
-
766
- // Compute the new y-scale.
767
- var y1 = d3.scale.linear()
768
- .domain(yd)
769
- .range([height, 0]);
770
-
771
- // Retrieve the old scales, if this is an update.
772
- if (this.__chart__) {
773
- x0 = this.__chart__.x;
774
- y0 = this.__chart__.y;
775
- } else {
776
- x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
777
- y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
778
- }
779
-
780
- // Stash the new scales.
781
- this.__chart__ = {x: x1, y: y1};
782
-
783
- // Update diagonal line.
784
- var diagonal = g.selectAll("line.diagonal")
785
- .data([null]);
786
-
787
- diagonal.enter().append("svg:line")
788
- .attr("class", "diagonal")
789
- .attr("x1", x1(yd[0]))
790
- .attr("y1", y1(xd[0]))
791
- .attr("x2", x1(yd[1]))
792
- .attr("y2", y1(xd[1]));
793
-
794
- diagonal.transition()
795
- .duration(duration)
796
- .attr("x1", x1(yd[0]))
797
- .attr("y1", y1(xd[0]))
798
- .attr("x2", x1(yd[1]))
799
- .attr("y2", y1(xd[1]));
800
-
801
- // Update quantile plots.
802
- var circle = g.selectAll("circle")
803
- .data(d3.range(n).map(function(i) {
804
- return {x: qx[i], y: qy[i]};
805
- }));
806
-
807
- circle.enter().append("svg:circle")
808
- .attr("class", "quantile")
809
- .attr("r", 4.5)
810
- .attr("cx", function(d) { return x0(d.x); })
811
- .attr("cy", function(d) { return y0(d.y); })
812
- .style("opacity", 1e-6)
813
- .transition()
814
- .duration(duration)
815
- .attr("cx", function(d) { return x1(d.x); })
816
- .attr("cy", function(d) { return y1(d.y); })
817
- .style("opacity", 1);
818
-
819
- circle.transition()
820
- .duration(duration)
821
- .attr("cx", function(d) { return x1(d.x); })
822
- .attr("cy", function(d) { return y1(d.y); })
823
- .style("opacity", 1);
824
-
825
- circle.exit().transition()
826
- .duration(duration)
827
- .attr("cx", function(d) { return x1(d.x); })
828
- .attr("cy", function(d) { return y1(d.y); })
829
- .style("opacity", 1e-6)
830
- .remove();
831
-
832
- var xformat = tickFormat || x1.tickFormat(4),
833
- yformat = tickFormat || y1.tickFormat(4),
834
- tx = function(d) { return "translate(" + x1(d) + "," + height + ")"; },
835
- ty = function(d) { return "translate(0," + y1(d) + ")"; };
836
-
837
- // Update x-ticks.
838
- var xtick = g.selectAll("g.x.tick")
839
- .data(x1.ticks(4), function(d) {
840
- return this.textContent || xformat(d);
841
- });
842
-
843
- var xtickEnter = xtick.enter().append("svg:g")
844
- .attr("class", "x tick")
845
- .attr("transform", function(d) { return "translate(" + x0(d) + "," + height + ")"; })
846
- .style("opacity", 1e-6);
847
-
848
- xtickEnter.append("svg:line")
849
- .attr("y1", 0)
850
- .attr("y2", -6);
851
-
852
- xtickEnter.append("svg:text")
853
- .attr("text-anchor", "middle")
854
- .attr("dy", "1em")
855
- .text(xformat);
856
-
857
- // Transition the entering ticks to the new scale, x1.
858
- xtickEnter.transition()
859
- .duration(duration)
860
- .attr("transform", tx)
861
- .style("opacity", 1);
862
-
863
- // Transition the updating ticks to the new scale, x1.
864
- xtick.transition()
865
- .duration(duration)
866
- .attr("transform", tx)
867
- .style("opacity", 1);
868
-
869
- // Transition the exiting ticks to the new scale, x1.
870
- xtick.exit().transition()
871
- .duration(duration)
872
- .attr("transform", tx)
873
- .style("opacity", 1e-6)
874
- .remove();
875
-
876
- // Update ticks.
877
- var ytick = g.selectAll("g.y.tick")
878
- .data(y1.ticks(4), function(d) {
879
- return this.textContent || yformat(d);
880
- });
881
-
882
- var ytickEnter = ytick.enter().append("svg:g")
883
- .attr("class", "y tick")
884
- .attr("transform", function(d) { return "translate(0," + y0(d) + ")"; })
885
- .style("opacity", 1e-6);
886
-
887
- ytickEnter.append("svg:line")
888
- .attr("x1", 0)
889
- .attr("x2", 6);
890
-
891
- ytickEnter.append("svg:text")
892
- .attr("text-anchor", "end")
893
- .attr("dx", "-.5em")
894
- .attr("dy", ".3em")
895
- .text(yformat);
896
-
897
- // Transition the entering ticks to the new scale, y1.
898
- ytickEnter.transition()
899
- .duration(duration)
900
- .attr("transform", ty)
901
- .style("opacity", 1);
902
-
903
- // Transition the updating ticks to the new scale, y1.
904
- ytick.transition()
905
- .duration(duration)
906
- .attr("transform", ty)
907
- .style("opacity", 1);
908
-
909
- // Transition the exiting ticks to the new scale, y1.
910
- ytick.exit().transition()
911
- .duration(duration)
912
- .attr("transform", ty)
913
- .style("opacity", 1e-6)
914
- .remove();
915
- });
916
- }
917
-
918
- qq.width = function(x) {
919
- if (!arguments.length) return width;
920
- width = x;
921
- return qq;
922
- };
923
-
924
- qq.height = function(x) {
925
- if (!arguments.length) return height;
926
- height = x;
927
- return qq;
928
- };
929
-
930
- qq.duration = function(x) {
931
- if (!arguments.length) return duration;
932
- duration = x;
933
- return qq;
934
- };
935
-
936
- qq.domain = function(x) {
937
- if (!arguments.length) return domain;
938
- domain = x == null ? x : d3.functor(x);
939
- return qq;
940
- };
941
-
942
- qq.count = function(z) {
943
- if (!arguments.length) return n;
944
- n = z;
945
- return qq;
946
- };
947
-
948
- qq.x = function(z) {
949
- if (!arguments.length) return x;
950
- x = z;
951
- return qq;
952
- };
953
-
954
- qq.y = function(z) {
955
- if (!arguments.length) return y;
956
- y = z;
957
- return qq;
958
- };
959
-
960
- qq.tickFormat = function(x) {
961
- if (!arguments.length) return tickFormat;
962
- tickFormat = x;
963
- return qq;
964
- };
965
-
966
- return qq;
967
- };
968
-
969
- function d3_chart_qqQuantiles(n, values) {
970
- var m = values.length - 1;
971
- values = values.slice().sort(d3.ascending);
972
- return d3.range(n).map(function(i) {
973
- return values[~~(i * m / n)];
974
- });
975
- }
976
-
977
- function d3_chart_qqX(d) {
978
- return d.x;
979
- }
980
-
981
- function d3_chart_qqY(d) {
982
- return d.y;
983
- }
984
- })();