@3dsource/utils 1.0.9 → 1.0.10

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.
Files changed (140) hide show
  1. package/eslint.config.js +37 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +4 -14
  4. package/{lib/color/CMYKtoRGB.d.ts → src/lib/color/CMYKtoRGB.ts} +11 -1
  5. package/src/lib/color/HEXtoRGB.ts +9 -0
  6. package/src/lib/color/HSVtoRGB.ts +82 -0
  7. package/{lib/color/RGBtoCMYK.d.ts → src/lib/color/RGBtoCMYK.ts} +31 -1
  8. package/src/lib/color/RGBtoHEX.ts +17 -0
  9. package/src/lib/color/RGBtoHSV.ts +53 -0
  10. package/src/lib/color/hsv.ts +14 -0
  11. package/src/lib/color/max.ts +18 -0
  12. package/src/lib/color/min.ts +18 -0
  13. package/src/lib/color/overlay.ts +25 -0
  14. package/{lib/color/rgb.d.ts → src/lib/color/rgb.ts} +3 -1
  15. package/src/lib/color/sub.ts +18 -0
  16. package/src/lib/color/subtract.ts +27 -0
  17. package/src/lib/color/sum.ts +19 -0
  18. package/{lib/color/toRGB.d.ts → src/lib/color/toRGB.ts} +7 -1
  19. package/src/lib/color/toRGBA.ts +8 -0
  20. package/src/lib/constants/color-codes.constant.ts +9 -0
  21. package/src/lib/csv/CSV2Array.ts +66 -0
  22. package/src/lib/csv/CSV2Records.ts +56 -0
  23. package/src/lib/csv/ObjectToCSV.ts +21 -0
  24. package/src/lib/dev/dev3d.ts +1 -0
  25. package/src/lib/dev/logger.ts +94 -0
  26. package/src/lib/dev/timeToString.ts +16 -0
  27. package/src/lib/filenaming/cleanupFileName.ts +18 -0
  28. package/src/lib/filenaming/makePath.ts +5 -0
  29. package/src/lib/filenaming/normalizePath.ts +9 -0
  30. package/src/lib/geom/expandOverRectangle.ts +17 -0
  31. package/src/lib/geom/fitIntoRectangle.ts +43 -0
  32. package/{lib/geom/interfaces/area.interface.d.ts → src/lib/geom/interfaces/area.interface.ts} +2 -1
  33. package/{lib/geom/interfaces/rect.interface.d.ts → src/lib/geom/interfaces/rect.interface.ts} +2 -2
  34. package/src/lib/geom/interfaces/size.interface.ts +4 -0
  35. package/src/lib/geom/interfaces//321/201oords.interface.ts +4 -0
  36. package/src/lib/helpers/BatchLoader.ts +243 -0
  37. package/src/lib/helpers/KeyboardNumericCode.ts +118 -0
  38. package/src/lib/helpers/debounce.ts +10 -0
  39. package/src/lib/helpers/generate-uuid.ts +5 -0
  40. package/{lib/helpers/index.d.ts → src/lib/helpers/index.ts} +1 -0
  41. package/src/lib/helpers/save-to-local-drive.ts +31 -0
  42. package/src/lib/helpers/serialize.ts +11 -0
  43. package/src/lib/helpers/short-hash.ts +20 -0
  44. package/src/lib/helpers/signal.ts +46 -0
  45. package/src/lib/helpers/sleep.ts +3 -0
  46. package/src/lib/helpers/trimLastSlashFromUrl.ts +9 -0
  47. package/src/lib/image/SaveImage.ts +65 -0
  48. package/src/lib/image/getCanvasCached.ts +16 -0
  49. package/src/lib/image/getSnapshot.ts +99 -0
  50. package/src/lib/image/loadImage.ts +13 -0
  51. package/src/lib/interfaces/image-output.ts +8 -0
  52. package/{lib/interfaces/load-args-tmp.interface.d.ts → src/lib/interfaces/load-args-tmp.interface.ts} +2 -1
  53. package/src/lib/interfaces/load-args.interface.ts +15 -0
  54. package/{lib/math/baseSortedIndex.d.ts → src/lib/math/baseSortedIndex.ts} +19 -1
  55. package/{lib/math/calculateMedian.d.ts → src/lib/math/calculateMedian.ts} +17 -1
  56. package/{lib/math/circularIndex.d.ts → src/lib/math/circularIndex.ts} +5 -1
  57. package/src/lib/math/clampf.ts +14 -0
  58. package/src/lib/math/degrees.ts +7 -0
  59. package/{lib/math/floatCompare.d.ts → src/lib/math/floatCompare.ts} +30 -3
  60. package/{lib/math/inverseLerp.d.ts → src/lib/math/inverseLerp.ts} +22 -1
  61. package/src/lib/math/lerp.ts +12 -0
  62. package/{lib/mutex/Mutex.d.ts → src/lib/mutex/Mutex.ts} +15 -8
  63. package/{lib/mutex/Semaphore.d.ts → src/lib/mutex/Semaphore.ts} +27 -7
  64. package/src/lib/mutex/TaskRunner.ts +26 -0
  65. package/src/lib/predicates/operators.ts +75 -0
  66. package/{lib/predicates/textForSearch.d.ts → src/lib/predicates/textForSearch.ts} +17 -1
  67. package/{lib/predicates/where.d.ts → src/lib/predicates/where.ts} +32 -2
  68. package/src/lib/rxjs/leadingTrailingDebounceTime.ts +86 -0
  69. package/{lib/rxjs/smoothTransition.d.ts → src/lib/rxjs/smoothTransition.ts} +19 -1
  70. package/src/lib/rxjs/tapLog.ts +13 -0
  71. package/src/lib/strings/pad.ts +18 -0
  72. package/tsconfig.lib.json +13 -0
  73. package/tsconfig.lib.prod.json +11 -0
  74. package/fesm2022/3dsource-utils.mjs +0 -1886
  75. package/fesm2022/3dsource-utils.mjs.map +0 -1
  76. package/index.d.ts +0 -5
  77. package/lib/color/HEXtoRGB.d.ts +0 -5
  78. package/lib/color/HSVtoRGB.d.ts +0 -21
  79. package/lib/color/RGBtoHEX.d.ts +0 -1
  80. package/lib/color/RGBtoHSV.d.ts +0 -19
  81. package/lib/color/hsv.d.ts +0 -1
  82. package/lib/color/max.d.ts +0 -1
  83. package/lib/color/min.d.ts +0 -1
  84. package/lib/color/overlay.d.ts +0 -1
  85. package/lib/color/sub.d.ts +0 -1
  86. package/lib/color/subtract.d.ts +0 -1
  87. package/lib/color/sum.d.ts +0 -1
  88. package/lib/color/toRGBA.d.ts +0 -1
  89. package/lib/constants/color-codes.constant.d.ts +0 -9
  90. package/lib/csv/CSV2Array.d.ts +0 -1
  91. package/lib/csv/CSV2Records.d.ts +0 -1
  92. package/lib/csv/ObjectToCSV.d.ts +0 -1
  93. package/lib/dev/dev3d.d.ts +0 -1
  94. package/lib/dev/logger.d.ts +0 -11
  95. package/lib/dev/timeToString.d.ts +0 -5
  96. package/lib/filenaming/cleanupFileName.d.ts +0 -1
  97. package/lib/filenaming/makePath.d.ts +0 -1
  98. package/lib/filenaming/normalizePath.d.ts +0 -1
  99. package/lib/geom/expandOverRectangle.d.ts +0 -2
  100. package/lib/geom/fitIntoRectangle.d.ts +0 -2
  101. package/lib/geom/interfaces/size.interface.d.ts +0 -4
  102. package/lib/geom/interfaces//321/201oords.interface.d.ts +0 -4
  103. package/lib/helpers/BatchLoader.d.ts +0 -47
  104. package/lib/helpers/KeyboardNumericCode.d.ts +0 -103
  105. package/lib/helpers/debounce.d.ts +0 -1
  106. package/lib/helpers/generate-uuid.d.ts +0 -1
  107. package/lib/helpers/save-to-local-drive.d.ts +0 -1
  108. package/lib/helpers/serialize.d.ts +0 -1
  109. package/lib/helpers/signal.d.ts +0 -23
  110. package/lib/helpers/sleep.d.ts +0 -1
  111. package/lib/helpers/trimLastSlashFromUrl.d.ts +0 -1
  112. package/lib/image/SaveImage.d.ts +0 -18
  113. package/lib/image/getCanvasCached.d.ts +0 -4
  114. package/lib/image/getSnapshot.d.ts +0 -2
  115. package/lib/image/loadImage.d.ts +0 -1
  116. package/lib/interfaces/image-output.d.ts +0 -7
  117. package/lib/interfaces/load-args.interface.d.ts +0 -15
  118. package/lib/math/clampf.d.ts +0 -8
  119. package/lib/math/degrees.d.ts +0 -2
  120. package/lib/math/lerp.d.ts +0 -7
  121. package/lib/mutex/TaskRunner.d.ts +0 -5
  122. package/lib/predicates/operators.d.ts +0 -32
  123. package/lib/rxjs/leadingTrailingDebounceTime.d.ts +0 -15
  124. package/lib/rxjs/tapLog.d.ts +0 -2
  125. package/lib/strings/pad.d.ts +0 -8
  126. /package/{lib/color/index.d.ts → src/lib/color/index.ts} +0 -0
  127. /package/{lib/constants/index.d.ts → src/lib/constants/index.ts} +0 -0
  128. /package/{lib/csv/index.d.ts → src/lib/csv/index.ts} +0 -0
  129. /package/{lib/dev/index.d.ts → src/lib/dev/index.ts} +0 -0
  130. /package/{lib/filenaming/index.d.ts → src/lib/filenaming/index.ts} +0 -0
  131. /package/{lib/geom/index.d.ts → src/lib/geom/index.ts} +0 -0
  132. /package/{lib/geom/interfaces/index.d.ts → src/lib/geom/interfaces/index.ts} +0 -0
  133. /package/{lib/image/index.d.ts → src/lib/image/index.ts} +0 -0
  134. /package/{lib/interfaces/index.d.ts → src/lib/interfaces/index.ts} +0 -0
  135. /package/{lib/math/index.d.ts → src/lib/math/index.ts} +0 -0
  136. /package/{lib/mutex/index.d.ts → src/lib/mutex/index.ts} +0 -0
  137. /package/{lib/predicates/index.d.ts → src/lib/predicates/index.ts} +0 -0
  138. /package/{lib/rxjs/index.d.ts → src/lib/rxjs/index.ts} +0 -0
  139. /package/{lib/strings/index.d.ts → src/lib/strings/index.ts} +0 -0
  140. /package/{public-api.d.ts → src/public-api.ts} +0 -0
