wiki 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/lib/wiki.rb +2 -0
  8. data/lib/wiki/ReadMe.md +89 -0
  9. data/lib/wiki/config.ru +2 -0
  10. data/lib/wiki/favicon.rb +31 -0
  11. data/lib/wiki/page.rb +74 -0
  12. data/lib/wiki/random_id.rb +5 -0
  13. data/lib/wiki/server.rb +336 -0
  14. data/lib/wiki/server_helpers.rb +66 -0
  15. data/lib/wiki/stores/ReadMe.md +26 -0
  16. data/lib/wiki/stores/all.rb +3 -0
  17. data/lib/wiki/stores/couch.rb +121 -0
  18. data/lib/wiki/stores/file.rb +53 -0
  19. data/lib/wiki/stores/store.rb +38 -0
  20. data/lib/wiki/version.rb +3 -0
  21. data/lib/wiki/views/client/Gruntfile.js +50 -0
  22. data/lib/wiki/views/client/ReadMe.md +67 -0
  23. data/lib/wiki/views/client/build-test.bat +10 -0
  24. data/lib/wiki/views/client/build.bat +8 -0
  25. data/lib/wiki/views/client/builder.pl +41 -0
  26. data/lib/wiki/views/client/client.coffee +3 -0
  27. data/lib/wiki/views/client/client.js +3607 -0
  28. data/lib/wiki/views/client/crosses.png +0 -0
  29. data/lib/wiki/views/client/images/external-link-ltr-icon.png +0 -0
  30. data/lib/wiki/views/client/images/noise.png +0 -0
  31. data/lib/wiki/views/client/images/oops.jpg +0 -0
  32. data/lib/wiki/views/client/js/d3/d3.behavior.js +198 -0
  33. data/lib/wiki/views/client/js/d3/d3.chart.js +984 -0
  34. data/lib/wiki/views/client/js/d3/d3.csv.js +92 -0
  35. data/lib/wiki/views/client/js/d3/d3.geo.js +566 -0
  36. data/lib/wiki/views/client/js/d3/d3.geom.js +825 -0
  37. data/lib/wiki/views/client/js/d3/d3.js +3597 -0
  38. data/lib/wiki/views/client/js/d3/d3.layout.js +1923 -0
  39. data/lib/wiki/views/client/js/d3/d3.time.js +660 -0
  40. data/lib/wiki/views/client/js/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  41. data/lib/wiki/views/client/js/images/ui-icons_222222_256x240.png +0 -0
  42. data/lib/wiki/views/client/js/jquery-1.6.2.min.js +18 -0
  43. data/lib/wiki/views/client/js/jquery-1.7.1.min.js +4 -0
  44. data/lib/wiki/views/client/js/jquery-1.9.1.min.js +5 -0
  45. data/lib/wiki/views/client/js/jquery-migrate-1.1.1.min.js +3 -0
  46. data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.css +5 -0
  47. data/lib/wiki/views/client/js/jquery-ui-1.10.1.custom.min.js +6 -0
  48. data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.css +339 -0
  49. data/lib/wiki/views/client/js/jquery-ui-1.8.16.custom.min.js +315 -0
  50. data/lib/wiki/views/client/js/jquery.ie.cors.js +310 -0
  51. data/lib/wiki/views/client/js/jquery.ui.touch-punch.min.js +11 -0
  52. data/lib/wiki/views/client/js/modernizr.custom.63710.js +824 -0
  53. data/lib/wiki/views/client/js/sockjs-0.3.min.js +27 -0
  54. data/lib/wiki/views/client/js/underscore-min.js +30 -0
  55. data/lib/wiki/views/client/mkplugin.sh +97 -0
  56. data/lib/wiki/views/client/package.json +36 -0
  57. data/lib/wiki/views/client/runtests.html +26 -0
  58. data/lib/wiki/views/client/style.css +339 -0
  59. data/lib/wiki/views/client/test/mocha.css +231 -0
  60. data/lib/wiki/views/client/test/mocha.js +5340 -0
  61. data/lib/wiki/views/client/test/testclient.js +17133 -0
  62. data/lib/wiki/views/client/testclient.coffee +18 -0
  63. data/lib/wiki/views/client/theme/granite.css +59 -0
  64. data/lib/wiki/views/client/theme/stoneSeamless.jpg +0 -0
  65. data/lib/wiki/views/client/twitter-maintainance.jpg +0 -0
  66. data/lib/wiki/views/layout.haml +56 -0
  67. data/lib/wiki/views/oops.haml +5 -0
  68. data/lib/wiki/views/page.haml +20 -0
  69. data/lib/wiki/views/static.html +30 -0
  70. data/lib/wiki/views/view.haml +2 -0
  71. data/wiki.gemspec +28 -0
  72. metadata +121 -0
