UNPKG

2.86 kBJavaScriptView Raw
1import {Transform} from 'vega-dataflow';
2import {
3 TIME_UNITS, timeBin, timeFloor, timeInterval, timeUnits,
4 utcFloor, utcInterval
5} from 'vega-time';
6import {accessorFields, extent, inherits, peek} from 'vega-util';
7
8/**
9 * Discretize dates to specific time units.
10 * @constructor
11 * @param {object} params - The parameters for this operator.
12 * @param {function(object): *} params.field - The data field containing date/time values.
13 */
14export default function TimeUnit(params) {
15 Transform.call(this, null, params);
16}
17
18const OUTPUT = ['unit0', 'unit1'];
19
20TimeUnit.Definition = {
21 'type': 'TimeUnit',
22 'metadata': {'modifies': true},
23 'params': [
24 { 'name': 'field', 'type': 'field', 'required': true },
25 { 'name': 'interval', 'type': 'boolean', 'default': true },
26 { 'name': 'units', 'type': 'enum', 'values': TIME_UNITS, 'array': true },
27 { 'name': 'step', 'type': 'number', 'default': 1 },
28 { 'name': 'maxbins', 'type': 'number', 'default': 40 },
29 { 'name': 'extent', 'type': 'date', 'array': true},
30 { 'name': 'timezone', 'type': 'enum', 'default': 'local', 'values': ['local', 'utc'] },
31 { 'name': 'as', 'type': 'string', 'array': true, 'length': 2, 'default': OUTPUT }
32 ]
33};
34
35var prototype = inherits(TimeUnit, Transform);
36
37prototype.transform = function(_, pulse) {
38 var field = _.field,
39 band = _.interval !== false,
40 utc = _.timezone === 'utc',
41 floor = this._floor(_, pulse),
42 offset = (utc ? utcInterval : timeInterval)(floor.unit).offset,
43 as = _.as || OUTPUT,
44 u0 = as[0],
45 u1 = as[1],
46 min = floor.start || Infinity,
47 max = floor.stop || -Infinity,
48 step = floor.step,
49 flag = pulse.ADD;
50
51 if (_.modified() || pulse.modified(accessorFields(field))) {
52 pulse = pulse.reflow(true);
53 flag = pulse.SOURCE;
54 min = Infinity;
55 max = -Infinity;
56 }
57
58 pulse.visit(flag, function(t) {
59 var v = field(t), a, b;
60 if (v == null) {
61 t[u0] = null;
62 if (band) t[u1] = null;
63 } else {
64 t[u0] = a = b = floor(v);
65 if (band) t[u1] = b = offset(a, step);
66 if (a < min) min = a;
67 if (b > max) max = b;
68 }
69 });
70
71 floor.start = min;
72 floor.stop = max;
73
74 return pulse.modifies(band ? as : u0);
75};
76
77prototype._floor = function(_, pulse) {
78 const utc = _.timezone === 'utc';
79
80 // get parameters
81 let {units, step} = _.units
82 ? {units: _.units, step: _.step || 1}
83 : timeBin({
84 extent: _.extent || extent(pulse.materialize(pulse.SOURCE).source, _.field),
85 maxbins: _.maxbins
86 });
87
88 // check / standardize time units
89 units = timeUnits(units);
90
91 const prev = this.value || {},
92 floor = (utc ? utcFloor : timeFloor)(units, step);
93
94 floor.unit = peek(units);
95 floor.units = units;
96 floor.step = step;
97 floor.start = prev.start;
98 floor.stop = prev.stop;
99 return this.value = floor;
100};