@uwrl/qc-utils 0.0.12 → 0.0.13

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