@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.
- package/dist/assets/delete-data.worker.ts +36 -0
- package/dist/index.js +42 -39
- package/dist/index.umd.cjs +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
},
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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,
|
|
53
|
-
class
|
|
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:
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 = (
|
|
407
|
-
m(
|
|
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) =>
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
525
|
+
O as ObservationRecord
|
|
523
526
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(g
|
|
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"})});
|