add.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. export default function(d) {
  2. const x = +this._x.call(null, d),
  3. y = +this._y.call(null, d);
  4. return add(this.cover(x, y), x, y, d);
  5. }
  6. function add(tree, x, y, d) {
  7. if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
  8. var parent,
  9. node = tree._root,
  10. leaf = {data: d},
  11. x0 = tree._x0,
  12. y0 = tree._y0,
  13. x1 = tree._x1,
  14. y1 = tree._y1,
  15. xm,
  16. ym,
  17. xp,
  18. yp,
  19. right,
  20. bottom,
  21. i,
  22. j;
  23. // If the tree is empty, initialize the root as a leaf.
  24. if (!node) return tree._root = leaf, tree;
  25. // Find the existing leaf for the new point, or add it.
  26. while (node.length) {
  27. if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
  28. if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
  29. if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
  30. }
  31. // Is the new point is exactly coincident with the existing point?
  32. xp = +tree._x.call(null, node.data);
  33. yp = +tree._y.call(null, node.data);
  34. if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
  35. // Otherwise, split the leaf node until the old and new point are separated.
  36. do {
  37. parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
  38. if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
  39. if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
  40. } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
  41. return parent[j] = node, parent[i] = leaf, tree;
  42. }
  43. export function addAll(data) {
  44. var d, i, n = data.length,
  45. x,
  46. y,
  47. xz = new Array(n),
  48. yz = new Array(n),
  49. x0 = Infinity,
  50. y0 = Infinity,
  51. x1 = -Infinity,
  52. y1 = -Infinity;
  53. // Compute the points and their extent.
  54. for (i = 0; i < n; ++i) {
  55. if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
  56. xz[i] = x;
  57. yz[i] = y;
  58. if (x < x0) x0 = x;
  59. if (x > x1) x1 = x;
  60. if (y < y0) y0 = y;
  61. if (y > y1) y1 = y;
  62. }
  63. // If there were no (valid) points, abort.
  64. if (x0 > x1 || y0 > y1) return this;
  65. // Expand the tree to cover the new points.
  66. this.cover(x0, y0).cover(x1, y1);
  67. // Add the new points.
  68. for (i = 0; i < n; ++i) {
  69. add(this, xz[i], yz[i], data[i]);
  70. }
  71. return this;
  72. }