@@ -1,1886 +0,0 @@
1
- import { Subject, from, switchMap, finalize, asyncScheduler, Observable, timer, animationFrameScheduler, interval } from 'rxjs';
2
- import { filter, map, distinctUntilChanged, tap } from 'rxjs/operators';
3
- import { v4 } from 'uuid';
4
-
5
- /**
6
- * RGB from each of the CMYK values to determine a return as an any[].
7
- * CMYK values are as follows.
8
- * C - a number between 0 and 255 representing cyan
9
- * M - number between 0 and 255 representing magenta
10
- * Y - number between 0 and 255 representing yellow
11
- * K - number between 0 and 255 representing black
12
- *
13
- **/
14
- function CMYKtoRGB(c, m, y, k) {
15
- c = 255 - c;
16
- m = 255 - m;
17
- y = 255 - y;
18
- k = 255 - k;
19
- return [
20
- ((255 - c) * (255 - k)) / 255,
21
- ((255 - m) * (255 - k)) / 255,
22
- ((255 - y) * (255 - k)) / 255,
23
- ];
24
- }
25
-
26
- function HEXtoRGB(color) {
27
- if (typeof color === 'string') {
28
- color = parseInt(color.replace('#', ''), 16);
29
- }
30
- const r = (color >> 16) & 255;
31
- const g = (color >> 8) & 255;
32
- const b = color & 255;
33
- return { r: r, g: g, b: b };
34
- }
35
-
36
- /**
37
- * Values calculated from each RGB * RGB color value.
38
- * @ Param r the red (R) indicating the number (0-255)
39
- * @ Param g green (G) indicates the number (0-255)
40
- * @ Param b blue (B) shows the number (0-255)
41
- * @ Return obtained from the RGB color value for each indicating the number
42
- **/
43
- function rgb(r, g, b) {
44
- return (r << 16) | (g << 8) | b;
45
- }
46
-
47
- /* eslint-disable prefer-const */
48
- /**
49
- * HSV from each of the RGB values to determine a return as an any[].
50
- * RGB values are as follows.
51
- * R - a number from 0 to 255
52
- * G - a number from 0 to 255
53
- * B - a number from 0 to 255
54
- *
55
- * HSV values are as follows.
56
- * H - a number between 360-0
57
- * S - number between 0 and 1.0
58
- * V - number between 0 and 1.0
59
- *
60
- * H is replaced with equivalent numbers in the range of the 360-0 that is out of range.
61
- * Cannot compute, including alpha.
62
- *
63
- * @ Param h hue (Hue) number that indicates (to 360-0)
64
- * @ Param s the saturation (Saturation) shows the number (0.0 to 1.0)
65
- * @ Param v lightness (Value) indicates the number (0.0 to 1.0)
66
- * @ Return RGB values into an any[] of [R, G, B]
67
- **/
68
- function HSVtoRGB(h, s, v) {
69
- let r = 0, g = 0, b = 0;
70
- let i, x, y, z;
71
- if (s < 0) {
72
- s = 0;
73
- }
74
- if (s > 1) {
75
- s = 1;
76
- }
77
- if (v < 0) {
78
- v = 0;
79
- }
80
- if (v > 1) {
81
- v = 1;
82
- }
83
- h = h % 360;
84
- if (h < 0) {
85
- h += 360;
86
- }
87
- h /= 60;
88
- i = h >> 0;
89
- x = v * (1 - s);
90
- y = v * (1 - s * (h - i));
91
- z = v * (1 - s * (1 - h + i));
92
- switch (i) {
93
- case 0:
94
- r = v;
95
- g = z;
96
- b = x;
97
- break;
98
- case 1:
99
- r = y;
100
- g = v;
101
- b = x;
102
- break;
103
- case 2:
104
- r = x;
105
- g = v;
106
- b = z;
107
- break;
108
- case 3:
109
- r = x;
110
- g = y;
111
- b = v;
112
- break;
113
- case 4:
114
- r = z;
115
- g = x;
116
- b = v;
117
- break;
118
- case 5:
119
- r = v;
120
- g = x;
121
- b = y;
122
- break;
123
- }
124
- return [(r * 255) >> 0, (g * 255) >> 0, (b * 255) >> 0];
125
- }
126
-
127
- /* eslint-disable prefer-spread */
128
- /**
129
- * HSV calculated from the numbers of each RGB color value.
130
- * @ Param h hue (Hue) number that indicates (to 360-0)
131
- * @ Param s the saturation (Saturation) shows the number (0.0 to 1.0)
132
- * @ Param v lightness (Value) indicates the number (0.0 to 1.0)
133
- * @ Return obtained from the RGB color value for each indicating the number
134
- **/
135
- function hsv(h, s, v) {
136
- return rgb.apply(null, HSVtoRGB(h, s, v));
137
- }
138
-
139
- /**
140
- * RGB figures show (0x000000 0xFFFFFF up from) the
141
- * R, G, B returns an any[] divided into a number from 0 to 255, respectively.
142
- *
143
- * @ Param rgb numbers show (0x000000 0xFFFFFF up from)
144
- * @ Return any[] indicates the value of each color [R, G, B]
145
- **/
146
- function toRGB(rgb) {
147
- const r = (rgb >> 16) & 0xff;
148
- const g = (rgb >> 8) & 0xff;
149
- const b = rgb & 0xff;
150
- return [r, g, b];
151
- }
152
-
153
- /**
154
- * Comparison (light).
155
- * 2 RGB single number that indicates (0x000000 0xFFFFFF up from) to compare,
156
- * RGB values combined with higher returns to their numbers.
157
- * @ Param col1 RGB numbers show (0x000000 0xFFFFFF up from)
158
- * @ Param col2 RGB numbers show (0x000000 0xFFFFFF up from)
159
- * @ Return comparison (light) value
160
- **/
161
- function max(col1, col2) {
162
- const c1 = toRGB(col1);
163
- const c2 = toRGB(col2);
164
- const r = Math.max(c1[0], c2[0]);
165
- const g = Math.max(c1[1], c2[1]);
166
- const b = Math.max(c1[2], c2[2]);
167
- return (r << 16) | (g << 8) | b;
168
- }
169
-
170
- /**
171
- * Comparison (dark).
172
- * 2 RGB single numbers that indicate (0x000000 0xFFFFFF up from) to compare,
173
- * RGB lower combined returns a numeric value for each number.
174
- * @ Param col1 RGB numbers show (0x000000 0xFFFFFF up from)
175
- * @ Param col2 RGB numbers show (0x000000 0xFFFFFF up from)
176
- * @ Return comparison (dark) values
177
- **/
178
- function min(col1, col2) {
179
- const c1 = toRGB(col1);
180
- const c2 = toRGB(col2);
181
- const r = Math.min(c1[0], c2[0]);
182
- const g = Math.min(c1[1], c2[1]);
183
- const b = Math.min(c1[2], c2[2]);
184
- return (r << 16) | (g << 8) | b;
185
- }
186
-
187
- /**
188
- *
189
- There are two part of formula:
190
- First part: If Lower Layer Value > 127.5, then do the following -
191
- Value Unit = (255-Lower Layer Value)/127.5
192
- Min Value = Lower Layer Value - (255-Lower Layer Value)
193
- Overlay = (Upper Layer Value * Value Unit) + Min Value
194
- Second part: If Lower Layer Value < 127.5, then do the following -
195
- Value Unit=Lower Layer Value/127.5
196
-
197
- Overlay = Upper Layer Value * Value Unit
198
- * @param {number} col1
199
- * @param {number} col2
200
- * @return {number}
201
- */
202
- function overlay(col1, col2) {
203
- const c1 = toRGB(col1);
204
- const c2 = toRGB(col2);
205
- const r = Math.max(c1[0], c2[0]);
206
- const g = Math.max(c1[1], c2[1]);
207
- const b = Math.max(c1[2], c2[2]);
208
- return (r << 16) | (g << 8) | b;
209
- }
210
-
211
- /**
212
- * RGB from the respective figures, HSV sequences in terms of returns.
213
- * RGB values are as follows.
214
- * R - a number from 0 to 255
215
- * G - a number from 0 to 255
216
- * B - a number from 0 to 255
217
- *
218
- * CMYK values are as follows.
219
- * C - a number between 0 and 255 representing cyan
220
- * M - number between 0 and 255 representing magenta
221
- * Y - number between 0 and 255 representing yellow
222
- * K - number between 0 and 255 representing black
223
- *
224
- * Cannot compute, including alpha.
225
- * @ Param r the red (R) indicating the number (0x00 to 0xFF to)
226
- * @ Param g green (G) indicates the number (0x00 to 0xFF to)
227
- * @ Param b blue (B) shows the number (0x00 to 0xFF to)
228
- * @ Return CMYK values into an any[] of [H, S, V]
229
- **/
230
- function RGBtoCMYK(r, g, b) {
231
- let c = 0;
232
- let m = 0;
233
- let y = 0;
234
- let k = 0;
235
- c = 255 - r;
236
- m = 255 - g;
237
- y = 255 - b;
238
- k = 255;
239
- if (c < k) {
240
- k = c;
241
- }
242
- if (m < k) {
243
- k = m;
244
- }
245
- if (y < k) {
246
- k = y;
247
- }
248
- if (k === 255) {
249
- c = 0;
250
- m = 0;
251
- y = 0;
252
- }
253
- else {
254
- c = Math.round((255 * (c - k)) / (255 - k));
255
- m = Math.round((255 * (m - k)) / (255 - k));
256
- y = Math.round((255 * (y - k)) / (255 - k));
257
- }
258
- return [c, m, y, k];
259
- }
260
-
261
- function RGBtoHEX(r, g, b) {
262
- let redColor = r.toString(16);
263
- let greenColor = g.toString(16);
264
- let blackColor = b.toString(16);
265
- if (redColor.length === 1) {
266
- redColor = '0' + redColor;
267
- }
268
- if (greenColor.length === 1) {
269
- greenColor = '0' + greenColor;
270
- }
271
- if (blackColor.length === 1) {
272
- blackColor = '0' + blackColor;
273
- }
274
- return (redColor + greenColor + blackColor).toUpperCase();
275
- }
276
-
277
- /**
278
- * RGB from the respective figures, HSV sequences in terms of returns.
279
- * RGB values are as follows.
280
- * R - a number from 0 to 255
281
- * G - a number from 0 to 255
282
- * B - a number from 0 to 255
283
- *
284
- * HSV values are as follows.
285
- * H - a number between 360-0
286
- * S - number between 0 and 1.0
287
- * V - number between 0 and 1.0
288
- *
289
- * Cannot compute, including alpha.
290
- * @ Param r the red (R) indicating the number (0x00 to 0xFF to)
291
- * @ Param g green (G) indicates the number (0x00 to 0xFF to)
292
- * @ Param b blue (B) shows the number (0x00 to 0xFF to)
293
- * @ Return HSV values into an any[] of [H, S, V]
294
- **/
295
- function RGBtoHSV(r, g, b) {
296
- r /= 255;
297
- g /= 255;
298
- b /= 255;
299
- let h = 0, s = 0, v = 0;
300
- let x, y;
301
- if (r >= g)
302
- x = r;
303
- else
304
- x = g;
305
- if (b > x)
306
- x = b;
307
- if (r <= g)
308
- y = r;
309
- else
310
- y = g;
311
- if (b < y)
312
- y = b;
313
- v = x;
314
- const c = x - y;
315
- if (x === 0)
316
- s = 0;
317
- else
318
- s = c / x;
319
- if (s !== 0) {
320
- if (r === x) {
321
- h = (g - b) / c;
322
- }
323
- else {
324
- if (g === x) {
325
- h = 2 + (b - r) / c;
326
- }
327
- else {
328
- if (b === x) {
329
- h = 4 + (r - g) / c;
330
- }
331
- }
332
- }
333
- h = h * 60;
334
- if (h < 0)
335
- h = h + 360;
336
- }
337
- return [h, s, v];
338
- }
339
-
340
- /**
341
- * Subtractive.
342
- * 2 RGB single numbers that indicate (0x000000 0xFFFFFF up from) Return the value
343
- * of the subtractive color.
344
- * @ Param col1 RGB numbers show (0x000000 0xFFFFFF up from)
345
- * @ Param col2 RGB numbers show (0x000000 0xFFFFFF up from)
346
- * @ Return the subtractive
347
- **/
348
- function sub(col1, col2) {
349
- const c1 = toRGB(col1);
350
- const c2 = toRGB(col2);
351
- const r = Math.max(c1[0] - c2[0], 0);
352
- const g = Math.max(c1[1] - c2[1], 0);
353
- const b = Math.max(c1[2] - c2[2], 0);
354
- return (r << 16) | (g << 8) | b;
355
- }
356
-
357
- /**
358
- * Subtraction.
359
- * 2 RGB single number that indicates (0x000000 0xFFFFFF up from) is subtracted
360
- * from the return numbers.
361
- * @ Param col1 RGB numbers show (0x000000 0xFFFFFF up from)
362
- * @ Param col2 RGB numbers show (0x000000 0xFFFFFF up from)
363
- * @ Return value subtracted Blend
364
- **/
365
- function subtract(col1, col2) {
366
- const colA = toRGB(col1);
367
- const colB = toRGB(col2);
368
- const r = Math.max(Math.max(colB[0] - (256 - colA[0]), colA[0] - (256 - colB[0])), 0);
369
- const g = Math.max(Math.max(colB[1] - (256 - colA[1]), colA[1] - (256 - colB[1])), 0);
370
- const b = Math.max(Math.max(colB[2] - (256 - colA[2]), colA[2] - (256 - colB[2])), 0);
371
- return (r << 16) | (g << 8) | b;
372
- }
373
-
374
- /**
375
- * Additive color.
376
- * 2 RGB single numbers that indicate (0x000000 0xFFFFFF up from) Return the value
377
- * of the additive mixture.
378
- * @ Param col1 RGB numbers show (0x000000 0xFFFFFF up from)
379
- * @ Param col2 RGB numbers show (0x000000 0xFFFFFF up from)
380
- * @ Return the additive color
381
- **/
382
- function sum(col1, col2) {
383
- const c1 = toRGB(col1);
384
- const c2 = toRGB(col2);
385
- const r = Math.min(c1[0] + c2[0], 255);
386
- const g = Math.min(c1[1] + c2[1], 255);
387
- const b = Math.min(c1[2] + c2[2], 255);
388
- return (r << 16) | (g << 8) | b;
389
- }
390
-
391
- function toRGBA(rgba) {
392
- const a = (rgba >> 24) & 0xff;
393
- const r = (rgba >> 16) & 0xff;
394
- const g = (rgba >> 8) & 0xff;
395
- const b = rgba & 0xff;
396
- return [r, g, b, a];
397
- }
398
-
399
- const COLOR_CODES = {
400
- TO_UNREAL: ['#ffffff', '#005912', `UNREAL <-`],
401
- TAP_LOG: ['#ffff00', '#1976d2', ' [TAPLOG]'],
402
- FROM_UNREAL: ['#ffff00', '#898989', 'UNREAL ->'],
403
- FROM_UNREAL_ERROR: ['#ffffff', '#ff0000', 'UNREAL ERROR ->'],
404
- FROM_CIRRUS: ['#ffffff', '#ef702b', 'CIRRUS ->'],
405
- FROM_CIRRUS_ERROR: ['#ffffff', '#ff0000', 'CIRRUS ->'],
406
- TO_CIRRUS: ['#ffffff', '#3c9738', 'CIRRUS <-'],
407
- };
408
-
409
- function CSV2Array(strData, strDelimiter) {
410
- // Check to see if the delimiter is defined. If not,
411
- // then default to comma.
412
- strDelimiter = strDelimiter || ',';
413
- // Create a regular expression to parse the CSV values.
414
- const objPattern = new RegExp(
415
- // Delimiters.
416
- '(\\' +
417
- strDelimiter +
418
- '|\\r?\\n|\\r|^)' +
419
- // Quoted fields.
420
- '(?:"([^"]*(?:""[^"]*)*)"|' +
421
- // Standard fields.
422
- '([^"\\' +
423
- strDelimiter +
424
- '\\r\\n]*))', 'gi');
425
- // Create an array to hold our data. Give the array
426
- // a default empty first row.
427
- const arrData = [[]];
428
- // Create an array to hold our individual pattern
429
- // matching groups.
430
- let arrMatches = null;
431
- // Keep looping over the regular expression matches
432
- // until we can no longer find a match.
433
- while ((arrMatches = objPattern.exec(strData))) {
434
- // Get the delimiter that was found.
435
- const strMatchedDelimiter = arrMatches[1];
436
- // Check to see if the given delimiter has a length
437
- // (is not the start of string) and if it matches
438
- // field delimiter. If idKey does not, then we know
439
- // that this delimiter is a row delimiter.
440
- if (strMatchedDelimiter.length && strMatchedDelimiter !== strDelimiter) {
441
- // Since we have reached a new row of data,
442
- // add an empty row to our data array.
443
- arrData.push([]);
444
- }
445
- let strMatchedValue;
446
- // Now that we have our delimiter out of the way,
447
- // let's check to see which kind of value we
448
- // captured (quoted or unquoted).
449
- if (arrMatches[2]) {
450
- // We found a quoted value. When we capture
451
- // this value, unescape any double quotes.
452
- strMatchedValue = arrMatches[2].replace(new RegExp('""', 'g'), '"');
453
- }
454
- else {
455
- // We found a non-quoted value.
456
- strMatchedValue = arrMatches[3];
457
- }
458
- // Now that we have our value string, let's add
459
- // it to the data array.
460
- arrData[arrData.length - 1].push(strMatchedValue);
461
- }
462
- // Return the parsed data.
463
- return arrData;
464
- }
465
-
466
- const booleanRegex = /^(true|false)$/i;
467
- const trueRegex = /^(true)$/i;
468
- const jsonRegex = /([\d.]+)|(\[])|(\[.+])|({.+})/i;
469
- const zipObject = (props, values) => props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {});
470
- const toHead = (input) => {
471
- return String(input).trim();
472
- };
473
- const toCorrectString = (input) => {
474
- if (typeof input === 'string') {
475
- if (input.match(jsonRegex)) {
476
- // optimization for use try-catch only after regex match. much faster than without regex
477
- try {
478
- return JSON.parse(input);
479
- }
480
- catch {
481
- /* empty */
482
- }
483
- }
484
- if (input.match(booleanRegex)) {
485
- return !!input.match(trueRegex);
486
- }
487
- return input.trim();
488
- }
489
- else if (typeof input === 'number') {
490
- return input;
491
- }
492
- };
493
- function CSV2Records(csv, useRowAsHead = 0, strDelimiter) {
494
- const arr = CSV2Array(csv, strDelimiter);
495
- const total = arr.length;
496
- const keys = arr[useRowAsHead].map(toHead);
497
- const data = [];
498
- let tmpSKU = 0;
499
- for (let i = useRowAsHead + 1; i < total; i++) {
500
- const obj = zipObject(keys, arr[i].map(toCorrectString));
501
- data.push(obj);
502
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
503
- tmpSKU++;
504
- }
505
- return data.filter(Boolean);
506
- }
507
-
508
- function ObjectToCSV(records) {
509
- if (records.length === 0) {
510
- return;
511
- }
512
- const uniqueFields = Array.from(records.reduce((fields, record) => {
513
- Object.keys(record).forEach((field) => fields.add(field));
514
- return fields;
515
- }, new Set()));
516
- const csvHeader = uniqueFields.join(',') + '\n';
517
- const csvRows = records
518
- .map((record) => uniqueFields.map((field) => `"${record[field] || ''}"`).join(','))
519
- .join('\n');
520
- return csvHeader + csvRows;
521
- }
522
-
523
- const isLocalhost = !!window.location.href.match(/localhost/gi);
524
-
525
- /**
526
- * Adds required number of symbols before input
527
- * @param input input string
528
- * @param size amount of total symbols
529
- * @param symbol filler
530
- * @returns string
531
- */
532
- function pad(input, size, symbol = '0') {
533
- let s = input + '';
534
- while (s.length < size) {
535
- s = symbol + s;
536
- }
537
- return s.slice(-size);
538
- }
539
-
540
- /**
541
- * Create a string of the form 'HOURS.MINUTES.SECONDS.MILLISECONDS'.
542
- */
543
- function timeToString() {
544
- const date = new Date();
545
- return `${pad(date.getHours(), 2)}:${pad(date.getMinutes(), 2)}:${pad(date.getSeconds(), 2)}.${pad(date.getMilliseconds(), 3)}`;
546
- }
547
- function timeUTCToString() {
548
- const date = new Date();
549
- return `${pad(date.getUTCHours(), 2)}:${pad(date.getUTCMinutes(), 2)}:${pad(date.getUTCSeconds(), 2)}.${pad(date.getUTCMilliseconds(), 3)}`;
550
- }
551
-
552
- /**
553
- * The Boolean object represents a truth value: true or false.
554
- * @param value
555
- * @constructor
556
- * Returns:boolean
557
- */
558
- const Truthy = (value) => !!value && value !== 'false' && value !== 'undefined' && value !== 'null';
559
- /**
560
- * The Boolean object represents an INVERSE truth value: true or false.
561
- * @param value
562
- * @constructor
563
- * Returns:boolean
564
- */
565
- const Falsy = (value) => !Truthy(value);
566
- /**
567
- * Checks if a value is empty.
568
- *
569
- * @param {any} value - The value to check.
570
- * @return {boolean} Returns true if the value is empty, otherwise false.
571
- */
572
- const IsEmpty = (value) => {
573
- return (value === undefined ||
574
- value === null ||
575
- (typeof value === 'object' && Object.keys(value).length === 0) ||
576
- (typeof value === 'string' && value.trim().length === 0));
577
- };
578
- const NotEmpty = (value) => {
579
- return !IsEmpty(value);
580
- };
581
- const isDefined = (arg) => arg !== null && arg !== undefined;
582
- const isNotDefined = (arg) => arg === null || arg === undefined;
583
- const isJSON = (str) => {
584
- try {
585
- JSON.parse(str);
586
- }
587
- catch (e) {
588
- console.warn(e);
589
- return false;
590
- }
591
- return true;
592
- };
593
- const isEmpty = (value) => value === undefined ||
594
- value === null ||
595
- (typeof value === 'object' && Object.keys(value).length === 0) ||
596
- (typeof value === 'string' && value.trim().length === 0);
597
- function isAllValuesTruthy(value) {
598
- return Object.values(value).every(Truthy);
599
- }
600
-
601
- const cache = {};
602
- /**
603
- * Converts a given value to a string suitable for search comparisons.
604
- * The resulting string is in lowercase, with consecutive spaces replaced by underscores.
605
- * The function uses a cache to improve performance by storing and reusing the results of previous conversions.
606
- *
607
- * @param {any} value - The value to be converted to a search-friendly string.
608
- * It can be of any type, but it will be coerced to a string if not already one.
609
- *
610
- * @param {boolean} caseSensitive - A flag indicating whether the comparison should be case-sensitive.
611
- * If set to true, the function will perform case-sensitive comparisons, preserving the original casing of input strings.
612
- * If set to false (default), the function will convert the input strings to lowercase for case-insensitive comparisons
613
- *
614
- * @returns {string} The processed string, which is trimmed, converted to lowercase (unless caseSensitive is true),
615
- * and has all sequences of spaces replaced with underscores. This string is either
616
- * retrieved from the cache or freshly computed and then cached.
617
- *
618
- */
619
- function textForSearch(value, caseSensitive = false) {
620
- const key = `${value}_${caseSensitive}`;
621
- return (cache[key] ||
622
- (() => {
623
- let result = String(value).trim().replace(/ +/gi, '_');
624
- if (!caseSensitive) {
625
- result = result.toLowerCase();
626
- }
627
- cache[key] = result;
628
- return result;
629
- })());
630
- }
631
-
632
- /**
633
- * Creates a predicate function to filter records from a collection based on specified criteria.
634
- *
635
- * The `where` function accepts a criteria object with key-value pairs, indicating the fields
636
- * and their expected values for filtering. It returns a predicate function that filters a collection
637
- * of records. This predicate checks if records match the criteria using a case-insensitive comparison,
638
- * making it particularly useful in conjunction with the `textForSearch` function, which standardizes
639
- * strings for such comparisons.
640
- *
641
- * Each criterion value is first processed with `textForSearch` to normalize spacing and case,
642
- * ensuring consistent and predictable filtering. The comparison between each record's field value
643
- * and the criterion value is thus case-insensitive and ignores extra spaces.
644
- *
645
- * @param {Partial<Record<K, T[K]>>} criteria - An object representing the filtering criteria.
646
- * Keys correspond to the record's fields to be filtered, and values are the expected values for those fields,
647
- * processed in a case-insensitive manner. Undefined values are ignored.
648
- *
649
- * @param {boolean} caseSensitive - A flag indicating whether the comparison should be case-sensitive.
650
- * If set to true, the function will perform case-sensitive comparisons, preserving the original casing of input strings.
651
- * If set to false (default), the function will convert the input strings to lowercase for case-insensitive comparisons
652
- *
653
- * @returns {(record: T) => boolean} A predicate function that takes a record of type `T`
654
- * and returns `true` if the record's field values match all criteria, otherwise `false`.
655
- *
656
- * @example
657
- * // Define a collection of items
658
- * const items = [
659
- * { name: "Apple", category: "Fruit" },
660
- * { name: "Carrot", category: "Vegetable" },
661
- * { name: "Banana", category: "Fruit" }
662
- * ];
663
- *
664
- * // Create a predicate to find fruits, using a case-insensitive comparison
665
- * const isFruit = where({ category: "fruit" }); // 'fruit' will match 'Fruit' in items
666
- *
667
- * // Filter the collection with the predicate
668
- * const fruits = items.filter(isFruit);
669
- * // Output: [{ name: "Apple", category: "Fruit" }, { name: "Banana", category: "Fruit" }]
670
- *
671
- * @typeparam T - Specifies the type of records in the collection to be filtered. It extends `object`,
672
- * ensuring the function is only used with object types. This generic approach allows for flexible usage
673
- * with various record structures.
674
- */
675
- function where(criteria, caseSensitive = false) {
676
- const preComputedEntries = Object.entries(criteria)
677
- .filter(([, value]) => value !== undefined)
678
- .map(([key, value]) => [key, textForSearch(value, caseSensitive)]);
679
- return (record) => {
680
- return (preComputedEntries.length > 0 &&
681
- preComputedEntries.every(([key, criterionValue]) => {
682
- return (textForSearch(record[key] ?? '', caseSensitive) ===
683
- criterionValue);
684
- }));
685
- };
686
- }
687
- function whereNot(criteria, caseSensitive = false) {
688
- const whereFunc = where(criteria, caseSensitive);
689
- return (record) => {
690
- return !whereFunc(record);
691
- };
692
- }
693
-
694
- class Logger {
695
- static { this.isDevMode = Truthy(localStorage.getItem('devMode')); }
696
- static colored(color, background, ...args) {
697
- if (!Logger.isDevMode) {
698
- return;
699
- }
700
- const [first, ...rest] = args;
701
- console.log.apply(console, [
702
- `%c ${timeUTCToString()} ${first} `,
703
- `color: ${color}; background: ${background};`,
704
- ...rest,
705
- ]);
706
- }
707
- static log(...args) {
708
- if (!Logger.isDevMode) {
709
- return;
710
- }
711
- console.log.apply(console, [
712
- `%c ${timeUTCToString()} [ LOG ] `,
713
- 'color: black; background: #80ff80;',
714
- ...args,
715
- ]);
716
- }
717
- static warn(...args) {
718
- if (!Logger.isDevMode) {
719
- return;
720
- }
721
- console.warn.apply(console, [
722
- `%c ${timeUTCToString()} WARN `,
723
- 'color: black; background: #ffd500;',
724
- ...args,
725
- ]);
726
- }
727
- static info(...args) {
728
- if (!Logger.isDevMode) {
729
- return;
730
- }
731
- console.log.apply(console, [
732
- `%c ${timeUTCToString()} [ INFO ] `,
733
- 'color: white; background: blue;',
734
- ...args,
735
- ]);
736
- }
737
- static error(...args) {
738
- if (!Logger.isDevMode) {
739
- return;
740
- }
741
- console.error.apply(console, [
742
- `%c ${timeUTCToString()} ERROR `,
743
- 'color: white; background: red;',
744
- ...args,
745
- ]);
746
- }
747
- static table(...args) {
748
- if (!Logger.isDevMode) {
749
- return;
750
- }
751
- // eslint-disable-next-line no-console
752
- console.table.apply(console, [args]);
753
- }
754
- static time(...args) {
755
- if (!Logger.isDevMode) {
756
- return;
757
- }
758
- // eslint-disable-next-line no-console,prefer-spread
759
- console.time.apply(console, args);
760
- }
761
- static timeEnd(...args) {
762
- if (!Logger.isDevMode) {
763
- return;
764
- }
765
- // eslint-disable-next-line no-console,prefer-spread
766
- console.timeEnd.apply(console, args);
767
- }
768
- }
769
-
770
- function cleanupFileName(value) {
771
- if (!value) {
772
- return value;
773
- }
774
- value = value
775
- .toString()
776
- .replace(/undefined/g, '')
777
- .trim()
778
- .replace(/\//g, '-')
779
- .replace(/[-]+/g, '-')
780
- .replace(/[^\w^.-]+/gi, '_')
781
- .replace(/[\^]+/gi, '_');
782
- value = value.split('_').filter(Boolean).join('_').toLowerCase();
783
- return value;
784
- }
785
-
786
- function makePath(...value) {
787
- return [...value].map((el) => cleanupFileName(el)).join('/');
788
- }
789
-
790
- function normalizePath(value) {
791
- const re = new RegExp('[/\\\\]+', 'g');
792
- return value
793
- .split(re)
794
- .map((el) => cleanupFileName(el))
795
- .join('/');
796
- }
797
-
798
- function expandOverRectangle(objectRect, areaRect) {
799
- const ratio = objectRect.w / objectRect.h;
800
- const result = { x: 0, y: 0, w: 0, h: 0, scale: 1 };
801
- if (areaRect.w / ratio < areaRect.h) {
802
- result.w = areaRect.h * ratio;
803
- result.h = areaRect.h;
804
- }
805
- else {
806
- result.w = areaRect.w;
807
- result.h = areaRect.w / ratio;
808
- }
809
- result.x = areaRect.x + (areaRect.w - result.w) / 2;
810
- result.y = areaRect.y + (areaRect.h - result.h) / 2;
811
- result.scale = result.w / objectRect.w;
812
- return result;
813
- }
814
-
815
- function fitIntoRectangle(objectRect, areaRect, round = true, fixedRatio = null) {
816
- const result = { x: 0, y: 0, w: 0, h: 0, scale: 1 };
817
- const ratio = objectRect.h / objectRect.w;
818
- if (objectRect.h > objectRect.w) {
819
- result.h = areaRect.h;
820
- result.w = areaRect.h / ratio;
821
- if (result.w > areaRect.w) {
822
- result.w = areaRect.w;
823
- result.h = areaRect.w * ratio;
824
- }
825
- }
826
- else {
827
- result.w = areaRect.w;
828
- result.h = areaRect.w * ratio;
829
- if (result.h > areaRect.h) {
830
- result.h = areaRect.h;
831
- result.w = areaRect.h / ratio;
832
- }
833
- }
834
- if (fixedRatio) {
835
- result.w = objectRect.w * fixedRatio;
836
- result.h = objectRect.h * fixedRatio;
837
- }
838
- const wOut = round ? Math.floor(result.w) : result.w;
839
- const hOut = round ? Math.floor(result.h) : result.h;
840
- return {
841
- x: areaRect.x + (areaRect.w - wOut) / 2,
842
- y: areaRect.y + (areaRect.h - hOut) / 2,
843
- w: wOut,
844
- h: hOut,
845
- scale: wOut / objectRect.w,
846
- };
847
- }
848
-
849
- const canvasCacheObj = {};
850
- function getCanvasCached(id) {
851
- if (!canvasCacheObj[id]) {
852
- const canvas = document.createElement('canvas');
853
- canvasCacheObj[id] = {
854
- canvas,
855
- ctx: canvas.getContext('2d'),
856
- };
857
- }
858
- return canvasCacheObj[id];
859
- }
860
-
861
- function getSnapshot2(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
862
- const drawableImage = imageElement;
863
- const canvasHelper = document.createElement('canvas');
864
- const drawCTX = canvasHelper.getContext('2d');
865
- const prop = fitIntoRectangle({
866
- x: 0,
867
- y: 0,
868
- w: drawableImage.naturalWidth || drawableImage.width,
869
- h: drawableImage.naturalHeight || drawableImage.height,
870
- }, {
871
- x: 0,
872
- y: 0,
873
- w: maxWidth,
874
- h: drawableImage.naturalHeight || drawableImage.height,
875
- });
876
- const width = prop.w;
877
- const height = prop.h;
878
- canvasHelper.width = width;
879
- canvasHelper.height = height;
880
- drawCTX.save();
881
- drawCTX.clearRect(0, 0, width, height);
882
- drawCTX.drawImage(drawableImage, 0, 0, width, height);
883
- drawCTX.restore();
884
- if (output === 'canvas') {
885
- return canvasHelper;
886
- }
887
- return canvasHelper.toDataURL(output, quality);
888
- }
889
- function getSnapshot(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
890
- const drawableImage = imageElement;
891
- const canvasHelper = document.createElement('canvas');
892
- const drawCTX = canvasHelper.getContext('2d');
893
- const prop = fitIntoRectangle({
894
- x: 0,
895
- y: 0,
896
- w: drawableImage.naturalWidth || drawableImage.width,
897
- h: drawableImage.naturalHeight || drawableImage.height,
898
- }, {
899
- x: 0,
900
- y: 0,
901
- w: (drawableImage.naturalWidth || drawableImage.width) / 2,
902
- h: drawableImage.naturalHeight || drawableImage.height,
903
- });
904
- const width = prop.w;
905
- const height = prop.h;
906
- canvasHelper.width = width;
907
- canvasHelper.height = height;
908
- drawCTX.save();
909
- drawCTX.clearRect(0, 0, width, height);
910
- drawCTX.drawImage(drawableImage, 0, 0, width, height);
911
- drawCTX.restore();
912
- if (width > maxWidth * 2) {
913
- return getSnapshot(canvasHelper, maxWidth, output, quality);
914
- }
915
- return getSnapshot2(drawableImage, maxWidth, output, quality);
916
- }
917
-
918
- function loadImage(url) {
919
- return new Promise((resolve, reject) => {
920
- const img = new Image();
921
- img.crossOrigin = 'anonymous';
922
- img.onload = () => {
923
- setTimeout(() => resolve(img), 1);
924
- };
925
- img.onerror = () => {
926
- setTimeout(() => reject(null), 1);
927
- };
928
- img.src = url;
929
- });
930
- }
931
-
932
- /**
933
- * USE DownloadImage instead!
934
- * @deprecated use DownloadImage instead!
935
- * @param imageSource
936
- * @param name
937
- * @param width
938
- * @param format
939
- */
940
- function SaveImage(imageSource, name, width, format) {
941
- let out;
942
- const image = imageSource;
943
- if (typeof image !== 'string') {
944
- out = getSnapshot(image, width, format);
945
- }
946
- else {
947
- out = image;
948
- }
949
- if (navigator.msSaveBlob) {
950
- // IE10+
951
- try {
952
- const blob = image.msToBlob();
953
- return navigator.msSaveBlob(blob, name);
954
- }
955
- catch (e) {
956
- console.warn(e);
957
- }
958
- }
959
- else {
960
- const uri = out;
961
- const link = document.createElement('a');
962
- link.download = name;
963
- link.href = uri;
964
- document.body.appendChild(link);
965
- if (link.click) {
966
- link.click();
967
- }
968
- else {
969
- const event = document.createEvent('MouseEvents');
970
- event.initMouseEvent('click', true, true, window);
971
- link.dispatchEvent(event);
972
- }
973
- document.body.removeChild(link);
974
- }
975
- }
976
- /**
977
- * @param imageSource
978
- * @param string name
979
- * @param number width
980
- * @param string format
981
- */
982
- const DownloadImage = SaveImage;
983
-
984
- class BatchLoader {
985
- constructor() {
986
- this.maximumSlotsNumber = 1;
987
- this.queue = [];
988
- this.slots = [];
989
- }
990
- clear() {
991
- this.queue.forEach((item) => {
992
- try {
993
- if (item.img) {
994
- item.img.src = '';
995
- }
996
- }
997
- catch (e) {
998
- console.warn(e);
999
- }
1000
- try {
1001
- item.xhr?.abort();
1002
- }
1003
- catch (e) {
1004
- console.warn(e);
1005
- }
1006
- });
1007
- this.slots.forEach((item) => {
1008
- try {
1009
- if (item.img) {
1010
- item.img.src = '';
1011
- }
1012
- }
1013
- catch (e) {
1014
- console.warn(e);
1015
- }
1016
- try {
1017
- item.xhr?.abort();
1018
- }
1019
- catch (e) {
1020
- console.warn(e);
1021
- }
1022
- });
1023
- this.slots.length = 0;
1024
- this.queue.length = 0;
1025
- }
1026
- /**
1027
- * new settings
1028
- * you must pass new settings
1029
- * @param sett
1030
- */
1031
- setSettings(sett) {
1032
- this.maximumSlotsNumber =
1033
- sett.maximumSlotsNumber !== undefined
1034
- ? sett.maximumSlotsNumber
1035
- : this.maximumSlotsNumber;
1036
- }
1037
- /**
1038
- * execute with a chosen file
1039
- * @param id
1040
- * @param func
1041
- */
1042
- withItem(id, func) {
1043
- let item = this.getById(id);
1044
- if (!item) {
1045
- return false;
1046
- }
1047
- item = func(item);
1048
- this.queue.sort(this.sortByOrder);
1049
- return true;
1050
- }
1051
- remove(id) {
1052
- this.queue = this.queue.filter((arg) => arg.id !== id);
1053
- return this.queue;
1054
- }
1055
- /**
1056
- * executes when all files are downloaded
1057
- * @param cb
1058
- */
1059
- whenDone(cb) {
1060
- this._whenDone = cb;
1061
- }
1062
- // order {number} lower will execute first, default *100*
1063
- load(args) {
1064
- const out = args
1065
- .filter((arg) => !!arg.path)
1066
- .map((arg) => ({
1067
- path: arg.path,
1068
- id: this.add(arg),
1069
- }));
1070
- this.queue.sort(this.sortByOrder);
1071
- this.checkSlots();
1072
- return out;
1073
- }
1074
- /**
1075
- * operates with one file
1076
- * @param item
1077
- * @private
1078
- */
1079
- add(item) {
1080
- // eslint-disable-next-line @typescript-eslint/no-this-alias
1081
- const that = this;
1082
- const temp = {
1083
- id: item.id,
1084
- resolutionId: null,
1085
- useXhr: item.useXhr,
1086
- order: item.order !== undefined ? item.order : 100,
1087
- fallBack: item.fallBack,
1088
- path: item.path,
1089
- onLoadEnd: item.onLoadEnd,
1090
- onProgress: item.onProgress,
1091
- onLoadStart: item.onLoadStart,
1092
- extra: item.extra,
1093
- };
1094
- let retryCount = 1;
1095
- if (temp.useXhr) {
1096
- temp.xhr = this.getXmlHttp();
1097
- temp.xhr.onloadstart = (data) => item.onLoadStart(data);
1098
- temp.xhr.onprogress = (data) => item.onProgress(data);
1099
- temp.xhr.onreadystatechange = async function (data) {
1100
- if (this.readyState === 1 && this.status === 0) {
1101
- return;
1102
- }
1103
- if (this.readyState === 4 &&
1104
- (this.status === 404 || this.status === 0)) {
1105
- temp.error = true;
1106
- that.loadEnd(temp);
1107
- return;
1108
- }
1109
- if (this.readyState === 4 && this.status === 200) {
1110
- const urlCreator = window.URL;
1111
- const imageUrl = urlCreator.createObjectURL(data.target.response);
1112
- temp.img = await loadImage(imageUrl);
1113
- that.loadEnd(temp);
1114
- return;
1115
- }
1116
- };
1117
- }
1118
- else {
1119
- temp.img = new Image();
1120
- temp.img.crossOrigin = 'anonymous';
1121
- temp.img.onload = () => {
1122
- that.loadEnd(temp);
1123
- };
1124
- temp.img.onerror = () => {
1125
- if (temp.fallBack && retryCount-- > 0) {
1126
- console.warn('Fallback used =>', temp.path, '=>', temp.fallBack);
1127
- if (temp.img) {
1128
- temp.img.onload = null;
1129
- temp.img.src = temp.fallBack;
1130
- }
1131
- that.loadEnd(temp);
1132
- }
1133
- else {
1134
- temp.error = true;
1135
- that.loadEnd(temp);
1136
- }
1137
- };
1138
- }
1139
- this.queue.push(temp);
1140
- return temp.id;
1141
- }
1142
- sortByOrder(a, b) {
1143
- return a.order > b.order ? 1 : a.order < b.order ? -1 : 0;
1144
- }
1145
- loadEnd(item) {
1146
- if (item.onLoadEnd !== undefined) {
1147
- for (let i = 0, len = this.slots.length; i < len; i += 1) {
1148
- if (this.slots[i].id === item.id) {
1149
- this.slots.splice(i, 1);
1150
- break;
1151
- }
1152
- }
1153
- item.onLoadEnd(item);
1154
- }
1155
- this.checkSlots();
1156
- }
1157
- checkSlots() {
1158
- while ((this.slots.length < this.maximumSlotsNumber ||
1159
- this.maximumSlotsNumber === -1) &&
1160
- this.queue.length) {
1161
- this.slots.push(this.queue.shift());
1162
- const slot = this.slots[this.slots.length - 1];
1163
- if (slot.useXhr) {
1164
- slot.xhr?.open('GET', slot.path, true);
1165
- slot.xhr?.send(null);
1166
- }
1167
- else {
1168
- if (slot.img) {
1169
- slot.img.src = slot.path;
1170
- }
1171
- }
1172
- }
1173
- if (this.slots.length === 0 &&
1174
- this.queue.length === 0 &&
1175
- this._whenDone !== undefined) {
1176
- this._whenDone();
1177
- }
1178
- }
1179
- /**
1180
- * get Item By id for interaction with files in this.queue
1181
- * @param id
1182
- * @private
1183
- */
1184
- getById(id) {
1185
- for (let i = 0, len = this.queue.length; i < len; i += 1) {
1186
- if (this.queue[i].id === id) {
1187
- return this.queue[i];
1188
- }
1189
- }
1190
- return null;
1191
- }
1192
- getXmlHttp() {
1193
- let xhr = null;
1194
- try {
1195
- xhr = new XMLHttpRequest();
1196
- xhr.responseType = 'blob';
1197
- }
1198
- catch (e) {
1199
- console.warn(e);
1200
- }
1201
- return xhr;
1202
- }
1203
- }
1204
-
1205
- const debounce = (fn, ms = 300) => {
1206
- let timeoutId;
1207
- return function (...args) {
1208
- clearTimeout(timeoutId);
1209
- timeoutId = setTimeout(() => fn.apply(this, args), ms);
1210
- };
1211
- };
1212
-
1213
- const KeyboardNumericCode = {
1214
- Backspace: 8,
1215
- Tab: 9,
1216
- Numpad5: 12,
1217
- NumpadEnter: 13,
1218
- ShiftRight: 16,
1219
- ControlRight: 17,
1220
- ControlLeft: 17,
1221
- AltRight: 18,
1222
- Escape: 27,
1223
- Space: 32,
1224
- Numpad9: 33,
1225
- Numpad3: 34,
1226
- Numpad1: 35,
1227
- Numpad7: 36,
1228
- Numpad4: 37,
1229
- Numpad8: 38,
1230
- Numpad6: 39,
1231
- Numpad2: 40,
1232
- Numpad0: 45,
1233
- NumpadDecimal: 46,
1234
- Digit0: 48,
1235
- Digit1: 49,
1236
- Digit2: 50,
1237
- Digit3: 51,
1238
- Digit4: 52,
1239
- Digit5: 53,
1240
- Digit6: 54,
1241
- Digit7: 55,
1242
- Digit8: 56,
1243
- Digit9: 57,
1244
- KeyA: 65,
1245
- KeyB: 66,
1246
- KeyC: 67,
1247
- KeyD: 68,
1248
- KeyE: 69,
1249
- KeyF: 70,
1250
- KeyG: 71,
1251
- KeyH: 72,
1252
- KeyI: 73,
1253
- KeyJ: 74,
1254
- KeyK: 75,
1255
- KeyL: 76,
1256
- KeyM: 77,
1257
- KeyN: 78,
1258
- KeyO: 79,
1259
- KeyP: 80,
1260
- KeyQ: 81,
1261
- KeyR: 82,
1262
- KeyS: 83,
1263
- KeyT: 84,
1264
- KeyU: 85,
1265
- KeyV: 86,
1266
- KeyW: 87,
1267
- KeyX: 88,
1268
- KeyY: 89,
1269
- KeyZ: 90,
1270
- MetaLeft: 91,
1271
- ContextMenu: 93,
1272
- NumpadMultiply: 106,
1273
- NumpadAdd: 107,
1274
- NumpadSubtract: 109,
1275
- NumpadDivide: 111,
1276
- F1: 112,
1277
- F2: 113,
1278
- F3: 114,
1279
- F4: 115,
1280
- F5: 116,
1281
- F6: 117,
1282
- F7: 118,
1283
- F8: 119,
1284
- F9: 120,
1285
- F10: 121,
1286
- F11: 122,
1287
- F12: 123,
1288
- NumLock: 144,
1289
- ScrollLock: 145,
1290
- Semicolon: 186,
1291
- Equal: 187,
1292
- Comma: 188,
1293
- Minus: 189,
1294
- Period: 190,
1295
- Slash: 191,
1296
- Backquote: 192,
1297
- BracketLeft: 219,
1298
- Backslash: 220,
1299
- BracketRight: 221,
1300
- Quote: 222,
1301
- IntlBackslash: 226,
1302
- ArrowUp: 38,
1303
- ArrowDown: 40,
1304
- ArrowLeft: 37,
1305
- ArrowRight: 39,
1306
- };
1307
- const InvertedKeyMapValues = {};
1308
- //For use for InvertedKeyMap[32] will return 'Space' and so on
1309
- const InvertedKeyMap = InvertedKeyMapValues;
1310
- const KeyboardStringCode = {};
1311
- Object.entries(KeyboardNumericCode).forEach(
1312
- // @ts-expect-error @typescript-eslint/ban-ts-comment
1313
- ([key, value]) => {
1314
- InvertedKeyMapValues[value] = key;
1315
- // @ts-expect-error @typescript-eslint/ban-ts-comment
1316
- KeyboardStringCode[key] = key;
1317
- });
1318
-
1319
- function serialize(obj) {
1320
- const str = [];
1321
- for (const p in obj) {
1322
- if (Object.prototype.hasOwnProperty.call(obj, p)) {
1323
- str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
1324
- }
1325
- }
1326
- return str.join('&');
1327
- }
1328
-
1329
- const saveToLocalDrive = (uri, name) => {
1330
- if (!uri) {
1331
- return;
1332
- }
1333
- if (navigator.msSaveBlob) {
1334
- // IE10+
1335
- try {
1336
- return navigator.msSaveBlob(uri, name);
1337
- }
1338
- catch (e) {
1339
- console.warn(e);
1340
- }
1341
- }
1342
- else {
1343
- const link = document.createElement('a');
1344
- link.target = '_blank';
1345
- link.href = uri;
1346
- link.download = name;
1347
- document.body.appendChild(link);
1348
- if (link.click) {
1349
- link.click();
1350
- }
1351
- else {
1352
- const event = document.createEvent('MouseEvents');
1353
- event.initMouseEvent('click', true, true, window);
1354
- link.dispatchEvent(event);
1355
- }
1356
- document.body.removeChild(link);
1357
- }
1358
- };
1359
-
1360
- function sleep(time) {
1361
- return new Promise((r) => setTimeout(r, time));
1362
- }
1363
-
1364
- function trimLastSlashFromUrl(baseUrl) {
1365
- if (!baseUrl) {
1366
- return null;
1367
- }
1368
- else if (baseUrl[baseUrl.length - 1] === '/') {
1369
- return baseUrl.substring(0, baseUrl.length - 1);
1370
- }
1371
- return;
1372
- }
1373
-
1374
- /**
1375
- * SingleTone Private class.
1376
- * Event-Driving pattern for sending signals from component to component.
1377
- */
1378
- class SignalClass {
1379
- constructor() {
1380
- if (SignalClass.eventBus) {
1381
- throw new Error(`Check that 'SignalClass' is not instantiated again!`);
1382
- }
1383
- SignalClass.eventBus = new Subject();
1384
- }
1385
- /**
1386
- * It is not recommended to use this class directly.
1387
- * use the sendSignal functions instead.
1388
- * those wrappers are more convenient and provide a better type safety.
1389
- */
1390
- broadcast(key, data) {
1391
- SignalClass.eventBus.next({ key, data });
1392
- }
1393
- /**
1394
- * It is not recommended to use this class directly.
1395
- * use the fromSignal functions instead.
1396
- * those wrappers are more convenient and provide a better type safety.
1397
- */
1398
- on(key) {
1399
- return SignalClass.eventBus.asObservable().pipe(filter((event) => event.key === key), map((event) => event.data));
1400
- }
1401
- }
1402
- const Signal = new SignalClass();
1403
-
1404
- function generateUuid() {
1405
- return v4();
1406
- }
1407
-
1408
- const ImageOutput = {
1409
- CANVAS: 'canvas',
1410
- PNG: 'image/png',
1411
- WEBP: 'image/webp',
1412
- JPG: 'image/jpeg',
1413
- };
1414
-
1415
- /**
1416
- * Calculates the index at which the `value` should be inserted into the `array` to maintain its
1417
- * sorted order. This function performs a binary search with a complexity of O(log n), making it
1418
- * efficient for large datasets. It assumes that the input array is sorted in ascending order and
1419
- * contains comparable elements.
1420
- *
1421
- * Note: The function is designed to handle arrays with lengths up to a maximum of `HALF_MAX_ARRAY_LENGTH`
1422
- * to ensure the search operation remains within JavaScript's maximum array index limit.
1423
- *
1424
- * @param {any[]} array The sorted array into which the value should be inserted. The array elements
1425
- * should be comparable with the `value` using less-than and greater-than operations.
1426
- * @param {number} value The value to insert into the array. This function assumes that `array` is sorted
1427
- * in ascending order and will find the correct position for `value` accordingly.
1428
- * @returns {number} The index at which the `value` should be inserted into `array` to maintain its sorted order.
1429
- * If the `array` is empty or if `value` is less than or equal to all elements in `array`,
1430
- * returns 0. If `value` is greater than all elements in `array`, returns the length of `array`.
1431
- * @example
1432
- * // returns 2
1433
- * baseSortedIndex([1, 3, 4], 3);
1434
- *
1435
- * @example
1436
- * // returns 1
1437
- * baseSortedIndex([1, 2, 3], 2);
1438
- */
1439
- function baseSortedIndex(array, value) {
1440
- const MAX_ARRAY_LENGTH = 4294967295;
1441
- const HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
1442
- let low = 0;
1443
- let high = array?.length || low;
1444
- if (high <= HALF_MAX_ARRAY_LENGTH) {
1445
- while (low < high) {
1446
- const mid = (low + high) >>> 1;
1447
- const computed = array[mid];
1448
- if (computed !== null && computed < value) {
1449
- low = mid + 1;
1450
- }
1451
- else {
1452
- high = mid;
1453
- }
1454
- }
1455
- }
1456
- return high;
1457
- }
1458
-
1459
- /**
1460
- * Calculates the median of an array of numbers.
1461
- *
1462
- * The median is the middle value of a sorted list of numbers. If the list has an even number
1463
- * of elements, the median is the average of the two middle numbers.
1464
- *
1465
- * @param numbers - An array of numbers for which the median will be calculated.
1466
- * @returns The median value as a number, or `null` if the array is empty.
1467
- *
1468
- * @example
1469
- * ```typescript
1470
- * const numbers = [3, 1, 4, 2];
1471
- * const median = calculateMedian(numbers);
1472
- * console.log(median); // Output: 2.5
1473
- * ```
1474
- */
1475
- function calculateMedian(numbers) {
1476
- if (numbers.length === 0)
1477
- return 0;
1478
- // Sort the array in ascending order
1479
- const sorted = [...numbers].sort((a, b) => a - b);
1480
- const length = sorted.length;
1481
- const middle = Math.floor(length / 2);
1482
- // If the length is even, return the average of the two middle numbers
1483
- if (length % 2 === 0) {
1484
- return (sorted[middle - 1] + sorted[middle]) / 2;
1485
- }
1486
- // If the length is odd, return the middle number
1487
- return sorted[middle];
1488
- }
1489
-
1490
- /**
1491
- * Clamps value between min and max;
1492
- * @param min minValue
1493
- * @param max maxValue
1494
- * @param value inputValue
1495
- * @returns number
1496
- */
1497
- function clampf(min, max, value) {
1498
- if (min > max) {
1499
- return min;
1500
- }
1501
- return Math.min(max, Math.max(min, value));
1502
- }
1503
-
1504
- /**
1505
- * Computes a circular index within a given range.
1506
- *
1507
- * This function ensures that the index wraps around within the range of 0 to `totalItems - 1`.
1508
- * It uses the `clampf` function to clamp the result within the valid range.
1509
- *
1510
- * @param index - The current index to be wrapped.
1511
- * @param totalItems - The total number of items in the range.
1512
- * @returns The wrapped index within the range of 0 to `totalItems - 1`.
1513
- *
1514
- * @example
1515
- * ```typescript
1516
- * import { circularIndex } from './circularIndex';
1517
- *
1518
- * // Example 1: Basic usage
1519
- * const index1 = circularIndex(5, 5);
1520
- * console.log(index1); // Output: 0
1521
- *
1522
- * // Example 2: Index greater than totalItems
1523
- * const index2 = circularIndex(6, 5);
1524
- * console.log(index2); // Output: 1
1525
- *
1526
- * // Example 3: Negative index
1527
- * const index3 = circularIndex(-2, 5);
1528
- * console.log(index3); // Output: 3
1529
- *
1530
- * // Example 4: Large Negative index
1531
- * const index4 = circularIndex(-6, 5);
1532
- * console.log(index4); // Output: 4
1533
- *
1534
- * // Example 5: Index equal to totalItems
1535
- * const index5 = circularIndex(1, 1);
1536
- * console.log(index5); // Output: 0
1537
- */
1538
- function circularIndex(index, totalItems) {
1539
- return clampf(0, totalItems - 1, (totalItems * 2 + index) % totalItems);
1540
- }
1541
-
1542
- function degreesToRadians(degrees) {
1543
- return degrees * (Math.PI / 180);
1544
- }
1545
- function radiansToDegrees(radians) {
1546
- return radians * (180 / Math.PI);
1547
- }
1548
-
1549
- /**
1550
- * A small epsilon value used for floating-point comparisons.
1551
- *
1552
- * @remarks
1553
- * The value of `EPSILON` is `0.01`. This can be overridden in the comparison functions if needed.
1554
- */
1555
- const EPSILON = 0.01;
1556
- /**
1557
- * Checks if floating-point number `A` is less than `B` considering a small margin of error.
1558
- *
1559
- * @param A - The first floating-point number to compare.
1560
- * @param B - The second floating-point number to compare.
1561
- * @param Epsilon - Optional custom epsilon value for comparison. Defaults to `EPSILON` if not provided.
1562
- * @returns `true` if `A` is less than `B` considering the epsilon margin, otherwise `false`.
1563
- *
1564
- * @example
1565
- * ```
1566
- * const result = fpIsALessThanB(0.0034, 0.0066); // true
1567
- * ```
1568
- */
1569
- function fpIsALessThanB(A, B, Epsilon) {
1570
- Epsilon = Epsilon || EPSILON;
1571
- return A - B < Epsilon && Math.abs(A - B) > Epsilon;
1572
- }
1573
- /**
1574
- * Checks if floating-point number `A` is greater than `B` considering a small margin of error.
1575
- *
1576
- * @param A - The first floating-point number to compare.
1577
- * @param B - The second floating-point number to compare.
1578
- * @param Epsilon - Optional custom epsilon value for comparison. Defaults to `EPSILON` if not provided.
1579
- * @returns `true` if `A` is greater than `B` considering the epsilon margin, otherwise `false`.
1580
- *
1581
- * @example
1582
- * ```
1583
- * const result = fpIsAGreaterThanB(0.0066, 0.0034); // true
1584
- * ```
1585
- */
1586
- function fpIsAGreaterThanB(A, B, Epsilon) {
1587
- Epsilon = Epsilon || EPSILON;
1588
- return A - B > Epsilon && Math.abs(A - B) > Epsilon;
1589
- }
1590
- /**
1591
- * Checks if floating-point number `A` is approximately the same as `B` considering a small margin of error.
1592
- *
1593
- * @param A - The first floating-point number to compare.
1594
- * @param B - The second floating-point number to compare.
1595
- * @param Epsilon - Optional custom epsilon value for comparison. Defaults to `EPSILON` if not provided.
1596
- * @returns `true` if `A` is approximately equal to `B` considering the epsilon margin, otherwise `false`.
1597
- *
1598
- * @example
1599
- * ```
1600
- * const result = fpIsASameAsB(0.005, 0.0051); // true
1601
- * ```
1602
- */
1603
- function fpIsASameAsB(A, B, Epsilon) {
1604
- Epsilon = Epsilon || EPSILON;
1605
- return Math.abs(A - B) < Epsilon;
1606
- }
1607
-
1608
- /**
1609
- * Performs an inverse linear interpolation.
1610
- *
1611
- * Given a range defined by `min` and `max`, this function calculates the
1612
- * interpolation factor (or percentage) of `value` within that range. Optionally,
1613
- * it can clamp the result to be between 0 and 1 to ensure the return value is
1614
- * within the range of a standard lerp operation.
1615
- *
1616
- * @param {number} min - The minimum value of the interpolation range.
1617
- * @param {number} max - The maximum value of the interpolation range.
1618
- * @param {number} value - The value to interpolate.
1619
- * @param {boolean} [clampToNormal=false] - Whether to clamp the result between 0 and 1.
1620
- * @returns {number} The interpolation factor of `value` between `min` and `max`.
1621
- * If `clampToNormal` is true, the result is clamped between 0 and 1.
1622
- * If the difference between `min` and `max` is 0, returns 1 to avoid division by zero.
1623
- */
1624
- function inverseLerp(min, max, value, clampToNormal = false) {
1625
- if (clampToNormal) {
1626
- value = Math.min(max, value);
1627
- value = Math.max(min, value);
1628
- }
1629
- const difference = max - min;
1630
- // Avoid JS division error
1631
- if (difference === 0) {
1632
- return 1;
1633
- }
1634
- const result = (value - min) / difference;
1635
- if (clampToNormal) {
1636
- return Math.min(1, Math.max(0, result));
1637
- }
1638
- return result;
1639
- }
1640
-
1641
- /**
1642
- * @param min minimums
1643
- * @param max maximums
1644
- * @param value current float value in 0-1 range
1645
- * @returns clamped value
1646
- */
1647
- function lerp(min, max, value) {
1648
- value = clampf(0, 1, value);
1649
- return value * (max - min) + min;
1650
- }
1651
-
1652
- /**
1653
- * A Mutex class to handle mutual exclusion locks, ensuring that only one asynchronous task can execute a critical section at a time.
1654
- *
1655
- * @example
1656
- * const mutex = new Mutex();
1657
- *
1658
- * async function task(name: string, duration: number) {
1659
- * console.log(`${name} waiting to acquire mutex`);
1660
- * const release = await mutex.acquire();
1661
- * console.log(`${name} acquired mutex`);
1662
- * await new Promise(resolve => setTimeout(resolve, duration));
1663
- * console.log(`${name} releasing mutex`);
1664
- * release();
1665
- * }
1666
- *
1667
- * task('Task 1', 1000);
1668
- * task('Task 2', 2000);
1669
- * task('Task 3', 1500);
1670
- * task('Task 4', 500);
1671
- *
1672
- * Outputs
1673
- * [LOG]: "Task 1 waiting to acquire mutex"
1674
- * [LOG]: "Task 2 waiting to acquire mutex"
1675
- * [LOG]: "Task 3 waiting to acquire mutex"
1676
- * [LOG]: "Task 4 waiting to acquire mutex"
1677
- * [LOG]: "Task 1 acquired mutex"
1678
- * [LOG]: "Task 1 releasing mutex"
1679
- * [LOG]: "Task 2 acquired mutex"
1680
- * [LOG]: "Task 2 releasing mutex"
1681
- * [LOG]: "Task 3 acquired mutex"
1682
- * [LOG]: "Task 3 releasing mutex"
1683
- * [LOG]: "Task 4 acquired mutex"
1684
- * [LOG]: "Task 4 releasing mutex"
1685
- */
1686
- class Mutex {
1687
- constructor() {
1688
- this.mutex = Promise.resolve();
1689
- }
1690
- /**
1691
- * Acquires the mutex, returning a promise that resolves when the mutex is acquired.
1692
- * The returned promise provides a release function that should be called to release the mutex.
1693
- * @returns A promise that resolves with a release function.
1694
- */
1695
- async acquire() {
1696
- let release;
1697
- const previous = this.mutex;
1698
- this.mutex = new Promise((resolve) => (release = resolve));
1699
- await previous;
1700
- return release;
1701
- }
1702
- }
1703
-
1704
- /**
1705
- * A Semaphore controls access to a resource that can handle a limited number of concurrent operations.
1706
- *
1707
- * @example
1708
- * const semaphore = new Semaphore(2);
1709
- *
1710
- * async function task(name: string, duration: number) {
1711
- * console.log(`${name} waiting to acquire semaphore`);
1712
- * await semaphore.acquire();
1713
- * console.log(`${name} acquired semaphore`);
1714
- * await new Promise(resolve => setTimeout(resolve, duration));
1715
- * console.log(`${name} releasing semaphore`);
1716
- * semaphore.release();
1717
- * }
1718
- *
1719
- * task('Task 1', 1000);
1720
- * task('Task 2', 2000);
1721
- * task('Task 3', 1500);
1722
- * task('Task 4', 500);
1723
- *
1724
- * Outputs
1725
- * [LOG]: "Task 1 waiting to acquire semaphore"
1726
- * [LOG]: "Task 2 waiting to acquire semaphore"
1727
- * [LOG]: "Task 3 waiting to acquire semaphore"
1728
- * [LOG]: "Task 4 waiting to acquire semaphore"
1729
- * [LOG]: "Task 1 acquired semaphore"
1730
- * [LOG]: "Task 2 acquired semaphore"
1731
- * [LOG]: "Task 1 releasing semaphore"
1732
- * [LOG]: "Task 3 acquired semaphore"
1733
- * [LOG]: "Task 2 releasing semaphore"
1734
- * [LOG]: "Task 4 acquired semaphore"
1735
- * [LOG]: "Task 4 releasing semaphore"
1736
- * [LOG]: "Task 3 releasing semaphore"
1737
- */
1738
- class Semaphore {
1739
- constructor(maxConcurrency) {
1740
- this.maxConcurrency = maxConcurrency;
1741
- this.tasks = [];
1742
- this.currentCount = 0;
1743
- }
1744
- acquire() {
1745
- return new Promise((resolve) => {
1746
- if (this.currentCount < this.maxConcurrency) {
1747
- this.currentCount++;
1748
- resolve();
1749
- }
1750
- else {
1751
- this.tasks.push(resolve);
1752
- }
1753
- });
1754
- }
1755
- release() {
1756
- if (this.tasks.length > 0) {
1757
- const nextTask = this.tasks.shift();
1758
- if (nextTask) {
1759
- nextTask();
1760
- }
1761
- }
1762
- else if (this.currentCount > 0) {
1763
- this.currentCount--;
1764
- }
1765
- }
1766
- }
1767
-
1768
- class TaskRunner {
1769
- constructor() {
1770
- this.mutex = new Mutex();
1771
- }
1772
- runTask(name, task) {
1773
- // Log that the task is waiting to acquire the mutex
1774
- Logger.log(`${name} waiting to acquire mutex`);
1775
- return from(this.mutex.acquire()).pipe(switchMap((release) => {
1776
- // Log that the mutex has been acquired
1777
- Logger.log(`${name} acquired mutex`);
1778
- return task().pipe(finalize(() => {
1779
- Logger.log(`${name} releasing mutex`);
1780
- release();
1781
- }));
1782
- }));
1783
- }
1784
- }
1785
-
1786
- /**
1787
- * Emits the most recent value emitted by the source Observable after a
1788
- * specified time span has passed without another source emission.
1789
- *
1790
- * This is a combination of `debounceTime` and `auditTime` operators.
1791
- *
1792
- * The leading value is emitted immediately, and trailing values are debounced.
1793
- *
1794
- * @param dueTime The time to wait before emitting the last value.
1795
- * @param scheduler The scheduler to use for the timeout.
1796
- * @returns A function that returns an Observable that mirrors the source Observable, but applies the specified debouncing.
1797
- */
1798
- function leadingTrailingDebounceTime(dueTime, scheduler = asyncScheduler) {
1799
- return (source) => new Observable((subscriber) => {
1800
- let hasValue = false;
1801
- let lastValue = null;
1802
- let timerSubscription = null;
1803
- let leading = true; // Controls whether we emit immediately.
1804
- const clearTimer = () => {
1805
- if (timerSubscription) {
1806
- timerSubscription.unsubscribe();
1807
- timerSubscription = null;
1808
- }
1809
- };
1810
- const resetValues = () => {
1811
- hasValue = false;
1812
- lastValue = null;
1813
- leading = true; // Reset so the next new value is immediate.
1814
- };
1815
- const emitLastValue = () => {
1816
- if (hasValue && lastValue !== null) {
1817
- subscriber.next(lastValue);
1818
- resetValues();
1819
- }
1820
- };
1821
- const sourceSubscription = source.subscribe({
1822
- next: (value) => {
1823
- // If we are "leading", emit immediately and switch leading off
1824
- if (leading) {
1825
- subscriber.next(value);
1826
- leading = false;
1827
- timerSubscription = timer(dueTime, scheduler).subscribe(() => {
1828
- resetValues();
1829
- clearTimer();
1830
- });
1831
- return;
1832
- }
1833
- // Otherwise, save the value and start (or restart) timer
1834
- hasValue = true;
1835
- lastValue = value;
1836
- clearTimer();
1837
- timerSubscription = timer(dueTime, scheduler).subscribe(() => {
1838
- emitLastValue();
1839
- });
1840
- },
1841
- error: (err) => {
1842
- clearTimer();
1843
- subscriber.error(err);
1844
- },
1845
- complete: () => {
1846
- // If there is a pending emission, emit it before completing
1847
- clearTimer();
1848
- emitLastValue();
1849
- subscriber.complete();
1850
- },
1851
- });
1852
- // Cleanup logic
1853
- return () => {
1854
- clearTimer();
1855
- sourceSubscription.unsubscribe();
1856
- };
1857
- });
1858
- }
1859
-
1860
- /**
1861
- * Creates an observable that emits values transitioning smoothly from the start value to the end value over a specified duration.
1862
- * The transition is performed using linear interpolation (lerp) and clamped to the range [0, 1].
1863
- *
1864
- * @param {number} start - The starting value of the transition.
1865
- * @param {number} end - The ending value of the transition.
1866
- * @param {number} duration - The duration of the transition in milliseconds.
1867
- * @returns {Observable<number>} An observable that emits the interpolated values from start to end over the specified duration.
1868
- */
1869
- const smoothTransition = (start, end, duration) => {
1870
- const startTime = animationFrameScheduler.now();
1871
- return interval(0, animationFrameScheduler).pipe(map(() => {
1872
- const elapsed = (animationFrameScheduler.now() - startTime) / duration;
1873
- return clampf(0, 1, elapsed);
1874
- }), distinctUntilChanged(), map((fraction) => lerp(start, end, fraction)));
1875
- };
1876
-
1877
- const tapLog = (text, ...args) => (source) => source.pipe(tap((data) => {
1878
- Logger.colored(...COLOR_CODES.TAP_LOG, text, data, ...args);
1879
- }));
1880
-
1881
- /**
1882
- * Generated bundle index. Do not edit.
1883
- */
1884
-
1885
- export { BatchLoader, CMYKtoRGB, COLOR_CODES, CSV2Array, CSV2Records, DownloadImage, Falsy, HEXtoRGB, HSVtoRGB, ImageOutput, InvertedKeyMap, IsEmpty, KeyboardNumericCode, KeyboardStringCode, Logger, Mutex, NotEmpty, ObjectToCSV, RGBtoCMYK, RGBtoHEX, RGBtoHSV, SaveImage, Semaphore, Signal, TaskRunner, Truthy, baseSortedIndex, calculateMedian, circularIndex, clampf, cleanupFileName, debounce, degreesToRadians, expandOverRectangle, fitIntoRectangle, fpIsAGreaterThanB, fpIsALessThanB, fpIsASameAsB, generateUuid, getCanvasCached, getSnapshot, hsv, inverseLerp, isAllValuesTruthy, isDefined, isEmpty, isJSON, isLocalhost, isNotDefined, leadingTrailingDebounceTime, lerp, loadImage, makePath, max, min, normalizePath, overlay, pad, radiansToDegrees, rgb, saveToLocalDrive, serialize, sleep, smoothTransition, sub, subtract, sum, tapLog, textForSearch, timeToString, timeUTCToString, toRGB, toRGBA, trimLastSlashFromUrl, where, whereNot };
1886
- //# sourceMappingURL=3dsource-utils.mjs.map