@uwrl/qc-utils 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import { ObservationRecord } from './utils/plotting/observationRecord';
2
2
  export { ObservationRecord, };
3
+ export * from './types';
package/dist/index.js CHANGED
@@ -1,107 +1,107 @@
1
- var f = /* @__PURE__ */ ((r) => (r.ADD_POINTS = "ADD_POINTS", r.CHANGE_VALUES = "CHANGE_VALUES", r.DELETE_POINTS = "DELETE_POINTS", r.DRIFT_CORRECTION = "DRIFT_CORRECTION", r.INTERPOLATE = "INTERPOLATE", r.SHIFT_DATETIMES = "SHIFT_DATETIMES", r.FILL_GAPS = "FILL_GAPS", r))(f || {}), _ = /* @__PURE__ */ ((r) => (r.FIND_GAPS = "FIND_GAPS", r.PERSISTENCE = "PERSISTENCE", r.RATE_OF_CHANGE = "RATE_OF_CHANGE", r.VALUE_THRESHOLD = "VALUE_THRESHOLD", r))(_ || {});
2
- const X = {
3
- "Less than": (r, t) => r < t,
4
- "Less than or equal to": (r, t) => r <= t,
5
- "Greater than": (r, t) => r > t,
6
- "Greater than or equal to": (r, t) => r >= t,
7
- Equal: (r, t) => r == t,
8
- "Start datetime": (r, t) => r == t,
9
- "End datetime": (r, t) => r == t
10
- };
11
- var E = /* @__PURE__ */ ((r) => (r.ADD = "ADD", r.SUB = "SUB", r.MULT = "MULT", r.DIV = "DIV", r.ASSIGN = "ASSIGN", r))(E || {});
1
+ var f = /* @__PURE__ */ ((s) => (s.ADD_POINTS = "ADD_POINTS", s.CHANGE_VALUES = "CHANGE_VALUES", s.DELETE_POINTS = "DELETE_POINTS", s.DRIFT_CORRECTION = "DRIFT_CORRECTION", s.INTERPOLATE = "INTERPOLATE", s.SHIFT_DATETIMES = "SHIFT_DATETIMES", s.FILL_GAPS = "FILL_GAPS", s))(f || {}), T = /* @__PURE__ */ ((s) => (s.FIND_GAPS = "FIND_GAPS", s.PERSISTENCE = "PERSISTENCE", s.RATE_OF_CHANGE = "RATE_OF_CHANGE", s.VALUE_THRESHOLD = "VALUE_THRESHOLD", s))(T || {}), X = /* @__PURE__ */ ((s) => (s.LT = "Less than", s.LTE = "Less than or equal to", s.GT = "Greater than", s.GTE = "Greater than or equal to", s.E = "Equal", s.START = "Start datetime", s.END = "End datetime", s))(X || {});
12
2
  const x = {
13
- "Less than": (r, t) => r < t,
14
- "Less than or equal to": (r, t) => r <= t,
15
- "Greater than": (r, t) => r > t,
16
- "Greater than or equal to": (r, t) => r >= t,
17
- Equal: (r, t) => r == t
3
+ "Less than": (s, t) => s < t,
4
+ "Less than or equal to": (s, t) => s <= t,
5
+ "Greater than": (s, t) => s > t,
6
+ "Greater than or equal to": (s, t) => s >= t,
7
+ Equal: (s, t) => s == t,
8
+ "Start datetime": (s, t) => s == t,
9
+ "End datetime": (s, t) => s == t
10
+ };
11
+ var y = /* @__PURE__ */ ((s) => (s.ADD = "ADD", s.SUB = "SUB", s.MULT = "MULT", s.DIV = "DIV", s.ASSIGN = "ASSIGN", s))(y || {}), G = /* @__PURE__ */ ((s) => (s.LT = "Less than", s.LTE = "Less than or equal to", s.GT = "Greater than", s.GTE = "Greater than or equal to", s.E = "Equal", s))(G || {});
12
+ const U = {
13
+ "Less than": (s, t) => s < t,
14
+ "Less than or equal to": (s, t) => s <= t,
15
+ "Greater than": (s, t) => s > t,
16
+ "Greater than or equal to": (s, t) => s >= t,
17
+ Equal: (s, t) => s == t
18
18
  }, I = `(function(){"use strict";self.onmessage=o=>{const{bufferX:s,bufferY:n,outputBufferX:u,outputBufferY:f,start:l,end:y,deleteSegment:a,startTarget:c}=o.data,A=new Float64Array(s),d=new Float32Array(n),g=new Float64Array(u),p=new Float32Array(f);let e=0,r=c;for(let t=l;t<=y;t++)e<a.length&&t===a[e]?e++:(g[r]=A[t],p[r]=d[t],r++);self.postMessage("Done")}})();
19
19
  `, b = typeof self < "u" && self.Blob && new Blob([I], { type: "text/javascript;charset=utf-8" });
