-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
ResolveFilter.js
74 lines (63 loc) · 2.44 KB
/
ResolveFilter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import {Transform} from 'vega-dataflow';
import {inherits} from 'vega-util';
/**
* Selectively filters tuples by resolving against a filter bitmap.
* Useful for processing the output of a cross-filter transform.
* @constructor
* @param {object} params - The parameters for this operator.
* @param {object} params.ignore - A bit mask indicating which filters to ignore.
* @param {object} params.filter - The per-tuple filter bitmaps. Typically this
* parameter value is a reference to a {@link CrossFilter} transform.
*/
export default function ResolveFilter(params) {
Transform.call(this, null, params);
}
ResolveFilter.Definition = {
"type": "ResolveFilter",
"metadata": {},
"params": [
{ "name": "ignore", "type": "number", "required": true,
"description": "A bit mask indicating which filters to ignore." },
{ "name": "filter", "type": "object", "required": true,
"description": "Per-tuple filter bitmaps from a CrossFilter transform." }
]
};
var prototype = inherits(ResolveFilter, Transform);
prototype.transform = function(_, pulse) {
var ignore = ~(_.ignore || 0), // bit mask where zeros -> dims to ignore
bitmap = _.filter,
mask = bitmap.mask;
// exit early if no relevant filter changes
if ((mask & ignore) === 0) return pulse.StopPropagation;
var output = pulse.fork(pulse.ALL),
data = bitmap.data(),
curr = bitmap.curr(),
prev = bitmap.prev(),
pass = function(k) {
return !(curr[k] & ignore) ? data[k] : null;
};
// propagate all mod tuples that pass the filter
output.filter(output.MOD, pass);
// determine add & rem tuples via filter functions
// for efficiency, we do *not* populate new arrays,
// instead we add filter functions applied downstream
if (!(mask & (mask-1))) { // only one filter changed
output.filter(output.ADD, pass);
output.filter(output.REM, function(k) {
return (curr[k] & ignore) === mask ? data[k] : null;
});
} else { // multiple filters changed
output.filter(output.ADD, function(k) {
var c = curr[k] & ignore,
f = !c && (c ^ (prev[k] & ignore));
return f ? data[k] : null;
});
output.filter(output.REM, function(k) {
var c = curr[k] & ignore,
f = c && !(c ^ (c ^ (prev[k] & ignore)));
return f ? data[k] : null;
});
}
// add filter to source data in case of reflow...
return output.filter(output.SOURCE, function(t) { return pass(t._index); });
};