foliage 0.1.0

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 (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
+ })();