@uwrl/qc-utils 0.0.9 → 0.0.12

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.
@@ -0,0 +1,36 @@
1
+ self.onmessage = (e) => {
2
+ const {
3
+ bufferX,
4
+ bufferY,
5
+ outputBufferX,
6
+ outputBufferY,
7
+ start,
8
+ end,
9
+ deleteSegment,
10
+ startTarget,
11
+ } = e.data
12
+ const arrayX = new Float64Array(bufferX)
13
+ const arrayY = new Float32Array(bufferY)
14
+ const outputArrayX = new Float64Array(outputBufferX)
15
+ const outputArrayY = new Float32Array(outputBufferY)
16
+
17
+ let deletePtr = 0
18
+ let writePtr = startTarget
19
+
20
+ // Copy non-deleted elements to output buffer
21
+ for (let readPtr = start; readPtr <= end; readPtr++) {
22
+ if (
23
+ deletePtr < deleteSegment.length &&
24
+ readPtr === deleteSegment[deletePtr]
25
+ ) {
26
+ deletePtr++ // Skip deleted index
27
+ } else {
28
+ outputArrayX[writePtr] = arrayX[readPtr]
29
+ outputArrayY[writePtr] = arrayY[readPtr]
30
+ writePtr++
31
+ }
32
+ }
33
+
34
+
35
+ self.postMessage('Done')
36
+ }
package/dist/index.js CHANGED
@@ -1,11 +1,27 @@
1
- const A = (i, t) => {
1
+ function Y(i) {
2
+ return new Worker(
3
+ "/assets/delete-data.worker-Iw4O1ScI.js",
4
+ {
5
+ name: i?.name
6
+ }
7
+ );
8
+ }
9
+ function b(i) {
10
+ return new Worker(
11
+ "/assets/fill-gaps.worker-BesEL5v2.js",
12
+ {
13
+ name: i?.name
14
+ }
15
+ );
16
+ }
17
+ const F = (i, t) => {
2
18
  let a = 0, e = i.length;
3
19
  for (; a < e; ) {
4
20
  const r = a + e >> 1;
5
21
  i[r] < t ? a = r + 1 : e = r;
6
22
  }
7
23
  return a;
8
- }, T = (i, t) => {
24
+ }, A = (i, t) => {
9
25
  let a = 0, e = i.length;
10
26
  for (; a < e; ) {
11
27
  const r = a + e >> 1;
@@ -17,16 +33,15 @@ const A = (i, t) => {
17
33
  console.log(` Done in ${(r - a).toFixed(2)} ms`);
18
34
  const s = +(r - a);
19
35
  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) => {
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) => {
30
45
  if (a === "M") {
31
46
  const e = new Date(i);
32
47
  return e.setMonth(e.getMonth() + t), e.getTime();
@@ -35,7 +50,7 @@ const w = {
35
50
  return e.setFullYear(e.getFullYear() + t), e.getTime();
36
51
  } else
37
52
  return i + t * w[a] * 1e3;
38
- }, S = {
53
+ }, M = {
39
54
  "Less than": (i, t) => i < t,
40
55
  "Less than or equal to": (i, t) => i <= t,
41
56
  "Greater than": (i, t) => i > t,
@@ -43,17 +58,17 @@ const w = {
43
58
  Equal: (i, t) => i == t,
44
59
  "Start datetime": (i, t) => i == t,
45
60
  "End datetime": (i, t) => i == t
46
- }, Y = {
61
+ }, P = {
47
62
  "Less than": (i, t) => i < t,
48
63
  "Less than or equal to": (i, t) => i <= t,
49
64
  "Greater than": (i, t) => i > t,
50
65
  "Greater than or equal to": (i, t) => i >= t,
51
66
  Equal: (i, t) => i == t
52
- }, g = 20 * 1e3, B = ["date", "value", "qualifier"];
53
- class b {
67
+ }, g = 20 * 1e3, R = ["date", "value", "qualifier"];
68
+ class O {
54
69
  /** The generated dataset to be used for plotting */
55
70
  dataset = {
56
- dimensions: B,
71
+ dimensions: R,
57
72
  source: {
58
73
  x: new Float64Array(
59
74
  new SharedArrayBuffer(
@@ -301,7 +316,7 @@ class b {
301
316
  */
302
317
  async _shift(t, a, e) {
303
318
  const r = t.map((s) => [
304
- D(this.dataX[s], a, e),
319
+ I(this.dataX[s], a, e),
305
320
  this.dataY[s]
306
321
  ]);
307
322
  await this._deleteDataPoints(t), await this._addDataPoints(r);
@@ -315,13 +330,7 @@ class b {
315
330
  for (let u = 0; u < s; u++)
316
331
  o.push(
317
332
  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
- );
333
+ const f = new b();
325
334
  n.push(f), f.postMessage({
326
335
  bufferX: this.dataX.buffer,
327
336
  bufferY: this.dataY.buffer,
@@ -372,7 +381,7 @@ class b {
372
381
  async _deleteDataPoints(t) {
373
382
  const a = navigator.hardwareConcurrency || 1, e = Math.ceil(this.dataX.length / a), r = [], s = [];
374
383
  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);
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);
376
385
  s.push({ start: d, end: f, deleteSegment: m });
377
386
  }
378
387
  const n = new Array(a).fill(0);
@@ -387,13 +396,7 @@ class b {
387
396
  const { start: d, end: f, deleteSegment: y } = s[u], E = d - n[u];
388
397
  o.push(
389
398
  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
- );
399
+ const p = new Y();
397
400
  r.push(p), p.postMessage({
398
401
  bufferX: this.dataX.buffer,
399
402
  bufferY: this.dataY.buffer,
@@ -403,8 +406,8 @@ class b {
403
406
  end: f,
404
407
  deleteSegment: y,
405
408
  startTarget: E
406
- }), p.onmessage = (L) => {
407
- m(L.data);
409
+ }), p.onmessage = (B) => {
410
+ m(B.data);
408
411
  };
409
412
  })
410
413
  );
@@ -441,7 +444,7 @@ class b {
441
444
  async _addDataPoints(t) {
442
445
  const a = this.dataX.length + t.length;
443
446
  this._growBuffer(a), t.sort((s, n) => s[0] - n[0]);
444
- const e = t.map((s) => T(this.dataX, s[0]) + 1);
447
+ const e = t.map((s) => A(this.dataX, s[0]) + 1);
445
448
  this._resizeTo(a), e.push(this.dataX.length);
446
449
  let r = t.length;
447
450
  for (let s = e.length - 1; s > 0; s--) {
@@ -462,7 +465,7 @@ class b {
462
465
  _valueThreshold(t) {
463
466
  const a = [];
464
467
  return this.dataset.source.y.forEach((e, r) => {
465
- Object.keys(t).some((s) => S[s]?.(
468
+ Object.keys(t).some((s) => M[s]?.(
466
469
  e,
467
470
  t[s]
468
471
  )) && a.push(r);
@@ -478,7 +481,7 @@ class b {
478
481
  const e = [], r = this.dataset.source.y;
479
482
  for (let s = 1; s < r.length; s++) {
480
483
  const n = r[s - 1], h = (r[s] - n) / Math.abs(n);
481
- Y[t]?.(
484
+ P[t]?.(
482
485
  h,
483
486
  a
484
487
  ) && e.push(s);
@@ -519,5 +522,5 @@ class b {
519
522
  }
520
523
  }
521
524
  export {
522
- b as ObservationRecord
525
+ O as ObservationRecord
523
526
  };
@@ -1 +1 @@
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";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"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uwrl/qc-utils",
3
- "version": "0.0.9",
3
+ "version": "0.0.12",
4
4
  "description": "Quality Control Utilities",
5
5
  "homepage": "https://github.com/hydroserver2/qc-utils#readme",
6
6
  "bugs": {