Skip to content

Commit

Permalink
Allow records to be removed.
Browse files Browse the repository at this point in the history
This adds a new method to all crossfilter instances, allowing the
currently-selected records to be removed, e.g.

  var db = crossfilter([1, 2, 3]),
      dimension = db.dimension(Number);
  dimension.filter(1);
  db.remove(); // removes a single record (1), leaving [2, 3]
  • Loading branch information
jasondavies committed Aug 17, 2013
1 parent 60b1d81 commit e645b9e
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 3 deletions.
63 changes: 62 additions & 1 deletion crossfilter.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ if (typeof Uint8Array !== "undefined") {
crossfilter_array32 = function(n) { return new Uint32Array(n); };

crossfilter_arrayLengthen = function(array, length) {
if (array.length >= length) return array;
var copy = new array.constructor(length);
copy.set(array);
return copy;
Expand Down Expand Up @@ -517,6 +518,7 @@ exports.crossfilter = crossfilter;
function crossfilter() {
var crossfilter = {
add: add,
remove: removeData,
dimension: dimension,
groupAll: groupAll,
size: size
Expand All @@ -528,7 +530,8 @@ function crossfilter() {
M = 8, // number of dimensions that can fit in `filters`
filters = crossfilter_array8(0), // M bits per record; 1 is filtered out
filterListeners = [], // when the filters change
dataListeners = []; // when data is added
dataListeners = [], // when data is added
removeDataListeners = []; // when data is removed

// Adds the specified new records to this crossfilter.
function add(newData) {
Expand All @@ -548,6 +551,32 @@ function crossfilter() {
return crossfilter;
}

// Removes all records that match the current filters.
function removeData() {
var newIndex = crossfilter_index(n, n),
removed = [];
for (var i = 0, j = 0; i < n; ++i) {
if (filters[i]) newIndex[i] = j++;
else removed.push(i);
}

// Remove all matching records from groups.
filterListeners.forEach(function(l) { l(0, [], removed); });

// Update indexes.
removeDataListeners.forEach(function(l) { l(newIndex); });

// Remove old filters and data by overwriting.
for (var i = 0, j = 0, k; i < n; ++i) {
if (k = filters[i]) {
if (i !== j) filters[j] = k, data[j] = data[i];
++j;
}
}
data.length = j;
while (n > j) filters[--n] = 0;
}

// Adds a new dimension with the specified value accessor function.
function dimension(value) {
var dimension = {
Expand Down Expand Up @@ -583,6 +612,8 @@ function crossfilter() {
dataListeners.unshift(preAdd);
dataListeners.push(postAdd);

removeDataListeners.push(removeData);

// Incorporate any existing data into this dimension, and make sure that the
// filter bitset is wide enough to handle the new dimension.
m |= one;
Expand Down Expand Up @@ -664,6 +695,22 @@ function crossfilter() {
newValues = newIndex = null;
}

function removeData(reIndex) {
for (var i = 0, j = 0, k; i < n; ++i) {
if (filters[k = index[i]] && i !== j) {
values[j] = values[i];
index[j] = reIndex[k];
++j;
}
}
values.length = j;
while (j < n) index[j++] = 0;

// Bisect again to recompute lo0 and hi0.
var bounds = refilter(values);
lo0 = bounds[0], hi0 = bounds[1];
}

// Updates the selected values based on the specified bounds [lo, hi].
// This implementation is used by all the public filter methods.
function filterIndexBounds(bounds) {
Expand Down Expand Up @@ -845,6 +892,7 @@ function crossfilter() {
// the parent dimension for when data is added, and compute new keys.
filterListeners.push(update);
indexListeners.push(add);
removeDataListeners.push(removeData);

// Incorporate any existing data into the grouping.
add(values, index, 0, n);
Expand Down Expand Up @@ -958,6 +1006,15 @@ function crossfilter() {
}
}

function removeData() {
for (var i = 0, j = 0; i < n; ++i) {
if (filters[i]) {
if (i !== j) groupIndex[j] = groupIndex[i];
++j;
}
}
}

// Reduces the specified selected or deselected records.
// This function is only used when the cardinality is greater than 1.
function updateMany(filterOne, added, removed) {
Expand Down Expand Up @@ -1103,6 +1160,8 @@ function crossfilter() {
if (i >= 0) filterListeners.splice(i, 1);
i = indexListeners.indexOf(add);
if (i >= 0) indexListeners.splice(i, 1);
i = removeDataListeners.indexOf(removeData);
if (i >= 0) removeDataListeners.splice(i, 1);
return group;
}

Expand All @@ -1127,6 +1186,8 @@ function crossfilter() {
if (i >= 0) dataListeners.splice(i, 1);
i = dataListeners.indexOf(postAdd);
if (i >= 0) dataListeners.splice(i, 1);
i = removeDataListeners.indexOf(removeData);
if (i >= 0) removeDataListeners.splice(i, 1);
for (i = 0; i < n; ++i) filters[i] &= zero;
m &= zero;
return dimension;
Expand Down
Loading

0 comments on commit e645b9e

Please sign in to comment.