1 | import {Transform} from 'vega-dataflow';
|
2 | import {
|
3 | TIME_UNITS, timeBin, timeFloor, timeInterval, timeUnits,
|
4 | utcFloor, utcInterval
|
5 | } from 'vega-time';
|
6 | import {accessorFields, extent, inherits, peek} from 'vega-util';
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | export default function TimeUnit(params) {
|
15 | Transform.call(this, null, params);
|
16 | }
|
17 |
|
18 | const OUTPUT = ['unit0', 'unit1'];
|
19 |
|
20 | TimeUnit.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 |
|
35 | var prototype = inherits(TimeUnit, Transform);
|
36 |
|
37 | prototype.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 |
|
77 | prototype._floor = function(_, pulse) {
|
78 | const utc = _.timezone === 'utc';
|
79 |
|
80 |
|
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 |
|
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 | };
|