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; | |
} | |