foliage 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +9 -0
  4. data/app/assets/images/.keep +0 -0
  5. data/app/assets/images/map/marker/icon-2x.png +0 -0
  6. data/app/assets/images/map/marker/icon.png +0 -0
  7. data/app/assets/images/map/marker/icon.svg +67 -0
  8. data/app/assets/images/map/marker/shadow.png +0 -0
  9. data/app/assets/javascripts/core_ext.js.coffee +61 -0
  10. data/app/assets/javascripts/foliage.js.coffee +23 -0
  11. data/app/assets/javascripts/foliage/band.js.coffee +99 -0
  12. data/app/assets/javascripts/foliage/bubbles.js.coffee +77 -0
  13. data/app/assets/javascripts/foliage/categories.js.coffee +70 -0
  14. data/app/assets/javascripts/foliage/choropleth.js.coffee +51 -0
  15. data/app/assets/javascripts/foliage/color.js.coffee +39 -0
  16. data/app/assets/javascripts/foliage/gradient.js.coffee +72 -0
  17. data/app/assets/javascripts/foliage/heatmap.js.coffee +49 -0
  18. data/app/assets/javascripts/foliage/leaf.js.coffee +422 -0
  19. data/app/assets/javascripts/foliage/path.js.coffee +76 -0
  20. data/app/assets/javascripts/foliage/paths.js.coffee +131 -0
  21. data/app/assets/javascripts/foliage/point_group.js.coffee +83 -0
  22. data/app/assets/javascripts/foliage/points.js.coffee +79 -0
  23. data/app/assets/javascripts/foliage/simple.js.coffee +35 -0
  24. data/app/assets/javascripts/leaflet/geographic_util.js.coffee +23 -0
  25. data/app/assets/javascripts/leaflet/ghost_label.js.coffee +100 -0
  26. data/app/assets/javascripts/leaflet/ghost_label_cluster.js.coffee +192 -0
  27. data/app/assets/javascripts/leaflet/layers_scheduler.js.coffee +57 -0
  28. data/app/assets/javascripts/leaflet/reactive_measure.js.coffee +414 -0
  29. data/app/assets/stylesheets/all.scss +16 -0
  30. data/app/assets/stylesheets/application.css +15 -0
  31. data/app/assets/stylesheets/compass/reset.scss +3 -0
  32. data/app/assets/stylesheets/compass/reset/utilities.scss +142 -0
  33. data/app/assets/stylesheets/leaflet.scss +1093 -0
  34. data/app/assets/stylesheets/leaflet/label.scss +40 -0
  35. data/app/assets/stylesheets/leaflet/tooltip.scss +42 -0
  36. data/app/assets/stylesheets/mixins.scss +131 -0
  37. data/app/assets/stylesheets/reset.scss +89 -0
  38. data/app/assets/stylesheets/variables.scss +47 -0
  39. data/app/helpers/foliage_helper.rb +23 -0
  40. data/lib/foliage.rb +9 -0
  41. data/lib/foliage/leaf.rb +235 -0
  42. data/lib/foliage/rails.rb +2 -0
  43. data/lib/foliage/rails/engine.rb +7 -0
  44. data/lib/foliage/rails/integration.rb +8 -0
  45. data/lib/foliage/version.rb +3 -0
  46. data/vendor/assets/javascripts/.keep +0 -0
  47. data/vendor/assets/javascripts/autosize.js +211 -0
  48. data/vendor/assets/javascripts/geographiclib.js +3074 -0
  49. data/vendor/assets/javascripts/leaflet.js.erb +9175 -0
  50. data/vendor/assets/javascripts/leaflet/draw.js +3573 -0
  51. data/vendor/assets/javascripts/leaflet/easy-button.js +366 -0
  52. data/vendor/assets/javascripts/leaflet/fullscreen.js +162 -0
  53. data/vendor/assets/javascripts/leaflet/heatmap.js +142 -0
  54. data/vendor/assets/javascripts/leaflet/label.js +545 -0
  55. data/vendor/assets/javascripts/leaflet/measure.js +6966 -0
  56. data/vendor/assets/javascripts/leaflet/modal.js +364 -0
  57. data/vendor/assets/javascripts/leaflet/providers.js +479 -0
  58. data/vendor/assets/javascripts/rbush.js +621 -0
  59. data/vendor/assets/stylesheets/.keep +0 -0
  60. data/vendor/assets/stylesheets/bootstrap/mixins.scss +55 -0
  61. data/vendor/assets/stylesheets/bootstrap/variables.scss +10 -0
  62. data/vendor/assets/stylesheets/leaflet.scss +479 -0
  63. data/vendor/assets/stylesheets/leaflet/draw.scss +282 -0
  64. data/vendor/assets/stylesheets/leaflet/easy-button.scss +56 -0
  65. data/vendor/assets/stylesheets/leaflet/fullscreen.scss +2 -0
  66. data/vendor/assets/stylesheets/leaflet/measure.scss +168 -0
  67. data/vendor/assets/stylesheets/leaflet/modal.scss +85 -0
  68. metadata +171 -0
