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