62 lines
1.9 KiB
JavaScript
62 lines
1.9 KiB
JavaScript
export default function(d) {
|
|
if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
|
|
|
|
var parent,
|
|
node = this._root,
|
|
retainer,
|
|
previous,
|
|
next,
|
|
x0 = this._x0,
|
|
y0 = this._y0,
|
|
x1 = this._x1,
|
|
y1 = this._y1,
|
|
x,
|
|
y,
|
|
xm,
|
|
ym,
|
|
right,
|
|
bottom,
|
|
i,
|
|
j;
|
|
|
|
// If the tree is empty, initialize the root as a leaf.
|
|
if (!node) return this;
|
|
|
|
// Find the leaf node for the point.
|
|
// While descending, also retain the deepest parent with a non-removed sibling.
|
|
if (node.length) while (true) {
|
|
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
|
|
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
|
|
if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
|
|
if (!node.length) break;
|
|
if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
|
|
}
|
|
|
|
// Find the point to remove.
|
|
while (node.data !== d) if (!(previous = node, node = node.next)) return this;
|
|
if (next = node.next) delete node.next;
|
|
|
|
// If there are multiple coincident points, remove just the point.
|
|
if (previous) return (next ? previous.next = next : delete previous.next), this;
|
|
|
|
// If this is the root point, remove it.
|
|
if (!parent) return this._root = next, this;
|
|
|
|
// Remove this leaf.
|
|
next ? parent[i] = next : delete parent[i];
|
|
|
|
// If the parent now contains exactly one leaf, collapse superfluous parents.
|
|
if ((node = parent[0] || parent[1] || parent[2] || parent[3])
|
|
&& node === (parent[3] || parent[2] || parent[1] || parent[0])
|
|
&& !node.length) {
|
|
if (retainer) retainer[j] = node;
|
|
else this._root = node;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
export function removeAll(data) {
|
|
for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
|
|
return this;
|
|
}
|