20
- function U(r) {
20
+ function M(s) {
21
21
  let t;
22
22
  try {
23
23
  if (t = b && (self.URL || self.webkitURL).createObjectURL(b), !t) throw "";
24
- const s = new Worker(t, {
25
- name: r?.name
24
+ const a = new Worker(t, {
25
+ name: s?.name
26
26
  });
27
- return s.addEventListener("error", () => {
27
+ return a.addEventListener("error", () => {
28
28
  (self.URL || self.webkitURL).revokeObjectURL(t);
29
- }), s;
29
+ }), a;
30
30
  } catch {
31
31
  return new Worker(
32
32
  "data:text/javascript;charset=utf-8," + encodeURIComponent(I),
33
33
  {
34
- name: r?.name
34
+ name: s?.name
35
35
  }
36
36
  );
37
37
  } finally {
38
38
  t && (self.URL || self.webkitURL).revokeObjectURL(t);
39
39
  }
40
40
  }
41
- const F = `(function(){"use strict";self.onmessage=function(e){const{bufferX:f,bufferY:t,outputBufferX:u,outputBufferY:s}=e.data;self.postMessage("Done")}})();
42
- `, R = typeof self < "u" && self.Blob && new Blob([F], { type: "text/javascript;charset=utf-8" });
43
- function M(r) {
41
+ const N = `(function(){"use strict";self.onmessage=function(e){const{bufferX:f,bufferY:t,outputBufferX:u,outputBufferY:s}=e.data;self.postMessage("Done")}})();
42
+ `, R = typeof self < "u" && self.Blob && new Blob([N], { type: "text/javascript;charset=utf-8" });
43
+ function C(s) {
44
44
  let t;
45
45
  try {
46
46
  if (t = R && (self.URL || self.webkitURL).createObjectURL(R), !t) throw "";
47
- const s = new Worker(t, {
48
- name: r?.name
47
+ const a = new Worker(t, {
48
+ name: s?.name
49
49
  });
50
- return s.addEventListener("error", () => {
50
+ return a.addEventListener("error", () => {
51
51
  (self.URL || self.webkitURL).revokeObjectURL(t);
52
- }), s;
52
+ }), a;
53
53
  } catch {
54
54
  return new Worker(
55
- "data:text/javascript;charset=utf-8," + encodeURIComponent(F),
55
+ "data:text/javascript;charset=utf-8," + encodeURIComponent(N),
56
56
  {
57
- name: r?.name
57
+ name: s?.name
58
58
  }
59
59
  );
60
60
  } finally {
61
61
  t && (self.URL || self.webkitURL).revokeObjectURL(t);
62
62
  }
63
63
  }
64
- const C = (r, t) => {
65
- let s = 0, e = r.length;
66
- for (; s < e; ) {
67
- const n = s + e >> 1;
68
- r[n] < t ? s = n + 1 : e = n;
64
+ const k = (s, t) => {
65
+ let a = 0, e = s.length;
66
+ for (; a < e; ) {
67
+ const n = a + e >> 1;
68
+ s[n] < t ? a = n + 1 : e = n;
69
69
  }
70
- return s;
71
- }, B = (r, t) => {
72
- let s = 0, e = r.length;
73
- for (; s < e; ) {
74
- const n = s + e >> 1;
75
- r[n] > t ? e = n : s = n + 1;
70
+ return a;
71
+ }, B = (s, t) => {
72
+ let a = 0, e = s.length;
73
+ for (; a < e; ) {
74
+ const n = a + e >> 1;
75
+ s[n] > t ? e = n : a = n + 1;
76
76
  }
77
- return s - 1;
78
- }, w = async (r, t) => {
79
- const s = performance.now(), e = await r(), n = performance.now();
80
- console.log(` Done in ${(n - s).toFixed(2)} ms`);
81
- const a = +(n - s);
82
- return { response: e, duration: a };
83
- }, N = 1, Y = N * 60, S = Y * 60, D = S * 24, G = D * 7, O = S * 30, k = D * 365, A = {
84
- s: N,
85
- m: Y,
77
+ return a - 1;
78
+ }, p = async (s, t) => {
79
+ const a = performance.now(), e = await s(), n = performance.now();
80
+ console.log(` Done in ${(n - a).toFixed(2)} ms`);
81
+ const r = +(n - a);
82
+ return { response: e, duration: r };
83
+ }, Y = 1, F = Y * 60, S = F * 60, D = S * 24, v = D * 7, H = S * 30, O = D * 365, A = {
84
+ s: Y,
85
+ m: F,
86
86
  h: S,
87
87
  D,
88
- W: G,
89
- M: O,
90
- Y: k
91
- }, H = (r, t, s) => {
92
- if (s === "M") {
93
- const e = new Date(r);
88
+ W: v,
89
+ M: H,
90
+ Y: O
91
+ }, V = (s, t, a) => {
92
+ if (a === "M") {
93
+ const e = new Date(s);
94
94
  return e.setMonth(e.getMonth() + t), e.getTime();
95
- } else if (s === "Y") {
96
- const e = new Date(r);
95
+ } else if (a === "Y") {
96
+ const e = new Date(s);
97
97
  return e.setFullYear(e.getFullYear() + t), e.getTime();
98
98
  } else
99
- return r + t * A[s] * 1e3;
100
- }, L = 20 * 1e3, v = ["date", "value", "qualifier"];
101
- class V {
99
+ return s + t * A[a] * 1e3;
100
+ }, L = 20 * 1e3, j = ["date", "value", "qualifier"];
101
+ class q {
102
102
  /** The generated dataset to be used for plotting */
103
103
  dataset = {
104
- dimensions: v,
104
+ dimensions: j,
105
105
  source: {
106
106
  x: new Float64Array(
107
107
  new SharedArrayBuffer(
@@ -134,10 +134,10 @@ class V {
134
134
  if (!t)
135
135
  return;
136
136
  this.isLoading = !0;
137
- const s = await w(() => {
137
+ const a = await p(() => {
138
138
  this._growBuffer(t.datetimes.length), this._resizeTo(t.datetimes.length), this.dataX.set(t.datetimes), this.dataY.set(t.dataValues);
139
139
  });
140
- this.loadingTime = s.duration, this.history.length = 0, this.isLoading = !1;
140
+ this.loadingTime = a.duration, this.history.length = 0, this.isLoading = !1;
141
141
  }
142
142
  get dataX() {
143
143
  return this.dataset.source.x;
@@ -162,9 +162,9 @@ class V {
162
162
  * @param newLength The total number of elements that the view will contain
163
163
  */
164
164
  _growBuffer(t) {
165
- const s = t * Float64Array.BYTES_PER_ELEMENT;
165
+ const a = t * Float64Array.BYTES_PER_ELEMENT;
166
166
  let e = this.dataX.buffer.byteLength;
167
- for (; s > e; )
167
+ for (; a > e; )
168
168
  e += L * Float64Array.BYTES_PER_ELEMENT;
169
169
  if (e * Float64Array.BYTES_PER_ELEMENT > this.dataX.buffer.maxByteLength) {
170
170
  const n = new SharedArrayBuffer(
@@ -172,12 +172,12 @@ class V {
172
172
  {
173
173
  maxByteLength: e * Float64Array.BYTES_PER_ELEMENT
174
174
  }
175
- ), a = new SharedArrayBuffer(
175
+ ), r = new SharedArrayBuffer(
176
176
  this.dataY.buffer.byteLength,
177
177
  {
178
178
  maxByteLength: e * Float32Array.BYTES_PER_ELEMENT
179
179
  }
180
- ), o = new Float64Array(n), i = new Float32Array(a);
180
+ ), o = new Float64Array(n), i = new Float32Array(r);
181
181
  o.set(this.dataX), i.set(this.dataY), this.dataset.source.x = o, this.dataset.source.y = i;
182
182
  }
183
183
  this.dataX.buffer.byteLength < t * Float64Array.BYTES_PER_ELEMENT && (this.dataX.buffer.grow(t * Float64Array.BYTES_PER_ELEMENT), this.dataY.buffer.grow(t * Float32Array.BYTES_PER_ELEMENT));
@@ -193,16 +193,16 @@ class V {
193
193
  * @returns
194
194
  */
195
195
  async reloadHistory(t) {
196
- const s = this.history.slice(0, t + 1);
197
- await this.reload(), await this.dispatch(s.map((e) => [e.method, ...e.args || []]));
196
+ const a = this.history.slice(0, t + 1);
197
+ await this.reload(), await this.dispatch(a.map((e) => [e.method, ...e.args || []]));
198
198
  }
199
199
  /**
200
200
  * Remove a history item
201
201
  * @param index
202
202
  */
203
203
  async removeHistoryItem(t) {
204
- const s = [...this.history];
205
- s.splice(t, 1), await this.reload(), await this.dispatch(s.map((e) => [e.method, ...e.args || []]));
204
+ const a = [...this.history];
205
+ a.splice(t, 1), await this.reload(), await this.dispatch(a.map((e) => [e.method, ...e.args || []]));
206
206
  }
207
207
  get beginTime() {
208
208
  return this.dataset.source.x.length ? new Date(this.dataset.source.x[0]) : null;
@@ -211,7 +211,7 @@ class V {
211
211
  return this.dataset.source.x.length ? new Date(this.dataset.source.x[this.dataset.source.x.length - 1]) : null;
212
212
  }
213
213
  /** Dispatch an operation and log its signature in hisotry */
214
- async dispatch(t, ...s) {
214
+ async dispatch(t, ...a) {
215
215
  const e = {
216
216
  [f.ADD_POINTS]: this._addDataPoints,
217
217
  [f.CHANGE_VALUES]: this._changeValues,
@@ -229,7 +229,7 @@ class V {
229
229
  [f.SHIFT_DATETIMES]: "mdi-calendar",
230
230
  [f.FILL_GAPS]: "mdi-keyboard-space"
231
231
  };
232
- let a = [];
232
+ let r = [];
233
233
  try {
234
234
  if (Array.isArray(t)) {
235
235
  for (let o = 0; o < t.length; o++) {
@@ -244,53 +244,53 @@ class V {
244
244
  for (let o = this.history.length - t.length; o < this.history.length; o++) {
245
245
  const i = this.history[o];
246
246
  i.isLoading = !0;
247
- const h = await w(async () => await e[i.method].apply(
247
+ const h = await p(async () => await e[i.method].apply(
248
248
  this,
249
249
  i.args
250
250
  ));
251
- i.duration = h.duration, i.isLoading = !1, a.push(h.response);
251
+ i.duration = h.duration, i.isLoading = !1, r.push(h.response);
252
252
  }
253
253
  } else {
254
254
  const o = {
255
255
  method: t,
256
- args: s,
256
+ args: a,
257
257
  icon: n[t],
258
258
  isLoading: !0
259
259
  };
260
260
  this.history.push(o);
261
- const i = await w(async () => await e[t].apply(this, s));
262
- a = i.response, o.duration = i.duration, o.isLoading = !1;
261
+ const i = await p(async () => await e[t].apply(this, a));
262
+ r = i.response, o.duration = i.duration, o.isLoading = !1;
263
263
  }
264
264
  } catch (o) {
265
265
  console.log(
266
266
  `Failed to execute operation: ${t} with arguments: `,
267
- s
267
+ a
268
268
  ), console.log(o);
269
269
  }
270
- return a;
270
+ return r;
271
271
  }
272
272
  /** Filter operations do not transform the data and are not logged in history */
273
- async dispatchFilter(t, ...s) {
273
+ async dispatchFilter(t, ...a) {
274
274
  const e = {
275
- [_.FIND_GAPS]: this._findGaps,
276
- [_.VALUE_THRESHOLD]: this._valueThreshold,
277
- [_.PERSISTENCE]: this._persistence,
278
- [_.RATE_OF_CHANGE]: this._rateOfChange
275
+ [T.FIND_GAPS]: this._findGaps,
276
+ [T.VALUE_THRESHOLD]: this._valueThreshold,
277
+ [T.PERSISTENCE]: this._persistence,
278
+ [T.RATE_OF_CHANGE]: this._rateOfChange
279
279
  };
280
280
  let n = [];
281
281
  try {
282
282
  if (Array.isArray(t))
283
- for (let a = 0; a < t.length; a++) {
284
- const o = t[a][0], i = t[a].slice(1, t[a].length), h = await e[o].apply(this, i);
283
+ for (let r = 0; r < t.length; r++) {
284
+ const o = t[r][0], i = t[r].slice(1, t[r].length), h = await e[o].apply(this, i);
285
285
  n.push(h);
286
286
  }
287
287
  else
288
- n = await e[t].apply(this, s);
289
- } catch (a) {
288
+ n = await e[t].apply(this, a);
289
+ } catch (r) {
290
290
  console.log(
291
291
  `Failed to execute filter operation: ${t} with arguments: `,
292
- s
293
- ), console.log(a);
292
+ a
293
+ ), console.log(r);
294
294
  }
295
295
  return n;
296
296
  }
@@ -300,35 +300,35 @@ class V {
300
300
  * @param value The value to use in the operation
301
301
  * @returns The modified DataFrame
302
302
  */
303
- _changeValues(t, s, e) {
304
- const n = (a) => {
305
- switch (s) {
306
- case E.ADD:
307
- return a + e;
308
- case E.ASSIGN:
303
+ _changeValues(t, a, e) {
304
+ const n = (r) => {
305
+ switch (a) {
306
+ case y.ADD:
307
+ return r + e;
308
+ case y.ASSIGN:
309
309
  return e;
310
- case E.DIV:
311
- return a / e;
312
- case E.MULT:
313
- return a * e;
314
- case E.SUB:
315
- return a - e;
310
+ case y.DIV:
311
+ return r / e;
312
+ case y.MULT:
313
+ return r * e;
314
+ case y.SUB:
315
+ return r - e;
316
316
  default:
317
- return a;
317
+ return r;
318
318
  }
319
319
  };
320
- t.forEach((a) => {
321
- this.dataset.source.y[a] = n(this.dataset.source.y[a]);
320
+ t.forEach((r) => {
321
+ this.dataset.source.y[r] = n(this.dataset.source.y[r]);
322
322
  });
323
323
  }
324
324
  _interpolate(t) {
325
325
  this._getConsecutiveGroups(t).forEach((e) => {
326
- const n = e[0], a = e[e.length - 1];
327
- let o = Math.max(0, n - 1), i = Math.min(this.dataset.source.y.length - 1, a + 1);
326
+ const n = e[0], r = e[e.length - 1];
327
+ let o = Math.max(0, n - 1), i = Math.min(this.dataset.source.y.length - 1, r + 1);
328
328
  const h = this.dataset.source.x, l = this.dataset.source.y;
329
- for (let u = 0; u < e.length; u++)
330
- this.dataset.source.y[e[u]] = this._interpolateLinear(
331
- h[e[u]],
329
+ for (let c = 0; c < e.length; c++)
330
+ this.dataset.source.y[e[c]] = this._interpolateLinear(
331
+ h[e[c]],
332
332
  h[o],
333
333
  l[o],
334
334
  h[i],
@@ -337,8 +337,8 @@ class V {
337
337
  });
338
338
  }
339
339
  /** Interpolate existing values in the data source */
340
- _interpolateLinear(t, s, e, n, a) {
341
- return e + (t - s) * (a - e) / (n - s);
340
+ _interpolateLinear(t, a, e, n, r) {
341
+ return e + (t - a) * (r - e) / (n - a);
342
342
  }
343
343
  /**
344
344
  * Shifts the selected indexes by specified amount of units. Elements are reinserted according to their datetime.
@@ -347,34 +347,34 @@ class V {
347
347
  * @param unit {@link TimeUnit}
348
348
  * @returns
349
349
  */
350
- async _shift(t, s, e) {
351
- const n = t.map((a) => [
352
- H(this.dataX[a], s, e),
353
- this.dataY[a]
350
+ async _shift(t, a, e) {
351
+ const n = t.map((r) => [
352
+ V(this.dataX[r], a, e),
353
+ this.dataY[r]
354
354
  ]);
355
355
  await this._deleteDataPoints(t), await this._addDataPoints(n);
356
356
  }
357
- async _fillGapsV2(t, s, e, n) {
358
- const a = navigator.hardwareConcurrency || 1, o = [], i = [], h = this.dataX.length, l = new SharedArrayBuffer(this.dataX.buffer.byteLength, {
357
+ async _fillGapsV2(t, a, e, n) {
358
+ const r = navigator.hardwareConcurrency || 1, o = [], i = [], h = this.dataX.length, l = new SharedArrayBuffer(this.dataX.buffer.byteLength, {
359
359
  maxByteLength: this.dataX.buffer.maxByteLength
360
- }), u = new SharedArrayBuffer(this.dataY.buffer.byteLength, {
360
+ }), c = new SharedArrayBuffer(this.dataY.buffer.byteLength, {
361
361
  maxByteLength: this.dataY.buffer.maxByteLength
362
362
  });
363
- for (let c = 0; c < a; c++)
363
+ for (let u = 0; u < r; u++)
364
364
  i.push(
365
365
  new Promise((d) => {
366
- const y = new M();
367
- o.push(y), y.postMessage({
366
+ const E = new C();
367
+ o.push(E), E.postMessage({
368
368
  bufferX: this.dataX.buffer,
369
369
  bufferY: this.dataY.buffer,
370
370
  outputBufferX: l,
371
- outputBufferY: u
372
- }), y.onmessage = (g) => {
371
+ outputBufferY: c
372
+ }), E.onmessage = (g) => {
373
373
  d(g.data);
374
374
  };
375
375
  })
376
376
  );
377
- await Promise.all(i), o.forEach((c) => c.terminate()), this.dataset.source.x = new Float64Array(l), this.dataset.source.y = new Float32Array(u), this._resizeTo(h);
377
+ await Promise.all(i), o.forEach((u) => u.terminate()), this.dataset.source.x = new Float64Array(l), this.dataset.source.y = new Float32Array(c), this._resizeTo(h);
378
378
  }
379
379
  /**
380
380
  * Find gaps and fill them with placeholder value
@@ -384,22 +384,22 @@ class V {
384
384
  * @returns
385
385
  */
386
386
  // TODO: this needs to be improved using web workers
387
- _fillGaps(t, s, e, n) {
388
- const a = this._findGaps(t[0], t[1], n);
389
- for (let o = a.length - 1; o >= 0; o--) {
390
- const i = a[o], h = this.dataX[i[0]], l = this.dataX[i[1]], u = [], c = s[0] * A[s[1]] * 1e3;
391
- let d = h + c;
387
+ _fillGaps(t, a, e, n) {
388
+ const r = this._findGaps(t[0], t[1], n);
389
+ for (let o = r.length - 1; o >= 0; o--) {
390
+ const i = r[o], h = this.dataX[i[0]], l = this.dataX[i[1]], c = [], u = a[0] * A[a[1]] * 1e3;
391
+ let d = h + u;
392
392
  for (; d < l; ) {
393
- const y = e ? this._interpolateLinear(
393
+ const E = e ? this._interpolateLinear(
394
394
  d,
395
395
  this.dataX[i[0]],
396
396
  this.dataY[i[0]],
397
397
  this.dataX[i[1]],
398
398
  this.dataY[i[1]]
399
399
  ) : -9999;
400
- u.push([d, y]), d += c;
400
+ c.push([d, E]), d += u;
401
401
  }
402
- this._addDataPoints(u);
402
+ this._addDataPoints(c);
403
403
  }
404
404
  }
405
405
  /**
@@ -412,40 +412,40 @@ class V {
412
412
  */
413
413
  // TODO: implement similar multithread solutions for other operations
414
414
  async _deleteDataPoints(t) {
415
- const s = navigator.hardwareConcurrency || 1, e = Math.ceil(this.dataX.length / s), n = [], a = [];
416
- for (let c = 0; c < s; c++) {
417
- const d = c * e, y = Math.min((c + 1) * e - 1, this.dataX.length - 1), g = C(t, d), p = B(t, y), m = t.slice(g, p + 1);
418
- a.push({ start: d, end: y, deleteSegment: m });
415
+ const a = navigator.hardwareConcurrency || 1, e = Math.ceil(this.dataX.length / a), n = [], r = [];
416
+ for (let u = 0; u < a; u++) {
417
+ const d = u * e, E = Math.min((u + 1) * e - 1, this.dataX.length - 1), g = k(t, d), _ = B(t, E), m = t.slice(g, _ + 1);
418
+ r.push({ start: d, end: E, deleteSegment: m });
419
419
  }
420
- const o = new Array(s).fill(0);
421
- for (let c = 1; c < s; c++)
422
- o[c] = o[c - 1] + a[c - 1].deleteSegment.length;
420
+ const o = new Array(a).fill(0);
421
+ for (let u = 1; u < a; u++)
422
+ o[u] = o[u - 1] + r[u - 1].deleteSegment.length;
423
423
  const i = [], h = this.dataX.length - t.length, l = new SharedArrayBuffer(this.dataX.buffer.byteLength, {
424
424
  maxByteLength: this.dataX.buffer.maxByteLength
425
- }), u = new SharedArrayBuffer(this.dataY.buffer.byteLength, {
425
+ }), c = new SharedArrayBuffer(this.dataY.buffer.byteLength, {
426
426
  maxByteLength: this.dataY.buffer.maxByteLength
427
427
  });
428
- for (let c = 0; c < s; c++) {
429
- const { start: d, end: y, deleteSegment: g } = a[c], p = d - o[c];
428
+ for (let u = 0; u < a; u++) {
429
+ const { start: d, end: E, deleteSegment: g } = r[u], _ = d - o[u];
430
430
  i.push(
431
431
  new Promise((m) => {
432
- const T = new U();
433
- n.push(T), T.postMessage({
432
+ const w = new M();
433
+ n.push(w), w.postMessage({
434
434
  bufferX: this.dataX.buffer,
435
435
  bufferY: this.dataY.buffer,
436
436
  outputBufferX: l,
437
- outputBufferY: u,
437
+ outputBufferY: c,
438
438
  start: d,
439
- end: y,
439
+ end: E,
440
440
  deleteSegment: g,
441
- startTarget: p
442
- }), T.onmessage = (P) => {
441
+ startTarget: _
442
+ }), w.onmessage = (P) => {
443
443
  m(P.data);
444
444
  };
445
445
  })
446
446
  );
447
447
  }
448
- await Promise.all(i), n.forEach((c) => c.terminate()), this.dataset.source.x = new Float64Array(l), this.dataset.source.y = new Float32Array(u), this._resizeTo(h);
448
+ await Promise.all(i), n.forEach((u) => u.terminate()), this.dataset.source.x = new Float64Array(l), this.dataset.source.y = new Float32Array(c), this._resizeTo(h);
449
449
  }
450
450
  /**
451
451
  *
@@ -453,10 +453,10 @@ class V {
453
453
  * @param end The end index
454
454
  * @param value The drift amount
455
455
  */
456
- _driftCorrection(t, s, e) {
457
- const n = this.dataset.source.x, a = this.dataset.source.y, o = n[t], h = n[s] - o;
458
- for (let l = t; l < s; l++)
459
- this.dataset.source.y[l] = a[l] + e * ((n[l] - o) / h);
456
+ _driftCorrection(t, a, e) {
457
+ const n = this.dataset.source.x, r = this.dataset.source.y, o = n[t], h = n[a] - o;
458
+ for (let l = t; l < a; l++)
459
+ this.dataset.source.y[l] = r[l] + e * ((n[l] - o) / h);
460
460
  }
461
461
  /** Traverses the index array and returns groups of consecutive values.
462
462
  * i.e.: `[0, 1, 3, 4, 6] => [[0, 1], [3, 4], [6]]`
@@ -464,27 +464,27 @@ class V {
464
464
  * @param index: the index array (sorted)
465
465
  */
466
466
  _getConsecutiveGroups(t) {
467
- const s = [[]];
467
+ const a = [[]];
468
468
  return t.reduce((e, n) => {
469
- const a = e[e.length - 1];
470
- return !a.length || n == a[a.length - 1] + 1 ? a.push(n) : e.push([n]), e;
471
- }, s), s;
469
+ const r = e[e.length - 1];
470
+ return !r.length || n == r[r.length - 1] + 1 ? r.push(n) : e.push([n]), e;
471
+ }, a), a;
472
472
  }
473
473
  /**
474
474
  * Adds data points. Their insert index is determined using `findFirstGreaterOrEqual` in the x-axis.
475
475
  * @param dataPoints
476
476
  */
477
477
  async _addDataPoints(t) {
478
- const s = this.dataX.length + t.length;
479
- this._growBuffer(s), t.sort((a, o) => a[0] - o[0]);
480
- const e = t.map((a) => B(this.dataX, a[0]) + 1);
481
- this._resizeTo(s), e.push(this.dataX.length);
478
+ const a = this.dataX.length + t.length;
479
+ this._growBuffer(a), t.sort((r, o) => r[0] - o[0]);
480
+ const e = t.map((r) => B(this.dataX, r[0]) + 1);
481
+ this._resizeTo(a), e.push(this.dataX.length);
482
482
  let n = t.length;
483
- for (let a = e.length - 1; a > 0; a--) {
484
- const o = e[a - 1], i = e[a] - 1;
483
+ for (let r = e.length - 1; r > 0; r--) {
484
+ const o = e[r - 1], i = e[r] - 1;
485
485
  for (let h = i; h >= o; h--)
486
486
  this.dataX[h + n] = this.dataX[h], this.dataY[h + n] = this.dataY[h];
487
- n--, this.dataX[o + n] = t[a - 1][0], this.dataY[o + n] = t[a - 1][1];
487
+ n--, this.dataX[o + n] = t[r - 1][0], this.dataY[o + n] = t[r - 1][1];
488
488
  }
489
489
  }
490
490
  // =======================
@@ -496,13 +496,13 @@ class V {
496
496
  * @returns
497
497
  */
498
498
  _valueThreshold(t) {
499
- const s = [];
499
+ const a = [];
500
500
  return this.dataset.source.y.forEach((e, n) => {
501
- Object.keys(t).some((a) => X[a]?.(
501
+ Object.keys(t).some((r) => x[r]?.(
502
502
  e,
503
- t[a]
504
- )) && s.push(n);
505
- }), s;
503
+ t[r]
504
+ )) && a.push(n);
505
+ }), a;
506
506
  }
507
507
  /**
508
508
  *
@@ -510,14 +510,14 @@ class V {
510
510
  * @param value
511
511
  * @returns
512
512
  */
513
- _rateOfChange(t, s) {
513
+ _rateOfChange(t, a) {
514
514
  const e = [], n = this.dataset.source.y;
515
- for (let a = 1; a < n.length; a++) {
516
- const o = n[a - 1], h = (n[a] - o) / Math.abs(o);
517
- x[t]?.(
515
+ for (let r = 1; r < n.length; r++) {
516
+ const o = n[r - 1], h = (n[r] - o) / Math.abs(o);
517
+ U[t]?.(
518
518
  h,
519
- s
520
- ) && e.push(a);
519
+ a
520
+ ) && e.push(r);
521
521
  }
522
522
  return e;
523
523
  }
@@ -528,14 +528,14 @@ class V {
528
528
  * @param range If specified, the gaps will be found only within the range
529
529
  * @returns
530
530
  */
531
- _findGaps(t, s, e) {
532
- const n = [], a = this.dataset.source.x;
533
- let o = 0, i = a.length;
531
+ _findGaps(t, a, e) {
532
+ const n = [], r = this.dataset.source.x;
533
+ let o = 0, i = r.length;
534
534
  e?.[0] && e?.[1] && (o = e[0], i = e[1]);
535
- let h = a[o];
535
+ let h = r[o];
536
536
  for (let l = o + 1; l <= i; l++) {
537
- const u = a[l];
538
- u - h > t * A[s] * 1e3 && n.push([l - 1, l]), h = u;
537
+ const c = r[l];
538
+ c - h > t * A[a] * 1e3 && n.push([l - 1, l]), h = c;
539
539
  }
540
540
  return n;
541
541
  }
@@ -545,15 +545,22 @@ class V {
545
545
  * @param range If specified, the points will be found only within the range
546
546
  * @returns
547
547
  */
548
- _persistence(t, s) {
549
- let e = [], n = this.dataset.source.y, a = 0, o = n.length;
550
- s?.[0] && s?.[1] && (a = s[0], o = s[1]);
551
- let i = n[a], h = [];
552
- for (let l = a + 1; l < o; l++)
548
+ _persistence(t, a) {
549
+ let e = [], n = this.dataset.source.y, r = 0, o = n.length;
550
+ a?.[0] && a?.[1] && (r = a[0], o = a[1]);
551
+ let i = n[r], h = [];
552
+ for (let l = r + 1; l < o; l++)
553
553
  n[l] != i || l === o ? (h.length >= t && (e = [...e, ...h]), h = []) : h.push(l);
554
554
  return e;
555
555
  }
556
556
  }
557
557
  export {
558
- V as ObservationRecord
558
+ f as EnumEditOperations,
559
+ T as EnumFilterOperations,
560
+ X as FilterOperation,
561
+ x as FilterOperationFn,
562
+ q as ObservationRecord,
563
+ y as Operator,
564
+ U as RateOfChangeComparator,
565
+ G as RateOfChangeOperation
559
566
  };
@@ -1,3 +1,3 @@
1
- (function(E,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(E=typeof globalThis<"u"?globalThis:E||self,c(E["@uwrl/qc-utils"]={}))})(this,function(E){"use strict";var c=(r=>(r.ADD_POINTS="ADD_POINTS",r.CHANGE_VALUES="CHANGE_VALUES",r.DELETE_POINTS="DELETE_POINTS",r.DRIFT_CORRECTION="DRIFT_CORRECTION",r.INTERPOLATE="INTERPOLATE",r.SHIFT_DATETIMES="SHIFT_DATETIMES",r.FILL_GAPS="FILL_GAPS",r))(c||{}),p=(r=>(r.FIND_GAPS="FIND_GAPS",r.PERSISTENCE="PERSISTENCE",r.RATE_OF_CHANGE="RATE_OF_CHANGE",r.VALUE_THRESHOLD="VALUE_THRESHOLD",r))(p||{});const x={"Less than":(r,t)=>r<t,"Less than or equal to":(r,t)=>r<=t,"Greater than":(r,t)=>r>t,"Greater than or equal to":(r,t)=>r>=t,Equal:(r,t)=>r==t,"Start datetime":(r,t)=>r==t,"End datetime":(r,t)=>r==t};var g=(r=>(r.ADD="ADD",r.SUB="SUB",r.MULT="MULT",r.DIV="DIV",r.ASSIGN="ASSIGN",r))(g||{});const X={"Less than":(r,t)=>r<t,"Less than or equal to":(r,t)=>r<=t,"Greater than":(r,t)=>r>t,"Greater than or equal to":(r,t)=>r>=t,Equal:(r,t)=>r==t},R=`(function(){"use strict";self.onmessage=o=>{const{bufferX:s,bufferY:n,outputBufferX:u,outputBufferY:f,start:l,end:y,deleteSegment:a,startTarget:c}=o.data,A=new Float64Array(s),d=new Float32Array(n),g=new Float64Array(u),p=new Float32Array(f);let e=0,r=c;for(let t=l;t<=y;t++)e<a.length&&t===a[e]?e++:(g[r]=A[t],p[r]=d[t],r++);self.postMessage("Done")}})();
2
- `,B=typeof self<"u"&&self.Blob&&new Blob([R],{type:"text/javascript;charset=utf-8"});function U(r){let t;try{if(t=B&&(self.URL||self.webkitURL).createObjectURL(B),!t)throw"";const s=new Worker(t,{name:r?.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),s}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(R),{name:r?.name})}finally{t&&(self.URL||self.webkitURL).revokeObjectURL(t)}}const I=`(function(){"use strict";self.onmessage=function(e){const{bufferX:f,bufferY:t,outputBufferX:u,outputBufferY:s}=e.data;self.postMessage("Done")}})();
3
- `,F=typeof self<"u"&&self.Blob&&new Blob([I],{type:"text/javascript;charset=utf-8"});function M(r){let t;try{if(t=F&&(self.URL||self.webkitURL).createObjectURL(F),!t)throw"";const s=new Worker(t,{name:r?.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),s}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(I),{name:r?.name})}finally{t&&(self.URL||self.webkitURL).revokeObjectURL(t)}}const C=(r,t)=>{let s=0,e=r.length;for(;s<e;){const n=s+e>>1;r[n]<t?s=n+1:e=n}return s},N=(r,t)=>{let s=0,e=r.length;for(;s<e;){const n=s+e>>1;r[n]>t?e=n:s=n+1}return s-1},_=async(r,t)=>{const s=performance.now(),e=await r(),n=performance.now();console.log(` Done in ${(n-s).toFixed(2)} ms`);const a=+(n-s);return{response:e,duration:a}},Y=1,P=Y*60,T=P*60,w=T*24,O=w*7,G=T*30,k=w*365,A={s:Y,m:P,h:T,D:w,W:O,M:G,Y:k},v=(r,t,s)=>{if(s==="M"){const e=new Date(r);return e.setMonth(e.getMonth()+t),e.getTime()}else if(s==="Y"){const e=new Date(r);return e.setFullYear(e.getFullYear()+t),e.getTime()}else return r+t*A[s]*1e3},L=20*1e3,H=["date","value","qualifier"];class j{dataset={dimensions:H,source:{x:new Float64Array(new SharedArrayBuffer(L*Float64Array.BYTES_PER_ELEMENT,{maxByteLength:L*Float64Array.BYTES_PER_ELEMENT})),y:new Float32Array(new SharedArrayBuffer(L*Float32Array.BYTES_PER_ELEMENT,{maxByteLength:L*Float32Array.BYTES_PER_ELEMENT}))}};history=[];loadingTime=null;isLoading=!0;rawData;constructor(t){this.history=[],this.rawData=t,this.loadData(this.rawData)}async loadData(t){if(!t)return;this.isLoading=!0;const s=await _(()=>{this._growBuffer(t.datetimes.length),this._resizeTo(t.datetimes.length),this.dataX.set(t.datetimes),this.dataY.set(t.dataValues)});this.loadingTime=s.duration,this.history.length=0,this.isLoading=!1}get dataX(){return this.dataset.source.x}get dataY(){return this.dataset.source.y}_resizeTo(t){this.dataset.source.x=new Float64Array(this.dataset.source.x.buffer).subarray(0,t),this.dataset.source.y=new Float32Array(this.dataset.source.y.buffer).subarray(0,t)}_growBuffer(t){const s=t*Float64Array.BYTES_PER_ELEMENT;let e=this.dataX.buffer.byteLength;for(;s>e;)e+=L*Float64Array.BYTES_PER_ELEMENT;if(e*Float64Array.BYTES_PER_ELEMENT>this.dataX.buffer.maxByteLength){const n=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:e*Float64Array.BYTES_PER_ELEMENT}),a=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:e*Float32Array.BYTES_PER_ELEMENT}),o=new Float64Array(n),i=new Float32Array(a);o.set(this.dataX),i.set(this.dataY),this.dataset.source.x=o,this.dataset.source.y=i}this.dataX.buffer.byteLength<t*Float64Array.BYTES_PER_ELEMENT&&(this.dataX.buffer.grow(t*Float64Array.BYTES_PER_ELEMENT),this.dataY.buffer.grow(t*Float32Array.BYTES_PER_ELEMENT))}async reload(){this.loadingTime=null,this.isLoading=!0,this.history.length=0,await this.loadData(this.rawData)}async reloadHistory(t){const s=this.history.slice(0,t+1);await this.reload(),await this.dispatch(s.map(e=>[e.method,...e.args||[]]))}async removeHistoryItem(t){const s=[...this.history];s.splice(t,1),await this.reload(),await this.dispatch(s.map(e=>[e.method,...e.args||[]]))}get beginTime(){return this.dataset.source.x.length?new Date(this.dataset.source.x[0]):null}get endTime(){return this.dataset.source.x.length?new Date(this.dataset.source.x[this.dataset.source.x.length-1]):null}async dispatch(t,...s){const e={[c.ADD_POINTS]:this._addDataPoints,[c.CHANGE_VALUES]:this._changeValues,[c.DELETE_POINTS]:this._deleteDataPoints,[c.DRIFT_CORRECTION]:this._driftCorrection,[c.INTERPOLATE]:this._interpolate,[c.SHIFT_DATETIMES]:this._shift,[c.FILL_GAPS]:this._fillGaps},n={[c.ADD_POINTS]:"mdi-plus",[c.CHANGE_VALUES]:"mdi-pencil",[c.DELETE_POINTS]:"mdi-trash-can",[c.DRIFT_CORRECTION]:"mdi-chart-sankey",[c.INTERPOLATE]:"mdi-transit-connection-horizontal",[c.SHIFT_DATETIMES]:"mdi-calendar",[c.FILL_GAPS]:"mdi-keyboard-space"};let a=[];try{if(Array.isArray(t)){for(let o=0;o<t.length;o++){const i=t[o][0],h=t[o].slice(1,t[o].length),l={method:i,args:h,icon:n[i],isLoading:!1};this.history.push(l)}for(let o=this.history.length-t.length;o<this.history.length;o++){const i=this.history[o];i.isLoading=!0;const h=await _(async()=>await e[i.method].apply(this,i.args));i.duration=h.duration,i.isLoading=!1,a.push(h.response)}}else{const o={method:t,args:s,icon:n[t],isLoading:!0};this.history.push(o);const i=await _(async()=>await e[t].apply(this,s));a=i.response,o.duration=i.duration,o.isLoading=!1}}catch(o){console.log(`Failed to execute operation: ${t} with arguments: `,s),console.log(o)}return a}async dispatchFilter(t,...s){const e={[p.FIND_GAPS]:this._findGaps,[p.VALUE_THRESHOLD]:this._valueThreshold,[p.PERSISTENCE]:this._persistence,[p.RATE_OF_CHANGE]:this._rateOfChange};let n=[];try{if(Array.isArray(t))for(let a=0;a<t.length;a++){const o=t[a][0],i=t[a].slice(1,t[a].length),h=await e[o].apply(this,i);n.push(h)}else n=await e[t].apply(this,s)}catch(a){console.log(`Failed to execute filter operation: ${t} with arguments: `,s),console.log(a)}return n}_changeValues(t,s,e){const n=a=>{switch(s){case g.ADD:return a+e;case g.ASSIGN:return e;case g.DIV:return a/e;case g.MULT:return a*e;case g.SUB:return a-e;default:return a}};t.forEach(a=>{this.dataset.source.y[a]=n(this.dataset.source.y[a])})}_interpolate(t){this._getConsecutiveGroups(t).forEach(e=>{const n=e[0],a=e[e.length-1];let o=Math.max(0,n-1),i=Math.min(this.dataset.source.y.length-1,a+1);const h=this.dataset.source.x,l=this.dataset.source.y;for(let f=0;f<e.length;f++)this.dataset.source.y[e[f]]=this._interpolateLinear(h[e[f]],h[o],l[o],h[i],l[i])})}_interpolateLinear(t,s,e,n,a){return e+(t-s)*(a-e)/(n-s)}async _shift(t,s,e){const n=t.map(a=>[v(this.dataX[a],s,e),this.dataY[a]]);await this._deleteDataPoints(t),await this._addDataPoints(n)}async _fillGapsV2(t,s,e,n){const a=navigator.hardwareConcurrency||1,o=[],i=[],h=this.dataX.length,l=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:this.dataX.buffer.maxByteLength}),f=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:this.dataY.buffer.maxByteLength});for(let u=0;u<a;u++)i.push(new Promise(d=>{const y=new M;o.push(y),y.postMessage({bufferX:this.dataX.buffer,bufferY:this.dataY.buffer,outputBufferX:l,outputBufferY:f}),y.onmessage=m=>{d(m.data)}}));await Promise.all(i),o.forEach(u=>u.terminate()),this.dataset.source.x=new Float64Array(l),this.dataset.source.y=new Float32Array(f),this._resizeTo(h)}_fillGaps(t,s,e,n){const a=this._findGaps(t[0],t[1],n);for(let o=a.length-1;o>=0;o--){const i=a[o],h=this.dataX[i[0]],l=this.dataX[i[1]],f=[],u=s[0]*A[s[1]]*1e3;let d=h+u;for(;d<l;){const y=e?this._interpolateLinear(d,this.dataX[i[0]],this.dataY[i[0]],this.dataX[i[1]],this.dataY[i[1]]):-9999;f.push([d,y]),d+=u}this._addDataPoints(f)}}async _deleteDataPoints(t){const s=navigator.hardwareConcurrency||1,e=Math.ceil(this.dataX.length/s),n=[],a=[];for(let u=0;u<s;u++){const d=u*e,y=Math.min((u+1)*e-1,this.dataX.length-1),m=C(t,d),S=N(t,y),D=t.slice(m,S+1);a.push({start:d,end:y,deleteSegment:D})}const o=new Array(s).fill(0);for(let u=1;u<s;u++)o[u]=o[u-1]+a[u-1].deleteSegment.length;const i=[],h=this.dataX.length-t.length,l=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:this.dataX.buffer.maxByteLength}),f=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:this.dataY.buffer.maxByteLength});for(let u=0;u<s;u++){const{start:d,end:y,deleteSegment:m}=a[u],S=d-o[u];i.push(new Promise(D=>{const b=new U;n.push(b),b.postMessage({bufferX:this.dataX.buffer,bufferY:this.dataY.buffer,outputBufferX:l,outputBufferY:f,start:d,end:y,deleteSegment:m,startTarget:S}),b.onmessage=V=>{D(V.data)}}))}await Promise.all(i),n.forEach(u=>u.terminate()),this.dataset.source.x=new Float64Array(l),this.dataset.source.y=new Float32Array(f),this._resizeTo(h)}_driftCorrection(t,s,e){const n=this.dataset.source.x,a=this.dataset.source.y,o=n[t],h=n[s]-o;for(let l=t;l<s;l++)this.dataset.source.y[l]=a[l]+e*((n[l]-o)/h)}_getConsecutiveGroups(t){const s=[[]];return t.reduce((e,n)=>{const a=e[e.length-1];return!a.length||n==a[a.length-1]+1?a.push(n):e.push([n]),e},s),s}async _addDataPoints(t){const s=this.dataX.length+t.length;this._growBuffer(s),t.sort((a,o)=>a[0]-o[0]);const e=t.map(a=>N(this.dataX,a[0])+1);this._resizeTo(s),e.push(this.dataX.length);let n=t.length;for(let a=e.length-1;a>0;a--){const o=e[a-1],i=e[a]-1;for(let h=i;h>=o;h--)this.dataX[h+n]=this.dataX[h],this.dataY[h+n]=this.dataY[h];n--,this.dataX[o+n]=t[a-1][0],this.dataY[o+n]=t[a-1][1]}}_valueThreshold(t){const s=[];return this.dataset.source.y.forEach((e,n)=>{Object.keys(t).some(a=>x[a]?.(e,t[a]))&&s.push(n)}),s}_rateOfChange(t,s){const e=[],n=this.dataset.source.y;for(let a=1;a<n.length;a++){const o=n[a-1],h=(n[a]-o)/Math.abs(o);X[t]?.(h,s)&&e.push(a)}return e}_findGaps(t,s,e){const n=[],a=this.dataset.source.x;let o=0,i=a.length;e?.[0]&&e?.[1]&&(o=e[0],i=e[1]);let h=a[o];for(let l=o+1;l<=i;l++){const f=a[l];f-h>t*A[s]*1e3&&n.push([l-1,l]),h=f}return n}_persistence(t,s){let e=[],n=this.dataset.source.y,a=0,o=n.length;s?.[0]&&s?.[1]&&(a=s[0],o=s[1]);let i=n[a],h=[];for(let l=a+1;l<o;l++)n[l]!=i||l===o?(h.length>=t&&(e=[...e,...h]),h=[]):h.push(l);return e}}E.ObservationRecord=j,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d["@uwrl/qc-utils"]={}))})(this,function(d){"use strict";var c=(s=>(s.ADD_POINTS="ADD_POINTS",s.CHANGE_VALUES="CHANGE_VALUES",s.DELETE_POINTS="DELETE_POINTS",s.DRIFT_CORRECTION="DRIFT_CORRECTION",s.INTERPOLATE="INTERPOLATE",s.SHIFT_DATETIMES="SHIFT_DATETIMES",s.FILL_GAPS="FILL_GAPS",s))(c||{}),L=(s=>(s.FIND_GAPS="FIND_GAPS",s.PERSISTENCE="PERSISTENCE",s.RATE_OF_CHANGE="RATE_OF_CHANGE",s.VALUE_THRESHOLD="VALUE_THRESHOLD",s))(L||{}),R=(s=>(s.LT="Less than",s.LTE="Less than or equal to",s.GT="Greater than",s.GTE="Greater than or equal to",s.E="Equal",s.START="Start datetime",s.END="End datetime",s))(R||{});const B={"Less than":(s,t)=>s<t,"Less than or equal to":(s,t)=>s<=t,"Greater than":(s,t)=>s>t,"Greater than or equal to":(s,t)=>s>=t,Equal:(s,t)=>s==t,"Start datetime":(s,t)=>s==t,"End datetime":(s,t)=>s==t};var g=(s=>(s.ADD="ADD",s.SUB="SUB",s.MULT="MULT",s.DIV="DIV",s.ASSIGN="ASSIGN",s))(g||{}),I=(s=>(s.LT="Less than",s.LTE="Less than or equal to",s.GT="Greater than",s.GTE="Greater than or equal to",s.E="Equal",s))(I||{});const N={"Less than":(s,t)=>s<t,"Less than or equal to":(s,t)=>s<=t,"Greater than":(s,t)=>s>t,"Greater than or equal to":(s,t)=>s>=t,Equal:(s,t)=>s==t},F=`(function(){"use strict";self.onmessage=o=>{const{bufferX:s,bufferY:n,outputBufferX:u,outputBufferY:f,start:l,end:y,deleteSegment:a,startTarget:c}=o.data,A=new Float64Array(s),d=new Float32Array(n),g=new Float64Array(u),p=new Float32Array(f);let e=0,r=c;for(let t=l;t<=y;t++)e<a.length&&t===a[e]?e++:(g[r]=A[t],p[r]=d[t],r++);self.postMessage("Done")}})();
2
+ `,Y=typeof self<"u"&&self.Blob&&new Blob([F],{type:"text/javascript;charset=utf-8"});function x(s){let t;try{if(t=Y&&(self.URL||self.webkitURL).createObjectURL(Y),!t)throw"";const a=new Worker(t,{name:s?.name});return a.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),a}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(F),{name:s?.name})}finally{t&&(self.URL||self.webkitURL).revokeObjectURL(t)}}const P=`(function(){"use strict";self.onmessage=function(e){const{bufferX:f,bufferY:t,outputBufferX:u,outputBufferY:s}=e.data;self.postMessage("Done")}})();
3
+ `,X=typeof self<"u"&&self.Blob&&new Blob([P],{type:"text/javascript;charset=utf-8"});function C(s){let t;try{if(t=X&&(self.URL||self.webkitURL).createObjectURL(X),!t)throw"";const a=new Worker(t,{name:s?.name});return a.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(t)}),a}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(P),{name:s?.name})}finally{t&&(self.URL||self.webkitURL).revokeObjectURL(t)}}const k=(s,t)=>{let a=0,e=s.length;for(;a<e;){const n=a+e>>1;s[n]<t?a=n+1:e=n}return a},G=(s,t)=>{let a=0,e=s.length;for(;a<e;){const n=a+e>>1;s[n]>t?e=n:a=n+1}return a-1},_=async(s,t)=>{const a=performance.now(),e=await s(),n=performance.now();console.log(` Done in ${(n-a).toFixed(2)} ms`);const r=+(n-a);return{response:e,duration:r}},U=1,M=U*60,p=M*60,w=p*24,O=w*7,v=p*30,H=w*365,A={s:U,m:M,h:p,D:w,W:O,M:v,Y:H},j=(s,t,a)=>{if(a==="M"){const e=new Date(s);return e.setMonth(e.getMonth()+t),e.getTime()}else if(a==="Y"){const e=new Date(s);return e.setFullYear(e.getFullYear()+t),e.getTime()}else return s+t*A[a]*1e3},T=20*1e3,q=["date","value","qualifier"];class V{dataset={dimensions:q,source:{x:new Float64Array(new SharedArrayBuffer(T*Float64Array.BYTES_PER_ELEMENT,{maxByteLength:T*Float64Array.BYTES_PER_ELEMENT})),y:new Float32Array(new SharedArrayBuffer(T*Float32Array.BYTES_PER_ELEMENT,{maxByteLength:T*Float32Array.BYTES_PER_ELEMENT}))}};history=[];loadingTime=null;isLoading=!0;rawData;constructor(t){this.history=[],this.rawData=t,this.loadData(this.rawData)}async loadData(t){if(!t)return;this.isLoading=!0;const a=await _(()=>{this._growBuffer(t.datetimes.length),this._resizeTo(t.datetimes.length),this.dataX.set(t.datetimes),this.dataY.set(t.dataValues)});this.loadingTime=a.duration,this.history.length=0,this.isLoading=!1}get dataX(){return this.dataset.source.x}get dataY(){return this.dataset.source.y}_resizeTo(t){this.dataset.source.x=new Float64Array(this.dataset.source.x.buffer).subarray(0,t),this.dataset.source.y=new Float32Array(this.dataset.source.y.buffer).subarray(0,t)}_growBuffer(t){const a=t*Float64Array.BYTES_PER_ELEMENT;let e=this.dataX.buffer.byteLength;for(;a>e;)e+=T*Float64Array.BYTES_PER_ELEMENT;if(e*Float64Array.BYTES_PER_ELEMENT>this.dataX.buffer.maxByteLength){const n=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:e*Float64Array.BYTES_PER_ELEMENT}),r=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:e*Float32Array.BYTES_PER_ELEMENT}),o=new Float64Array(n),i=new Float32Array(r);o.set(this.dataX),i.set(this.dataY),this.dataset.source.x=o,this.dataset.source.y=i}this.dataX.buffer.byteLength<t*Float64Array.BYTES_PER_ELEMENT&&(this.dataX.buffer.grow(t*Float64Array.BYTES_PER_ELEMENT),this.dataY.buffer.grow(t*Float32Array.BYTES_PER_ELEMENT))}async reload(){this.loadingTime=null,this.isLoading=!0,this.history.length=0,await this.loadData(this.rawData)}async reloadHistory(t){const a=this.history.slice(0,t+1);await this.reload(),await this.dispatch(a.map(e=>[e.method,...e.args||[]]))}async removeHistoryItem(t){const a=[...this.history];a.splice(t,1),await this.reload(),await this.dispatch(a.map(e=>[e.method,...e.args||[]]))}get beginTime(){return this.dataset.source.x.length?new Date(this.dataset.source.x[0]):null}get endTime(){return this.dataset.source.x.length?new Date(this.dataset.source.x[this.dataset.source.x.length-1]):null}async dispatch(t,...a){const e={[c.ADD_POINTS]:this._addDataPoints,[c.CHANGE_VALUES]:this._changeValues,[c.DELETE_POINTS]:this._deleteDataPoints,[c.DRIFT_CORRECTION]:this._driftCorrection,[c.INTERPOLATE]:this._interpolate,[c.SHIFT_DATETIMES]:this._shift,[c.FILL_GAPS]:this._fillGaps},n={[c.ADD_POINTS]:"mdi-plus",[c.CHANGE_VALUES]:"mdi-pencil",[c.DELETE_POINTS]:"mdi-trash-can",[c.DRIFT_CORRECTION]:"mdi-chart-sankey",[c.INTERPOLATE]:"mdi-transit-connection-horizontal",[c.SHIFT_DATETIMES]:"mdi-calendar",[c.FILL_GAPS]:"mdi-keyboard-space"};let r=[];try{if(Array.isArray(t)){for(let o=0;o<t.length;o++){const i=t[o][0],h=t[o].slice(1,t[o].length),l={method:i,args:h,icon:n[i],isLoading:!1};this.history.push(l)}for(let o=this.history.length-t.length;o<this.history.length;o++){const i=this.history[o];i.isLoading=!0;const h=await _(async()=>await e[i.method].apply(this,i.args));i.duration=h.duration,i.isLoading=!1,r.push(h.response)}}else{const o={method:t,args:a,icon:n[t],isLoading:!0};this.history.push(o);const i=await _(async()=>await e[t].apply(this,a));r=i.response,o.duration=i.duration,o.isLoading=!1}}catch(o){console.log(`Failed to execute operation: ${t} with arguments: `,a),console.log(o)}return r}async dispatchFilter(t,...a){const e={[L.FIND_GAPS]:this._findGaps,[L.VALUE_THRESHOLD]:this._valueThreshold,[L.PERSISTENCE]:this._persistence,[L.RATE_OF_CHANGE]:this._rateOfChange};let n=[];try{if(Array.isArray(t))for(let r=0;r<t.length;r++){const o=t[r][0],i=t[r].slice(1,t[r].length),h=await e[o].apply(this,i);n.push(h)}else n=await e[t].apply(this,a)}catch(r){console.log(`Failed to execute filter operation: ${t} with arguments: `,a),console.log(r)}return n}_changeValues(t,a,e){const n=r=>{switch(a){case g.ADD:return r+e;case g.ASSIGN:return e;case g.DIV:return r/e;case g.MULT:return r*e;case g.SUB:return r-e;default:return r}};t.forEach(r=>{this.dataset.source.y[r]=n(this.dataset.source.y[r])})}_interpolate(t){this._getConsecutiveGroups(t).forEach(e=>{const n=e[0],r=e[e.length-1];let o=Math.max(0,n-1),i=Math.min(this.dataset.source.y.length-1,r+1);const h=this.dataset.source.x,l=this.dataset.source.y;for(let f=0;f<e.length;f++)this.dataset.source.y[e[f]]=this._interpolateLinear(h[e[f]],h[o],l[o],h[i],l[i])})}_interpolateLinear(t,a,e,n,r){return e+(t-a)*(r-e)/(n-a)}async _shift(t,a,e){const n=t.map(r=>[j(this.dataX[r],a,e),this.dataY[r]]);await this._deleteDataPoints(t),await this._addDataPoints(n)}async _fillGapsV2(t,a,e,n){const r=navigator.hardwareConcurrency||1,o=[],i=[],h=this.dataX.length,l=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:this.dataX.buffer.maxByteLength}),f=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:this.dataY.buffer.maxByteLength});for(let u=0;u<r;u++)i.push(new Promise(E=>{const y=new C;o.push(y),y.postMessage({bufferX:this.dataX.buffer,bufferY:this.dataY.buffer,outputBufferX:l,outputBufferY:f}),y.onmessage=m=>{E(m.data)}}));await Promise.all(i),o.forEach(u=>u.terminate()),this.dataset.source.x=new Float64Array(l),this.dataset.source.y=new Float32Array(f),this._resizeTo(h)}_fillGaps(t,a,e,n){const r=this._findGaps(t[0],t[1],n);for(let o=r.length-1;o>=0;o--){const i=r[o],h=this.dataX[i[0]],l=this.dataX[i[1]],f=[],u=a[0]*A[a[1]]*1e3;let E=h+u;for(;E<l;){const y=e?this._interpolateLinear(E,this.dataX[i[0]],this.dataY[i[0]],this.dataX[i[1]],this.dataY[i[1]]):-9999;f.push([E,y]),E+=u}this._addDataPoints(f)}}async _deleteDataPoints(t){const a=navigator.hardwareConcurrency||1,e=Math.ceil(this.dataX.length/a),n=[],r=[];for(let u=0;u<a;u++){const E=u*e,y=Math.min((u+1)*e-1,this.dataX.length-1),m=k(t,E),S=G(t,y),D=t.slice(m,S+1);r.push({start:E,end:y,deleteSegment:D})}const o=new Array(a).fill(0);for(let u=1;u<a;u++)o[u]=o[u-1]+r[u-1].deleteSegment.length;const i=[],h=this.dataX.length-t.length,l=new SharedArrayBuffer(this.dataX.buffer.byteLength,{maxByteLength:this.dataX.buffer.maxByteLength}),f=new SharedArrayBuffer(this.dataY.buffer.byteLength,{maxByteLength:this.dataY.buffer.maxByteLength});for(let u=0;u<a;u++){const{start:E,end:y,deleteSegment:m}=r[u],S=E-o[u];i.push(new Promise(D=>{const b=new x;n.push(b),b.postMessage({bufferX:this.dataX.buffer,bufferY:this.dataY.buffer,outputBufferX:l,outputBufferY:f,start:E,end:y,deleteSegment:m,startTarget:S}),b.onmessage=W=>{D(W.data)}}))}await Promise.all(i),n.forEach(u=>u.terminate()),this.dataset.source.x=new Float64Array(l),this.dataset.source.y=new Float32Array(f),this._resizeTo(h)}_driftCorrection(t,a,e){const n=this.dataset.source.x,r=this.dataset.source.y,o=n[t],h=n[a]-o;for(let l=t;l<a;l++)this.dataset.source.y[l]=r[l]+e*((n[l]-o)/h)}_getConsecutiveGroups(t){const a=[[]];return t.reduce((e,n)=>{const r=e[e.length-1];return!r.length||n==r[r.length-1]+1?r.push(n):e.push([n]),e},a),a}async _addDataPoints(t){const a=this.dataX.length+t.length;this._growBuffer(a),t.sort((r,o)=>r[0]-o[0]);const e=t.map(r=>G(this.dataX,r[0])+1);this._resizeTo(a),e.push(this.dataX.length);let n=t.length;for(let r=e.length-1;r>0;r--){const o=e[r-1],i=e[r]-1;for(let h=i;h>=o;h--)this.dataX[h+n]=this.dataX[h],this.dataY[h+n]=this.dataY[h];n--,this.dataX[o+n]=t[r-1][0],this.dataY[o+n]=t[r-1][1]}}_valueThreshold(t){const a=[];return this.dataset.source.y.forEach((e,n)=>{Object.keys(t).some(r=>B[r]?.(e,t[r]))&&a.push(n)}),a}_rateOfChange(t,a){const e=[],n=this.dataset.source.y;for(let r=1;r<n.length;r++){const o=n[r-1],h=(n[r]-o)/Math.abs(o);N[t]?.(h,a)&&e.push(r)}return e}_findGaps(t,a,e){const n=[],r=this.dataset.source.x;let o=0,i=r.length;e?.[0]&&e?.[1]&&(o=e[0],i=e[1]);let h=r[o];for(let l=o+1;l<=i;l++){const f=r[l];f-h>t*A[a]*1e3&&n.push([l-1,l]),h=f}return n}_persistence(t,a){let e=[],n=this.dataset.source.y,r=0,o=n.length;a?.[0]&&a?.[1]&&(r=a[0],o=a[1]);let i=n[r],h=[];for(let l=r+1;l<o;l++)n[l]!=i||l===o?(h.length>=t&&(e=[...e,...h]),h=[]):h.push(l);return e}}d.EnumEditOperations=c,d.EnumFilterOperations=L,d.FilterOperation=R,d.FilterOperationFn=B,d.ObservationRecord=V,d.Operator=g,d.RateOfChangeComparator=N,d.RateOfChangeOperation=I,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uwrl/qc-utils",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "Quality Control Utilities",
5
5
  "homepage": "https://github.com/hydroserver2/qc-utils#readme",
6
6
  "bugs": {