@@ -0,0 +1,825 @@
1
+ (function(){d3.geom = {};
2
+ /**
3
+ * Computes a contour for a given input grid function using the <a
4
+ * href="http://en.wikipedia.org/wiki/Marching_squares">marching
5
+ * squares</a> algorithm. Returns the contour polygon as an array of points.
6
+ *
7
+ * @param grid a two-input function(x, y) that returns true for values
8
+ * inside the contour and false for values outside the contour.
9
+ * @param start an optional starting point [x, y] on the grid.
10
+ * @returns polygon [[x1, y1], [x2, y2], …]
11
+ */
12
+ d3.geom.contour = function(grid, start) {
13
+ var s = start || d3_geom_contourStart(grid), // starting point
14
+ c = [], // contour polygon
15
+ x = s[0], // current x position
16
+ y = s[1], // current y position
17
+ dx = 0, // next x direction
18
+ dy = 0, // next y direction
19
+ pdx = NaN, // previous x direction
20
+ pdy = NaN, // previous y direction
21
+ i = 0;
22
+
23
+ do {
24
+ // determine marching squares index
25
+ i = 0;
26
+ if (grid(x-1, y-1)) i += 1;
27
+ if (grid(x, y-1)) i += 2;
28
+ if (grid(x-1, y )) i += 4;
29
+ if (grid(x, y )) i += 8;
30
+
31
+ // determine next direction
32
+ if (i === 6) {
33
+ dx = pdy === -1 ? -1 : 1;
34
+ dy = 0;
35
+ } else if (i === 9) {
36
+ dx = 0;
37
+ dy = pdx === 1 ? -1 : 1;
38
+ } else {
39
+ dx = d3_geom_contourDx[i];
40
+ dy = d3_geom_contourDy[i];
41
+ }
42
+
43
+ // update contour polygon
44
+ if (dx != pdx && dy != pdy) {
45
+ c.push([x, y]);
46
+ pdx = dx;
47
+ pdy = dy;
48
+ }
49
+
50
+ x += dx;
51
+ y += dy;
52
+ } while (s[0] != x || s[1] != y);
53
+
54
+ return c;
55
+ };
56
+
57
+ // lookup tables for marching directions
58
+ var d3_geom_contourDx = [1, 0, 1, 1,-1, 0,-1, 1,0, 0,0,0,-1, 0,-1,NaN],
59
+ d3_geom_contourDy = [0,-1, 0, 0, 0,-1, 0, 0,1,-1,1,1, 0,-1, 0,NaN];
60
+
61
+ function d3_geom_contourStart(grid) {
62
+ var x = 0,
63
+ y = 0;
64
+
65
+ // search for a starting point; begin at origin
66
+ // and proceed along outward-expanding diagonals
67
+ while (true) {
68
+ if (grid(x,y)) {
69
+ return [x,y];
70
+ }
71
+ if (x === 0) {
72
+ x = y + 1;
73
+ y = 0;
74
+ } else {
75
+ x = x - 1;
76
+ y = y + 1;
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * Computes the 2D convex hull of a set of points using Graham's scanning
82
+ * algorithm. The algorithm has been implemented as described in Cormen,
83
+ * Leiserson, and Rivest's Introduction to Algorithms. The running time of
84
+ * this algorithm is O(n log n), where n is the number of input points.
85
+ *
86
+ * @param vertices [[x1, y1], [x2, y2], …]
87
+ * @returns polygon [[x1, y1], [x2, y2], …]
88
+ */
89
+ d3.geom.hull = function(vertices) {
90
+ if (vertices.length < 3) return [];
91
+
92
+ var len = vertices.length,
93
+ plen = len - 1,
94
+ points = [],
95
+ stack = [],
96
+ i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
97
+
98
+ // find the starting ref point: leftmost point with the minimum y coord
99
+ for (i=1; i<len; ++i) {
100
+ if (vertices[i][1] < vertices[h][1]) {
101
+ h = i;
102
+ } else if (vertices[i][1] == vertices[h][1]) {
103
+ h = (vertices[i][0] < vertices[h][0] ? i : h);
104
+ }
105
+ }
106
+
107
+ // calculate polar angles from ref point and sort
108
+ for (i=0; i<len; ++i) {
109
+ if (i === h) continue;
110
+ y1 = vertices[i][1] - vertices[h][1];
111
+ x1 = vertices[i][0] - vertices[h][0];
112
+ points.push({angle: Math.atan2(y1, x1), index: i});
113
+ }
114
+ points.sort(function(a, b) { return a.angle - b.angle; });
115
+
116
+ // toss out duplicate angles
117
+ a = points[0].angle;
118
+ v = points[0].index;
119
+ u = 0;
120
+ for (i=1; i<plen; ++i) {
121
+ j = points[i].index;
122
+ if (a == points[i].angle) {
123
+ // keep angle for point most distant from the reference
124
+ x1 = vertices[v][0] - vertices[h][0];
125
+ y1 = vertices[v][1] - vertices[h][1];
126
+ x2 = vertices[j][0] - vertices[h][0];
127
+ y2 = vertices[j][1] - vertices[h][1];
128
+ if ((x1*x1 + y1*y1) >= (x2*x2 + y2*y2)) {
129
+ points[i].index = -1;
130
+ } else {
131
+ points[u].index = -1;
132
+ a = points[i].angle;
133
+ u = i;
134
+ v = j;
135
+ }
136
+ } else {
137
+ a = points[i].angle;
138
+ u = i;
139
+ v = j;
140
+ }
141
+ }
142
+
143
+ // initialize the stack
144
+ stack.push(h);
145
+ for (i=0, j=0; i<2; ++j) {
146
+ if (points[j].index !== -1) {
147
+ stack.push(points[j].index);
148
+ i++;
149
+ }
150
+ }
151
+ sp = stack.length;
152
+
153
+ // do graham's scan
154
+ for (; j<plen; ++j) {
155
+ if (points[j].index === -1) continue; // skip tossed out points
156
+ while (!d3_geom_hullCCW(stack[sp-2], stack[sp-1], points[j].index, vertices)) {
157
+ --sp;
158
+ }
159
+ stack[sp++] = points[j].index;
160
+ }
161
+
162
+ // construct the hull
163
+ var poly = [];
164
+ for (i=0; i<sp; ++i) {
165
+ poly.push(vertices[stack[i]]);
166
+ }
167
+ return poly;
168
+ }
169
+
170
+ // are three points in counter-clockwise order?
171
+ function d3_geom_hullCCW(i1, i2, i3, v) {
172
+ var t, a, b, c, d, e, f;
173
+ t = v[i1]; a = t[0]; b = t[1];
174
+ t = v[i2]; c = t[0]; d = t[1];
175
+ t = v[i3]; e = t[0]; f = t[1];
176
+ return ((f-b)*(c-a) - (d-b)*(e-a)) > 0;
177
+ }
178
+ // Note: requires coordinates to be counterclockwise and convex!
179
+ d3.geom.polygon = function(coordinates) {
180
+
181
+ coordinates.area = function() {
182
+ var i = 0,
183
+ n = coordinates.length,
184
+ a = coordinates[n - 1][0] * coordinates[0][1],
185
+ b = coordinates[n - 1][1] * coordinates[0][0];
186
+ while (++i < n) {
187
+ a += coordinates[i - 1][0] * coordinates[i][1];
188
+ b += coordinates[i - 1][1] * coordinates[i][0];
189
+ }
190
+ return (b - a) * .5;
191
+ };
192
+
193
+ coordinates.centroid = function(k) {
194
+ var i = -1,
195
+ n = coordinates.length - 1,
196
+ x = 0,
197
+ y = 0,
198
+ a,
199
+ b,
200
+ c;
201
+ if (!arguments.length) k = 1 / (6 * coordinates.area());
202
+ while (++i < n) {
203
+ a = coordinates[i];
204
+ b = coordinates[i + 1];
205
+ c = a[0] * b[1] - b[0] * a[1];
206
+ x += (a[0] + b[0]) * c;
207
+ y += (a[1] + b[1]) * c;
208
+ }
209
+ return [x * k, y * k];
210
+ };
211
+
212
+ // The Sutherland-Hodgman clipping algorithm.
213
+ coordinates.clip = function(subject) {
214
+ var input,
215
+ i = -1,
216
+ n = coordinates.length,
217
+ j,
218
+ m,
219
+ a = coordinates[n - 1],
220
+ b,
221
+ c,
222
+ d;
223
+ while (++i < n) {
224
+ input = subject.slice();
225
+ subject.length = 0;
226
+ b = coordinates[i];
227
+ c = input[(m = input.length) - 1];
228
+ j = -1;
229
+ while (++j < m) {
230
+ d = input[j];
231
+ if (d3_geom_polygonInside(d, a, b)) {
232
+ if (!d3_geom_polygonInside(c, a, b)) {
233
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
234
+ }
235
+ subject.push(d);
236
+ } else if (d3_geom_polygonInside(c, a, b)) {
237
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
238
+ }
239
+ c = d;
240
+ }
241
+ a = b;
242
+ }
243
+ return subject;
244
+ };
245
+
246
+ return coordinates;
247
+ };
248
+
249
+ function d3_geom_polygonInside(p, a, b) {
250
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
251
+ }
252
+
253
+ // Intersect two infinite lines cd and ab.
254
+ function d3_geom_polygonIntersect(c, d, a, b) {
255
+ var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0],
256
+ y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1],
257
+ x13 = x1 - x3,
258
+ x21 = x2 - x1,
259
+ x43 = x4 - x3,
260
+ y13 = y1 - y3,
261
+ y21 = y2 - y1,
262
+ y43 = y4 - y3,
263
+ ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21);
264
+ return [x1 + ua * x21, y1 + ua * y21];
265
+ }
266
+ // Adapted from Nicolas Garcia Belmonte's JIT implementation:
267
+ // http://blog.thejit.org/2010/02/12/voronoi-tessellation/
268
+ // http://blog.thejit.org/assets/voronoijs/voronoi.js
269
+ // See lib/jit/LICENSE for details.
270
+
271
+ /**
272
+ * @param vertices [[x1, y1], [x2, y2], …]
273
+ * @returns polygons [[[x1, y1], [x2, y2], …], …]
274
+ */
275
+ d3.geom.voronoi = function(vertices) {
276
+ var polygons = vertices.map(function() { return []; });
277
+
278
+ // Note: we expect the caller to clip the polygons, if needed.
279
+ d3_voronoi_tessellate(vertices, function(e) {
280
+ var s1,
281
+ s2,
282
+ x1,
283
+ x2,
284
+ y1,
285
+ y2;
286
+ if (e.a === 1 && e.b >= 0) {
287
+ s1 = e.ep.r;
288
+ s2 = e.ep.l;
289
+ } else {
290
+ s1 = e.ep.l;
291
+ s2 = e.ep.r;
292
+ }
293
+ if (e.a === 1) {
294
+ y1 = s1 ? s1.y : -1e6;
295
+ x1 = e.c - e.b * y1;
296
+ y2 = s2 ? s2.y : 1e6;
297
+ x2 = e.c - e.b * y2;
298
+ } else {
299
+ x1 = s1 ? s1.x : -1e6;
300
+ y1 = e.c - e.a * x1;
301
+ x2 = s2 ? s2.x : 1e6;
302
+ y2 = e.c - e.a * x2;
303
+ }
304
+ var v1 = [x1, y1],
305
+ v2 = [x2, y2];
306
+ polygons[e.region.l.index].push(v1, v2);
307
+ polygons[e.region.r.index].push(v1, v2);
308
+ });
309
+
310
+ // Reconnect the polygon segments into counterclockwise loops.
311
+ return polygons.map(function(polygon, i) {
312
+ var cx = vertices[i][0],
313
+ cy = vertices[i][1];
314
+ polygon.forEach(function(v) {
315
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
316
+ });
317
+ return polygon.sort(function(a, b) {
318
+ return a.angle - b.angle;
319
+ }).filter(function(d, i) {
320
+ return !i || (d.angle - polygon[i - 1].angle > 1e-10);
321
+ });
322
+ });
323
+ };
324
+
325
+ var d3_voronoi_opposite = {"l": "r", "r": "l"};
326
+
327
+ function d3_voronoi_tessellate(vertices, callback) {
328
+
329
+ var Sites = {
330
+ list: vertices
331
+ .map(function(v, i) {
332
+ return {
333
+ index: i,
334
+ x: v[0],
335
+ y: v[1]
336
+ };
337
+ })
338
+ .sort(function(a, b) {
339
+ return a.y < b.y ? -1
340
+ : a.y > b.y ? 1
341
+ : a.x < b.x ? -1
342
+ : a.x > b.x ? 1
343
+ : 0;
344
+ }),
345
+ bottomSite: null
346
+ };
347
+
348
+ var EdgeList = {
349
+ list: [],
350
+ leftEnd: null,
351
+ rightEnd: null,
352
+
353
+ init: function() {
354
+ EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
355
+ EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
356
+ EdgeList.leftEnd.r = EdgeList.rightEnd;
357
+ EdgeList.rightEnd.l = EdgeList.leftEnd;
358
+ EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
359
+ },
360
+
361
+ createHalfEdge: function(edge, side) {
362
+ return {
363
+ edge: edge,
364
+ side: side,
365
+ vertex: null,
366
+ "l": null,
367
+ "r": null
368
+ };
369
+ },
370
+
371
+ insert: function(lb, he) {
372
+ he.l = lb;
373
+ he.r = lb.r;
374
+ lb.r.l = he;
375
+ lb.r = he;
376
+ },
377
+
378
+ leftBound: function(p) {
379
+ var he = EdgeList.leftEnd;
380
+ do {
381
+ he = he.r;
382
+ } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
383
+ he = he.l;
384
+ return he;
385
+ },
386
+
387
+ del: function(he) {
388
+ he.l.r = he.r;
389
+ he.r.l = he.l;
390
+ he.edge = null;
391
+ },
392
+
393
+ right: function(he) {
394
+ return he.r;
395
+ },
396
+
397
+ left: function(he) {
398
+ return he.l;
399
+ },
400
+
401
+ leftRegion: function(he) {
402
+ return he.edge == null
403
+ ? Sites.bottomSite
404
+ : he.edge.region[he.side];
405
+ },
406
+
407
+ rightRegion: function(he) {
408
+ return he.edge == null
409
+ ? Sites.bottomSite
410
+ : he.edge.region[d3_voronoi_opposite[he.side]];
411
+ }
412
+ };
413
+
414
+ var Geom = {
415
+
416
+ bisect: function(s1, s2) {
417
+ var newEdge = {
418
+ region: {"l": s1, "r": s2},
419
+ ep: {"l": null, "r": null}
420
+ };
421
+
422
+ var dx = s2.x - s1.x,
423
+ dy = s2.y - s1.y,
424
+ adx = dx > 0 ? dx : -dx,
425
+ ady = dy > 0 ? dy : -dy;
426
+
427
+ newEdge.c = s1.x * dx + s1.y * dy
428
+ + (dx * dx + dy * dy) * .5;
429
+
430
+ if (adx > ady) {
431
+ newEdge.a = 1;
432
+ newEdge.b = dy / dx;
433
+ newEdge.c /= dx;
434
+ } else {
435
+ newEdge.b = 1;
436
+ newEdge.a = dx / dy;
437
+ newEdge.c /= dy;
438
+ }
439
+
440
+ return newEdge;
441
+ },
442
+
443
+ intersect: function(el1, el2) {
444
+ var e1 = el1.edge,
445
+ e2 = el2.edge;
446
+ if (!e1 || !e2 || (e1.region.r == e2.region.r)) {
447
+ return null;
448
+ }
449
+ var d = (e1.a * e2.b) - (e1.b * e2.a);
450
+ if (Math.abs(d) < 1e-10) {
451
+ return null;
452
+ }
453
+ var xint = (e1.c * e2.b - e2.c * e1.b) / d,
454
+ yint = (e2.c * e1.a - e1.c * e2.a) / d,
455
+ e1r = e1.region.r,
456
+ e2r = e2.region.r,
457
+ el,
458
+ e;
459
+ if ((e1r.y < e2r.y) ||
460
+ (e1r.y == e2r.y && e1r.x < e2r.x)) {
461
+ el = el1;
462
+ e = e1;
463
+ } else {
464
+ el = el2;
465
+ e = e2;
466
+ }
467
+ var rightOfSite = (xint >= e.region.r.x);
468
+ if ((rightOfSite && (el.side === "l")) ||
469
+ (!rightOfSite && (el.side === "r"))) {
470
+ return null;
471
+ }
472
+ return {
473
+ x: xint,
474
+ y: yint
475
+ };
476
+ },
477
+
478
+ rightOf: function(he, p) {
479
+ var e = he.edge,
480
+ topsite = e.region.r,
481
+ rightOfSite = (p.x > topsite.x);
482
+
483
+ if (rightOfSite && (he.side === "l")) {
484
+ return 1;
485
+ }
486
+ if (!rightOfSite && (he.side === "r")) {
487
+ return 0;
488
+ }
489
+ if (e.a === 1) {
490
+ var dyp = p.y - topsite.y,
491
+ dxp = p.x - topsite.x,
492
+ fast = 0,
493
+ above = 0;
494
+
495
+ if ((!rightOfSite && (e.b < 0)) ||
496
+ (rightOfSite && (e.b >= 0))) {
497
+ above = fast = (dyp >= e.b * dxp);
498
+ } else {
499
+ above = ((p.x + p.y * e.b) > e.c);
500
+ if (e.b < 0) {
501
+ above = !above;
502
+ }
503
+ if (!above) {
504
+ fast = 1;
505
+ }
506
+ }
507
+ if (!fast) {
508
+ var dxs = topsite.x - e.region.l.x;
509
+ above = (e.b * (dxp * dxp - dyp * dyp)) <
510
+ (dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b));
511
+
512
+ if (e.b < 0) {
513
+ above = !above;
514
+ }
515
+ }
516
+ } else /* e.b == 1 */ {
517
+ var yl = e.c - e.a * p.x,
518
+ t1 = p.y - yl,
519
+ t2 = p.x - topsite.x,
520
+ t3 = yl - topsite.y;
521
+
522
+ above = (t1 * t1) > (t2 * t2 + t3 * t3);
523
+ }
524
+ return he.side === "l" ? above : !above;
525
+ },
526
+
527
+ endPoint: function(edge, side, site) {
528
+ edge.ep[side] = site;
529
+ if (!edge.ep[d3_voronoi_opposite[side]]) return;
530
+ callback(edge);
531
+ },
532
+
533
+ distance: function(s, t) {
534
+ var dx = s.x - t.x,
535
+ dy = s.y - t.y;
536
+ return Math.sqrt(dx * dx + dy * dy);
537
+ }
538
+ };
539
+
540
+ var EventQueue = {
541
+ list: [],
542
+
543
+ insert: function(he, site, offset) {
544
+ he.vertex = site;
545
+ he.ystar = site.y + offset;
546
+ for (var i=0, list=EventQueue.list, l=list.length; i<l; i++) {
547
+ var next = list[i];
548
+ if (he.ystar > next.ystar ||
549
+ (he.ystar == next.ystar &&
550
+ site.x > next.vertex.x)) {
551
+ continue;
552
+ } else {
553
+ break;
554
+ }
555
+ }
556
+ list.splice(i, 0, he);
557
+ },
558
+
559
+ del: function(he) {
560
+ for (var i=0, ls=EventQueue.list, l=ls.length; i<l && (ls[i] != he); ++i) {}
561
+ ls.splice(i, 1);
562
+ },
563
+
564
+ empty: function() { return EventQueue.list.length === 0; },
565
+
566
+ nextEvent: function(he) {
567
+ for (var i=0, ls=EventQueue.list, l=ls.length; i<l; ++i) {
568
+ if (ls[i] == he) return ls[i+1];
569
+ }
570
+ return null;
571
+ },
572
+
573
+ min: function() {
574
+ var elem = EventQueue.list[0];
575
+ return {
576
+ x: elem.vertex.x,
577
+ y: elem.ystar
578
+ };
579
+ },
580
+
581
+ extractMin: function() {
582
+ return EventQueue.list.shift();
583
+ }
584
+ };
585
+
586
+ EdgeList.init();
587
+ Sites.bottomSite = Sites.list.shift();
588
+
589
+ var newSite = Sites.list.shift(), newIntStar;
590
+ var lbnd, rbnd, llbnd, rrbnd, bisector;
591
+ var bot, top, temp, p, v;
592
+ var e, pm;
593
+
594
+ while (true) {
595
+ if (!EventQueue.empty()) {
596
+ newIntStar = EventQueue.min();
597
+ }
598
+ if (newSite && (EventQueue.empty()
599
+ || newSite.y < newIntStar.y
600
+ || (newSite.y == newIntStar.y
601
+ && newSite.x < newIntStar.x))) { //new site is smallest
602
+ lbnd = EdgeList.leftBound(newSite);
603
+ rbnd = EdgeList.right(lbnd);
604
+ bot = EdgeList.rightRegion(lbnd);
605
+ e = Geom.bisect(bot, newSite);
606
+ bisector = EdgeList.createHalfEdge(e, "l");
607
+ EdgeList.insert(lbnd, bisector);
608
+ p = Geom.intersect(lbnd, bisector);
609
+ if (p) {
610
+ EventQueue.del(lbnd);
611
+ EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
612
+ }
613
+ lbnd = bisector;
614
+ bisector = EdgeList.createHalfEdge(e, "r");
615
+ EdgeList.insert(lbnd, bisector);
616
+ p = Geom.intersect(bisector, rbnd);
617
+ if (p) {
618
+ EventQueue.insert(bisector, p, Geom.distance(p, newSite));
619
+ }
620
+ newSite = Sites.list.shift();
621
+ } else if (!EventQueue.empty()) { //intersection is smallest
622
+ lbnd = EventQueue.extractMin();
623
+ llbnd = EdgeList.left(lbnd);
624
+ rbnd = EdgeList.right(lbnd);
625
+ rrbnd = EdgeList.right(rbnd);
626
+ bot = EdgeList.leftRegion(lbnd);
627
+ top = EdgeList.rightRegion(rbnd);
628
+ v = lbnd.vertex;
629
+ Geom.endPoint(lbnd.edge, lbnd.side, v);
630
+ Geom.endPoint(rbnd.edge, rbnd.side, v);
631
+ EdgeList.del(lbnd);
632
+ EventQueue.del(rbnd);
633
+ EdgeList.del(rbnd);
634
+ pm = "l";
635
+ if (bot.y > top.y) {
636
+ temp = bot;
637
+ bot = top;
638
+ top = temp;
639
+ pm = "r";
640
+ }
641
+ e = Geom.bisect(bot, top);
642
+ bisector = EdgeList.createHalfEdge(e, pm);
643
+ EdgeList.insert(llbnd, bisector);
644
+ Geom.endPoint(e, d3_voronoi_opposite[pm], v);
645
+ p = Geom.intersect(llbnd, bisector);
646
+ if (p) {
647
+ EventQueue.del(llbnd);
648
+ EventQueue.insert(llbnd, p, Geom.distance(p, bot));
649
+ }
650
+ p = Geom.intersect(bisector, rrbnd);
651
+ if (p) {
652
+ EventQueue.insert(bisector, p, Geom.distance(p, bot));
653
+ }
654
+ } else {
655
+ break;
656
+ }
657
+ }//end while
658
+
659
+ for (lbnd = EdgeList.right(EdgeList.leftEnd);
660
+ lbnd != EdgeList.rightEnd;
661
+ lbnd = EdgeList.right(lbnd)) {
662
+ callback(lbnd.edge);
663
+ }
664
+ }
665
+ /**
666
+ * @param vertices [[x1, y1], [x2, y2], …]
667
+ * @returns triangles [[[x1, y1], [x2, y2], [x3, y3]], …]
668
+ */
669
+ d3.geom.delaunay = function(vertices) {
670
+ var edges = vertices.map(function() { return []; }),
671
+ triangles = [];
672
+
673
+ // Use the Voronoi tessellation to determine Delaunay edges.
674
+ d3_voronoi_tessellate(vertices, function(e) {
675
+ edges[e.region.l.index].push(vertices[e.region.r.index]);
676
+ });
677
+
678
+ // Reconnect the edges into counterclockwise triangles.
679
+ edges.forEach(function(edge, i) {
680
+ var v = vertices[i],
681
+ cx = v[0],
682
+ cy = v[1];
683
+ edge.forEach(function(v) {
684
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
685
+ });
686
+ edge.sort(function(a, b) {
687
+ return a.angle - b.angle;
688
+ });
689
+ for (var j = 0, m = edge.length - 1; j < m; j++) {
690
+ triangles.push([v, edge[j], edge[j + 1]]);
691
+ }
692
+ });
693
+
694
+ return triangles;
695
+ };
696
+ // Constructs a new quadtree for the specified array of points. A quadtree is a
697
+ // two-dimensional recursive spatial subdivision. This implementation uses
698
+ // square partitions, dividing each square into four equally-sized squares. Each
699
+ // point exists in a unique node; if multiple points are in the same position,
700
+ // some points may be stored on internal nodes rather than leaf nodes. Quadtrees
701
+ // can be used to accelerate various spatial operations, such as the Barnes-Hut
702
+ // approximation for computing n-body forces, or collision detection.
703
+ d3.geom.quadtree = function(points, x1, y1, x2, y2) {
704
+ var p,
705
+ i = -1,
706
+ n = points.length;
707
+
708
+ // Type conversion for deprecated API.
709
+ if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint);
710
+
711
+ // Allow bounds to be specified explicitly.
712
+ if (arguments.length < 5) {
713
+ if (arguments.length === 3) {
714
+ y2 = x2 = y1;
715
+ y1 = x1;
716
+ } else {
717
+ x1 = y1 = Infinity;
718
+ x2 = y2 = -Infinity;
719
+
720
+ // Compute bounds.
721
+ while (++i < n) {
722
+ p = points[i];
723
+ if (p.x < x1) x1 = p.x;
724
+ if (p.y < y1) y1 = p.y;
725
+ if (p.x > x2) x2 = p.x;
726
+ if (p.y > y2) y2 = p.y;
727
+ }
728
+
729
+ // Squarify the bounds.
730
+ var dx = x2 - x1,
731
+ dy = y2 - y1;
732
+ if (dx > dy) y2 = y1 + dx;
733
+ else x2 = x1 + dy;
734
+ }
735
+ }
736
+
737
+ // Recursively inserts the specified point p at the node n or one of its
738
+ // descendants. The bounds are defined by [x1, x2] and [y1, y2].
739
+ function insert(n, p, x1, y1, x2, y2) {
740
+ if (isNaN(p.x) || isNaN(p.y)) return; // ignore invalid points
741
+ if (n.leaf) {
742
+ var v = n.point;
743
+ if (v) {
744
+ // If the point at this leaf node is at the same position as the new
745
+ // point we are adding, we leave the point associated with the
746
+ // internal node while adding the new point to a child node. This
747
+ // avoids infinite recursion.
748
+ if ((Math.abs(v.x - p.x) + Math.abs(v.y - p.y)) < .01) {
749
+ insertChild(n, p, x1, y1, x2, y2);
750
+ } else {
751
+ n.point = null;
752
+ insertChild(n, v, x1, y1, x2, y2);
753
+ insertChild(n, p, x1, y1, x2, y2);
754
+ }
755
+ } else {
756
+ n.point = p;
757
+ }
758
+ } else {
759
+ insertChild(n, p, x1, y1, x2, y2);
760
+ }
761
+ }
762
+
763
+ // Recursively inserts the specified point p into a descendant of node n. The
764
+ // bounds are defined by [x1, x2] and [y1, y2].
765
+ function insertChild(n, p, x1, y1, x2, y2) {
766
+ // Compute the split point, and the quadrant in which to insert p.
767
+ var sx = (x1 + x2) * .5,
768
+ sy = (y1 + y2) * .5,
769
+ right = p.x >= sx,
770
+ bottom = p.y >= sy,
771
+ i = (bottom << 1) + right;
772
+
773
+ // Recursively insert into the child node.
774
+ n.leaf = false;
775
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
776
+
777
+ // Update the bounds as we recurse.
778
+ if (right) x1 = sx; else x2 = sx;
779
+ if (bottom) y1 = sy; else y2 = sy;
780
+ insert(n, p, x1, y1, x2, y2);
781
+ }
782
+
783
+ // Create the root node.
784
+ var root = d3_geom_quadtreeNode();
785
+
786
+ root.add = function(p) {
787
+ insert(root, p, x1, y1, x2, y2);
788
+ };
789
+
790
+ root.visit = function(f) {
791
+ d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
792
+ };
793
+
794
+ // Insert all points.
795
+ points.forEach(root.add);
796
+ return root;
797
+ };
798
+
799
+ function d3_geom_quadtreeNode() {
800
+ return {
801
+ leaf: true,
802
+ nodes: [],
803
+ point: null
804
+ };
805
+ }
806
+
807
+ function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
808
+ if (!f(node, x1, y1, x2, y2)) {
809
+ var sx = (x1 + x2) * .5,
810
+ sy = (y1 + y2) * .5,
811
+ children = node.nodes;
812
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
813
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
814
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
815
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
816
+ }
817
+ }
818
+
819
+ function d3_geom_quadtreePoint(p) {
820
+ return {
821
+ x: p[0],
822
+ y: p[1]
823
+ };
824
+ }
825
+ })();