@@ -0,0 +1,621 @@
1
+ /*
2
+ (c) 2015, Vladimir Agafonkin
3
+ RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
4
+ https://github.com/mourner/rbush
5
+ */
6
+
7
+ (function () {
8
+ 'use strict';
9
+
10
+ function rbush(maxEntries, format) {
11
+
12
+ // jshint newcap: false, validthis: true
13
+ if (!(this instanceof rbush)) return new rbush(maxEntries, format);
14
+
15
+ // max entries in a node is 9 by default; min node fill is 40% for best performance
16
+ this._maxEntries = Math.max(4, maxEntries || 9);
17
+ this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
18
+
19
+ if (format) {
20
+ this._initFormat(format);
21
+ }
22
+
23
+ this.clear();
24
+ }
25
+
26
+ rbush.prototype = {
27
+
28
+ all: function () {
29
+ return this._all(this.data, []);
30
+ },
31
+
32
+ search: function (bbox) {
33
+
34
+ var node = this.data,
35
+ result = [],
36
+ toBBox = this.toBBox;
37
+
38
+ if (!intersects(bbox, node.bbox)) return result;
39
+
40
+ var nodesToSearch = [],
41
+ i, len, child, childBBox;
42
+
43
+ while (node) {
44
+ for (i = 0, len = node.children.length; i < len; i++) {
45
+
46
+ child = node.children[i];
47
+ childBBox = node.leaf ? toBBox(child) : child.bbox;
48
+
49
+ if (intersects(bbox, childBBox)) {
50
+ if (node.leaf) result.push(child);
51
+ else if (contains(bbox, childBBox)) this._all(child, result);
52
+ else nodesToSearch.push(child);
53
+ }
54
+ }
55
+ node = nodesToSearch.pop();
56
+ }
57
+
58
+ return result;
59
+ },
60
+
61
+ collides: function (bbox) {
62
+
63
+ var node = this.data,
64
+ toBBox = this.toBBox;
65
+
66
+ if (!intersects(bbox, node.bbox)) return false;
67
+
68
+ var nodesToSearch = [],
69
+ i, len, child, childBBox;
70
+
71
+ while (node) {
72
+ for (i = 0, len = node.children.length; i < len; i++) {
73
+
74
+ child = node.children[i];
75
+ childBBox = node.leaf ? toBBox(child) : child.bbox;
76
+
77
+ if (intersects(bbox, childBBox)) {
78
+ if (node.leaf || contains(bbox, childBBox)) return true;
79
+ nodesToSearch.push(child);
80
+ }
81
+ }
82
+ node = nodesToSearch.pop();
83
+ }
84
+
85
+ return false;
86
+ },
87
+
88
+ load: function (data) {
89
+ if (!(data && data.length)) return this;
90
+
91
+ if (data.length < this._minEntries) {
92
+ for (var i = 0, len = data.length; i < len; i++) {
93
+ this.insert(data[i]);
94
+ }
95
+ return this;
96
+ }
97
+
98
+ // recursively build the tree with the given data from stratch using OMT algorithm
99
+ var node = this._build(data.slice(), 0, data.length - 1, 0);
100
+
101
+ if (!this.data.children.length) {
102
+ // save as is if tree is empty
103
+ this.data = node;
104
+
105
+ } else if (this.data.height === node.height) {
106
+ // split root if trees have the same height
107
+ this._splitRoot(this.data, node);
108
+
109
+ } else {
110
+ if (this.data.height < node.height) {
111
+ // swap trees if inserted one is bigger
112
+ var tmpNode = this.data;
113
+ this.data = node;
114
+ node = tmpNode;
115
+ }
116
+
117
+ // insert the small tree into the large tree at appropriate level
118
+ this._insert(node, this.data.height - node.height - 1, true);
119
+ }
120
+
121
+ return this;
122
+ },
123
+
124
+ insert: function (item) {
125
+ if (item) this._insert(item, this.data.height - 1);
126
+ return this;
127
+ },
128
+
129
+ clear: function () {
130
+ this.data = {
131
+ children: [],
132
+ height: 1,
133
+ bbox: empty(),
134
+ leaf: true
135
+ };
136
+ return this;
137
+ },
138
+
139
+ remove: function (item) {
140
+ if (!item) return this;
141
+
142
+ var node = this.data,
143
+ bbox = this.toBBox(item),
144
+ path = [],
145
+ indexes = [],
146
+ i, parent, index, goingUp;
147
+
148
+ // depth-first iterative tree traversal
149
+ while (node || path.length) {
150
+
151
+ if (!node) { // go up
152
+ node = path.pop();
153
+ parent = path[path.length - 1];
154
+ i = indexes.pop();
155
+ goingUp = true;
156
+ }
157
+
158
+ if (node.leaf) { // check current node
159
+ index = node.children.indexOf(item);
160
+
161
+ if (index !== -1) {
162
+ // item found, remove the item and condense tree upwards
163
+ node.children.splice(index, 1);
164
+ path.push(node);
165
+ this._condense(path);
166
+ return this;
167
+ }
168
+ }
169
+
170
+ if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down
171
+ path.push(node);
172
+ indexes.push(i);
173
+ i = 0;
174
+ parent = node;
175
+ node = node.children[0];
176
+
177
+ } else if (parent) { // go right
178
+ i++;
179
+ node = parent.children[i];
180
+ goingUp = false;
181
+
182
+ } else node = null; // nothing found
183
+ }
184
+
185
+ return this;
186
+ },
187
+
188
+ toBBox: function (item) { return item; },
189
+
190
+ compareMinX: function (a, b) { return a[0] - b[0]; },
191
+ compareMinY: function (a, b) { return a[1] - b[1]; },
192
+
193
+ toJSON: function () { return this.data; },
194
+
195
+ fromJSON: function (data) {
196
+ this.data = data;
197
+ return this;
198
+ },
199
+
200
+ _all: function (node, result) {
201
+ var nodesToSearch = [];
202
+ while (node) {
203
+ if (node.leaf) result.push.apply(result, node.children);
204
+ else nodesToSearch.push.apply(nodesToSearch, node.children);
205
+
206
+ node = nodesToSearch.pop();
207
+ }
208
+ return result;
209
+ },
210
+
211
+ _build: function (items, left, right, height) {
212
+
213
+ var N = right - left + 1,
214
+ M = this._maxEntries,
215
+ node;
216
+
217
+ if (N <= M) {
218
+ // reached leaf level; return leaf
219
+ node = {
220
+ children: items.slice(left, right + 1),
221
+ height: 1,
222
+ bbox: null,
223
+ leaf: true
224
+ };
225
+ calcBBox(node, this.toBBox);
226
+ return node;
227
+ }
228
+
229
+ if (!height) {
230
+ // target height of the bulk-loaded tree
231
+ height = Math.ceil(Math.log(N) / Math.log(M));
232
+
233
+ // target number of root entries to maximize storage utilization
234
+ M = Math.ceil(N / Math.pow(M, height - 1));
235
+ }
236
+
237
+ node = {
238
+ children: [],
239
+ height: height,
240
+ bbox: null,
241
+ leaf: false
242
+ };
243
+
244
+ // split the items into M mostly square tiles
245
+
246
+ var N2 = Math.ceil(N / M),
247
+ N1 = N2 * Math.ceil(Math.sqrt(M)),
248
+ i, j, right2, right3;
249
+
250
+ multiSelect(items, left, right, N1, this.compareMinX);
251
+
252
+ for (i = left; i <= right; i += N1) {
253
+
254
+ right2 = Math.min(i + N1 - 1, right);
255
+
256
+ multiSelect(items, i, right2, N2, this.compareMinY);
257
+
258
+ for (j = i; j <= right2; j += N2) {
259
+
260
+ right3 = Math.min(j + N2 - 1, right2);
261
+
262
+ // pack each entry recursively
263
+ node.children.push(this._build(items, j, right3, height - 1));
264
+ }
265
+ }
266
+
267
+ calcBBox(node, this.toBBox);
268
+
269
+ return node;
270
+ },
271
+
272
+ _chooseSubtree: function (bbox, node, level, path) {
273
+
274
+ var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
275
+
276
+ while (true) {
277
+ path.push(node);
278
+
279
+ if (node.leaf || path.length - 1 === level) break;
280
+
281
+ minArea = minEnlargement = Infinity;
282
+
283
+ for (i = 0, len = node.children.length; i < len; i++) {
284
+ child = node.children[i];
285
+ area = bboxArea(child.bbox);
286
+ enlargement = enlargedArea(bbox, child.bbox) - area;
287
+
288
+ // choose entry with the least area enlargement
289
+ if (enlargement < minEnlargement) {
290
+ minEnlargement = enlargement;
291
+ minArea = area < minArea ? area : minArea;
292
+ targetNode = child;
293
+
294
+ } else if (enlargement === minEnlargement) {
295
+ // otherwise choose one with the smallest area
296
+ if (area < minArea) {
297
+ minArea = area;
298
+ targetNode = child;
299
+ }
300
+ }
301
+ }
302
+
303
+ node = targetNode;
304
+ }
305
+
306
+ return node;
307
+ },
308
+
309
+ _insert: function (item, level, isNode) {
310
+
311
+ var toBBox = this.toBBox,
312
+ bbox = isNode ? item.bbox : toBBox(item),
313
+ insertPath = [];
314
+
315
+ // find the best node for accommodating the item, saving all nodes along the path too
316
+ var node = this._chooseSubtree(bbox, this.data, level, insertPath);
317
+
318
+ // put the item into the node
319
+ node.children.push(item);
320
+ extend(node.bbox, bbox);
321
+
322
+ // split on node overflow; propagate upwards if necessary
323
+ while (level >= 0) {
324
+ if (insertPath[level].children.length > this._maxEntries) {
325
+ this._split(insertPath, level);
326
+ level--;
327
+ } else break;
328
+ }
329
+
330
+ // adjust bboxes along the insertion path
331
+ this._adjustParentBBoxes(bbox, insertPath, level);
332
+ },
333
+
334
+ // split overflowed node into two
335
+ _split: function (insertPath, level) {
336
+
337
+ var node = insertPath[level],
338
+ M = node.children.length,
339
+ m = this._minEntries;
340
+
341
+ this._chooseSplitAxis(node, m, M);
342
+
343
+ var splitIndex = this._chooseSplitIndex(node, m, M);
344
+
345
+ var newNode = {
346
+ children: node.children.splice(splitIndex, node.children.length - splitIndex),
347
+ height: node.height,
348
+ bbox: null,
349
+ leaf: false
350
+ };
351
+
352
+ if (node.leaf) newNode.leaf = true;
353
+
354
+ calcBBox(node, this.toBBox);
355
+ calcBBox(newNode, this.toBBox);
356
+
357
+ if (level) insertPath[level - 1].children.push(newNode);
358
+ else this._splitRoot(node, newNode);
359
+ },
360
+
361
+ _splitRoot: function (node, newNode) {
362
+ // split root node
363
+ this.data = {
364
+ children: [node, newNode],
365
+ height: node.height + 1,
366
+ bbox: null,
367
+ leaf: false
368
+ };
369
+ calcBBox(this.data, this.toBBox);
370
+ },
371
+
372
+ _chooseSplitIndex: function (node, m, M) {
373
+
374
+ var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
375
+
376
+ minOverlap = minArea = Infinity;
377
+
378
+ for (i = m; i <= M - m; i++) {
379
+ bbox1 = distBBox(node, 0, i, this.toBBox);
380
+ bbox2 = distBBox(node, i, M, this.toBBox);
381
+
382
+ overlap = intersectionArea(bbox1, bbox2);
383
+ area = bboxArea(bbox1) + bboxArea(bbox2);
384
+
385
+ // choose distribution with minimum overlap
386
+ if (overlap < minOverlap) {
387
+ minOverlap = overlap;
388
+ index = i;
389
+
390
+ minArea = area < minArea ? area : minArea;
391
+
392
+ } else if (overlap === minOverlap) {
393
+ // otherwise choose distribution with minimum area
394
+ if (area < minArea) {
395
+ minArea = area;
396
+ index = i;
397
+ }
398
+ }
399
+ }
400
+
401
+ return index;
402
+ },
403
+
404
+ // sorts node children by the best axis for split
405
+ _chooseSplitAxis: function (node, m, M) {
406
+
407
+ var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
408
+ compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
409
+ xMargin = this._allDistMargin(node, m, M, compareMinX),
410
+ yMargin = this._allDistMargin(node, m, M, compareMinY);
411
+
412
+ // if total distributions margin value is minimal for x, sort by minX,
413
+ // otherwise it's already sorted by minY
414
+ if (xMargin < yMargin) node.children.sort(compareMinX);
415
+ },
416
+
417
+ // total margin of all possible split distributions where each node is at least m full
418
+ _allDistMargin: function (node, m, M, compare) {
419
+
420
+ node.children.sort(compare);
421
+
422
+ var toBBox = this.toBBox,
423
+ leftBBox = distBBox(node, 0, m, toBBox),
424
+ rightBBox = distBBox(node, M - m, M, toBBox),
425
+ margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
426
+ i, child;
427
+
428
+ for (i = m; i < M - m; i++) {
429
+ child = node.children[i];
430
+ extend(leftBBox, node.leaf ? toBBox(child) : child.bbox);
431
+ margin += bboxMargin(leftBBox);
432
+ }
433
+
434
+ for (i = M - m - 1; i >= m; i--) {
435
+ child = node.children[i];
436
+ extend(rightBBox, node.leaf ? toBBox(child) : child.bbox);
437
+ margin += bboxMargin(rightBBox);
438
+ }
439
+
440
+ return margin;
441
+ },
442
+
443
+ _adjustParentBBoxes: function (bbox, path, level) {
444
+ // adjust bboxes along the given tree path
445
+ for (var i = level; i >= 0; i--) {
446
+ extend(path[i].bbox, bbox);
447
+ }
448
+ },
449
+
450
+ _condense: function (path) {
451
+ // go through the path, removing empty nodes and updating bboxes
452
+ for (var i = path.length - 1, siblings; i >= 0; i--) {
453
+ if (path[i].children.length === 0) {
454
+ if (i > 0) {
455
+ siblings = path[i - 1].children;
456
+ siblings.splice(siblings.indexOf(path[i]), 1);
457
+
458
+ } else this.clear();
459
+
460
+ } else calcBBox(path[i], this.toBBox);
461
+ }
462
+ },
463
+
464
+ _initFormat: function (format) {
465
+ // data format (minX, minY, maxX, maxY accessors)
466
+
467
+ // uses eval-type function compilation instead of just accepting a toBBox function
468
+ // because the algorithms are very sensitive to sorting functions performance,
469
+ // so they should be dead simple and without inner calls
470
+
471
+ // jshint evil: true
472
+
473
+ var compareArr = ['return a', ' - b', ';'];
474
+
475
+ this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
476
+ this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
477
+
478
+ this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
479
+ }
480
+ };
481
+
482
+
483
+ // calculate node's bbox from bboxes of its children
484
+ function calcBBox(node, toBBox) {
485
+ node.bbox = distBBox(node, 0, node.children.length, toBBox);
486
+ }
487
+
488
+ // min bounding rectangle of node children from k to p-1
489
+ function distBBox(node, k, p, toBBox) {
490
+ var bbox = empty();
491
+
492
+ for (var i = k, child; i < p; i++) {
493
+ child = node.children[i];
494
+ extend(bbox, node.leaf ? toBBox(child) : child.bbox);
495
+ }
496
+
497
+ return bbox;
498
+ }
499
+
500
+ function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; }
501
+
502
+ function extend(a, b) {
503
+ a[0] = Math.min(a[0], b[0]);
504
+ a[1] = Math.min(a[1], b[1]);
505
+ a[2] = Math.max(a[2], b[2]);
506
+ a[3] = Math.max(a[3], b[3]);
507
+ return a;
508
+ }
509
+
510
+ function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; }
511
+ function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; }
512
+
513
+ function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); }
514
+ function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); }
515
+
516
+ function enlargedArea(a, b) {
517
+ return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
518
+ (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
519
+ }
520
+
521
+ function intersectionArea(a, b) {
522
+ var minX = Math.max(a[0], b[0]),
523
+ minY = Math.max(a[1], b[1]),
524
+ maxX = Math.min(a[2], b[2]),
525
+ maxY = Math.min(a[3], b[3]);
526
+
527
+ return Math.max(0, maxX - minX) *
528
+ Math.max(0, maxY - minY);
529
+ }
530
+
531
+ function contains(a, b) {
532
+ return a[0] <= b[0] &&
533
+ a[1] <= b[1] &&
534
+ b[2] <= a[2] &&
535
+ b[3] <= a[3];
536
+ }
537
+
538
+ function intersects(a, b) {
539
+ return b[0] <= a[2] &&
540
+ b[1] <= a[3] &&
541
+ b[2] >= a[0] &&
542
+ b[3] >= a[1];
543
+ }
544
+
545
+ // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
546
+ // combines selection algorithm with binary divide & conquer approach
547
+
548
+ function multiSelect(arr, left, right, n, compare) {
549
+ var stack = [left, right],
550
+ mid;
551
+
552
+ while (stack.length) {
553
+ right = stack.pop();
554
+ left = stack.pop();
555
+
556
+ if (right - left <= n) continue;
557
+
558
+ mid = left + Math.ceil((right - left) / n / 2) * n;
559
+ select(arr, left, right, mid, compare);
560
+
561
+ stack.push(left, mid, mid, right);
562
+ }
563
+ }
564
+
565
+ // Floyd-Rivest selection algorithm:
566
+ // sort an array between left and right (inclusive) so that the smallest k elements come first (unordered)
567
+ function select(arr, left, right, k, compare) {
568
+ var n, i, z, s, sd, newLeft, newRight, t, j;
569
+
570
+ while (right > left) {
571
+ if (right - left > 600) {
572
+ n = right - left + 1;
573
+ i = k - left + 1;
574
+ z = Math.log(n);
575
+ s = 0.5 * Math.exp(2 * z / 3);
576
+ sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1);
577
+ newLeft = Math.max(left, Math.floor(k - i * s / n + sd));
578
+ newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd));
579
+ select(arr, newLeft, newRight, k, compare);
580
+ }
581
+
582
+ t = arr[k];
583
+ i = left;
584
+ j = right;
585
+
586
+ swap(arr, left, k);
587
+ if (compare(arr[right], t) > 0) swap(arr, left, right);
588
+
589
+ while (i < j) {
590
+ swap(arr, i, j);
591
+ i++;
592
+ j--;
593
+ while (compare(arr[i], t) < 0) i++;
594
+ while (compare(arr[j], t) > 0) j--;
595
+ }
596
+
597
+ if (compare(arr[left], t) === 0) swap(arr, left, j);
598
+ else {
599
+ j++;
600
+ swap(arr, j, right);
601
+ }
602
+
603
+ if (j <= k) left = j + 1;
604
+ if (k <= j) right = j - 1;
605
+ }
606
+ }
607
+
608
+ function swap(arr, i, j) {
609
+ var tmp = arr[i];
610
+ arr[i] = arr[j];
611
+ arr[j] = tmp;
612
+ }
613
+
614
+
615
+ // export as AMD/CommonJS module or global variable
616
+ if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; });
617
+ else if (typeof module !== 'undefined') module.exports = rbush;
618
+ else if (typeof self !== 'undefined') self.rbush = rbush;
619
+ else window.rbush = rbush;
620
+
621
+ })();