uplot-webgpu 0.1.0 → 0.2.0

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 (42) hide show
  1. package/index.js +0 -17
  2. package/index.ts +5 -0
  3. package/package.json +4 -69
  4. package/paths/ts/bars.ts +253 -0
  5. package/paths/ts/catmullRomCentrip.ts +127 -0
  6. package/paths/ts/index.ts +9 -0
  7. package/paths/ts/linear.ts +172 -0
  8. package/paths/ts/monotoneCubic.ts +70 -0
  9. package/paths/ts/points.ts +70 -0
  10. package/paths/ts/spline.ts +105 -0
  11. package/paths/ts/stepped.ts +126 -0
  12. package/paths/ts/types.ts +143 -0
  13. package/paths/ts/utils.ts +303 -0
  14. package/scripts/ts/uPlot.ts +3732 -0
  15. package/scripts/ts/utils/dom.ts +124 -0
  16. package/scripts/ts/utils/domClasses.ts +22 -0
  17. package/scripts/ts/utils/feats.ts +13 -0
  18. package/scripts/ts/utils/fmtDate.ts +398 -0
  19. package/scripts/ts/utils/opts.ts +844 -0
  20. package/scripts/ts/utils/strings.ts +22 -0
  21. package/scripts/ts/utils/sync.ts +27 -0
  22. package/scripts/ts/utils/utils.ts +692 -0
  23. package/scripts/{webgpu → ts/webgpu}/GPUPath.ts +92 -41
  24. package/scripts/{webgpu → ts/webgpu}/WebGPURenderer.ts +176 -84
  25. package/scripts/ts/webgpu/exporters.ts +221 -0
  26. package/scripts/ts/webgpu/index.ts +31 -0
  27. package/scripts/{webgpu → ts/webgpu}/shaders.ts +0 -1
  28. package/scripts/uPlot.js +0 -2
  29. package/scripts/webgpu/GPUPath.js +513 -606
  30. package/scripts/webgpu/WebGPURenderer.js +3484 -4018
  31. package/scripts/webgpu/exporters.js +191 -201
  32. package/scripts/webgpu/index.js +12 -0
  33. package/scripts/webgpu/shaders.js +6 -3
  34. package/tinybuild.config.js +6 -6
  35. package/tsconfig.json +64 -0
  36. package/scripts/uPlot.d.ts +0 -26
  37. package/scripts/webgpu/GPUPath.d.ts +0 -46
  38. package/scripts/webgpu/WebGPURenderer.d.ts +0 -176
  39. package/scripts/webgpu/exporters.d.ts +0 -8
  40. package/scripts/webgpu/shaders.d.ts +0 -2
  41. package/scripts/webgpu/smokeTest.d.ts +0 -2
  42. package/scripts/webgpu/webgpu-ambient.d.ts +0 -41
@@ -0,0 +1,124 @@
1
+ import {
2
+ OFF,
3
+ } from './domClasses';
4
+
5
+ import {
6
+ change,
7
+ dppxchange,
8
+ } from './strings';
9
+
10
+ export const domEnv = typeof window != 'undefined';
11
+
12
+ export const doc = domEnv ? document : null;
13
+ export const win = domEnv ? window : null;
14
+
15
+ export let pxRatio;
16
+
17
+ //export const canHover = domEnv && !win.matchMedia('(hover: none)').matches;
18
+
19
+ let query;
20
+
21
+ function setPxRatio() {
22
+ let _pxRatio = devicePixelRatio;
23
+
24
+ // during print preview, Chrome fires off these dppx queries even without changes
25
+ if (pxRatio != _pxRatio) {
26
+ pxRatio = _pxRatio;
27
+
28
+ query && off(change, query, setPxRatio);
29
+ query = matchMedia(`(min-resolution: ${pxRatio - 0.001}dppx) and (max-resolution: ${pxRatio + 0.001}dppx)`);
30
+ on(change, query, setPxRatio);
31
+
32
+ win.dispatchEvent(new CustomEvent(dppxchange));
33
+ }
34
+ }
35
+
36
+ export function addClass(el?: any, c?: any, ..._extra: any[]) {
37
+ if (c != null) {
38
+ let cl = el.classList;
39
+ !cl.contains(c) && cl.add(c);
40
+ }
41
+ }
42
+
43
+ export function remClass(el?: any, c?: any, ..._extra: any[]) {
44
+ let cl = el.classList;
45
+ cl.contains(c) && cl.remove(c);
46
+ }
47
+
48
+ export function setStylePx(el?: any, name?: any, value?: any, ..._extra: any[]) {
49
+ el.style[name] = value + "px";
50
+ }
51
+
52
+ export function placeTag(tag?: any, cls?: any, targ?: any, refEl?: any, ..._extra: any[]) {
53
+ let el = doc.createElement(tag);
54
+
55
+ if (cls != null)
56
+ addClass(el, cls);
57
+
58
+ if (targ != null)
59
+ targ.insertBefore(el, refEl);
60
+
61
+ return el;
62
+ }
63
+
64
+ export function placeDiv(cls?: any, targ?: any, ..._extra: any[]) {
65
+ return placeTag("div", cls, targ);
66
+ }
67
+
68
+ const xformCache = new WeakMap();
69
+
70
+ export function elTrans(el?: any, xPos?: any, yPos?: any, xMax?: any, yMax?: any, ..._extra: any[]) {
71
+ let xform = "translate(" + xPos + "px," + yPos + "px)";
72
+ let xformOld = xformCache.get(el);
73
+
74
+ if (xform != xformOld) {
75
+ el.style.transform = xform;
76
+ xformCache.set(el, xform);
77
+
78
+ if (xPos < 0 || yPos < 0 || xPos > xMax || yPos > yMax)
79
+ addClass(el, OFF);
80
+ else
81
+ remClass(el, OFF);
82
+ }
83
+ }
84
+
85
+ const colorCache = new WeakMap();
86
+
87
+ export function elColor(el?: any, background?: any, borderColor?: any, ..._extra: any[]) {
88
+ let newColor = background + borderColor;
89
+ let oldColor = colorCache.get(el);
90
+
91
+ if (newColor != oldColor) {
92
+ colorCache.set(el, newColor);
93
+ el.style.background = background;
94
+ el.style.borderColor = borderColor;
95
+ }
96
+ }
97
+
98
+ const sizeCache = new WeakMap();
99
+
100
+ export function elSize(el?: any, newWid?: any, newHgt?: any, centered?: any, ..._extra: any[]) {
101
+ let newSize = newWid + "" + newHgt;
102
+ let oldSize = sizeCache.get(el);
103
+
104
+ if (newSize != oldSize) {
105
+ sizeCache.set(el, newSize);
106
+ el.style.height = newHgt + "px";
107
+ el.style.width = newWid + "px";
108
+ el.style.marginLeft = centered ? -newWid/2 + "px" : 0;
109
+ el.style.marginTop = centered ? -newHgt/2 + "px" : 0;
110
+ }
111
+ }
112
+
113
+ const evOpts = {passive: true};
114
+ const evOpts2 = {...evOpts, capture: true};
115
+
116
+ export function on(ev?: any, el?: any, cb?: any, capt?: any, ..._extra: any[]) {
117
+ el.addEventListener(ev, cb, capt ? evOpts2 : evOpts);
118
+ }
119
+
120
+ export function off(ev?: any, el?: any, cb?: any, capt?: any, ..._extra: any[]) {
121
+ el.removeEventListener(ev, cb, capt ? evOpts2 : evOpts);
122
+ }
123
+
124
+ domEnv && setPxRatio();
@@ -0,0 +1,22 @@
1
+ const pre = "u-";
2
+
3
+ export const UPLOT = "uplot";
4
+ export const ORI_HZ = pre + "hz";
5
+ export const ORI_VT = pre + "vt";
6
+ export const TITLE = pre + "title";
7
+ export const WRAP = pre + "wrap";
8
+ export const UNDER = pre + "under";
9
+ export const OVER = pre + "over";
10
+ export const AXIS = pre + "axis";
11
+ export const OFF = pre + "off";
12
+ export const SELECT = pre + "select";
13
+ export const CURSOR_X = pre + "cursor-x";
14
+ export const CURSOR_Y = pre + "cursor-y";
15
+ export const CURSOR_PT = pre + "cursor-pt";
16
+ export const LEGEND = pre + "legend"
17
+ export const LEGEND_LIVE = pre + "live";
18
+ export const LEGEND_INLINE = pre + "inline";
19
+ export const LEGEND_SERIES = pre + "series";
20
+ export const LEGEND_MARKER = pre + "marker";
21
+ export const LEGEND_LABEL = pre + "label";
22
+ export const LEGEND_VALUE = pre + "value";
@@ -0,0 +1,13 @@
1
+ export const FEAT_TIME = true;
2
+ export const FEAT_LEGEND = true;
3
+
4
+ export const FEAT_POINTS = true;
5
+
6
+ export const FEAT_PATHS = true;
7
+ export const FEAT_PATHS_LINEAR = true;
8
+ export const FEAT_PATHS_STEPPED = true;
9
+ export const FEAT_PATHS_BARS = true;
10
+ export const FEAT_PATHS_SPLINE = true;
11
+ export const FEAT_PATHS_SPLINE2 = true;
12
+
13
+ export const FEAT_JOIN = true;
@@ -0,0 +1,398 @@
1
+ import {
2
+ FEAT_TIME,
3
+ } from './feats';
4
+ import { abs, floor } from './utils';
5
+
6
+ const months = [
7
+ "January",
8
+ "February",
9
+ "March",
10
+ "April",
11
+ "May",
12
+ "June",
13
+ "July",
14
+ "August",
15
+ "September",
16
+ "October",
17
+ "November",
18
+ "December",
19
+ ];
20
+
21
+ const days = [
22
+ "Sunday",
23
+ "Monday",
24
+ "Tuesday",
25
+ "Wednesday",
26
+ "Thursday",
27
+ "Friday",
28
+ "Saturday",
29
+ ];
30
+
31
+ function slice3(str?: any, ..._extra: any[]) {
32
+ return str.slice(0, 3);
33
+ }
34
+
35
+ const days3 = FEAT_TIME && days.map(slice3);
36
+
37
+ const months3 = FEAT_TIME && months.map(slice3);
38
+
39
+ const engNames = {
40
+ MMMM: months,
41
+ MMM: months3,
42
+ WWWW: days,
43
+ WWW: days3,
44
+ };
45
+
46
+ function zeroPad2(int?: any, ..._extra: any[]) {
47
+ return (int < 10 ? '0' : '') + int;
48
+ }
49
+
50
+ function zeroPad3(int?: any, ..._extra: any[]) {
51
+ return (int < 10 ? '00' : int < 100 ? '0' : '') + int;
52
+ }
53
+
54
+ /*
55
+ function suffix(int?: any, ..._extra: any[]) {
56
+ let mod10 = int % 10;
57
+
58
+ return int + (
59
+ mod10 == 1 && int != 11 ? "st" :
60
+ mod10 == 2 && int != 12 ? "nd" :
61
+ mod10 == 3 && int != 13 ? "rd" : "th"
62
+ );
63
+ }
64
+ */
65
+
66
+ const subs = {
67
+ // 2019
68
+ YYYY: d => d.getFullYear(),
69
+ // 19
70
+ YY: d => (d.getFullYear()+'').slice(2),
71
+ // July
72
+ MMMM: (d, names) => names.MMMM[d.getMonth()],
73
+ // Jul
74
+ MMM: (d, names) => names.MMM[d.getMonth()],
75
+ // 07
76
+ MM: d => zeroPad2(d.getMonth()+1),
77
+ // 7
78
+ M: d => d.getMonth()+1,
79
+ // 09
80
+ DD: d => zeroPad2(d.getDate()),
81
+ // 9
82
+ D: d => d.getDate(),
83
+ // Monday
84
+ WWWW: (d, names) => names.WWWW[d.getDay()],
85
+ // Mon
86
+ WWW: (d, names) => names.WWW[d.getDay()],
87
+ // 03
88
+ HH: d => zeroPad2(d.getHours()),
89
+ // 3
90
+ H: d => d.getHours(),
91
+ // 9 (12hr, unpadded)
92
+ h: d => {let h = d.getHours(); return h == 0 ? 12 : h > 12 ? h - 12 : h;},
93
+ // AM
94
+ AA: d => d.getHours() >= 12 ? 'PM' : 'AM',
95
+ // am
96
+ aa: d => d.getHours() >= 12 ? 'pm' : 'am',
97
+ // a
98
+ a: d => d.getHours() >= 12 ? 'p' : 'a',
99
+ // 09
100
+ mm: d => zeroPad2(d.getMinutes()),
101
+ // 9
102
+ m: d => d.getMinutes(),
103
+ // 09
104
+ ss: d => zeroPad2(d.getSeconds()),
105
+ // 9
106
+ s: d => d.getSeconds(),
107
+ // 374
108
+ fff: d => zeroPad3(d.getMilliseconds()),
109
+
110
+ /*
111
+ // this really only makes sense for DateZoned
112
+ // -05:00
113
+ tzo: d => {
114
+ let o = d.getTimezoneOffset();
115
+ let s = o > 0 ? '-' : '+';
116
+ o = abs(o);
117
+ let hh = zeroPad2(floor(o / 60));
118
+ let mm = zeroPad2(o % 60);
119
+ return `${s}${hh}:${mm}`;
120
+ }
121
+ */
122
+ };
123
+
124
+ // export const iso8601 = fmtDate('{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}.{fff}{tzo}');
125
+
126
+ export function fmtDate(tpl?: any, names?: any, ..._extra: any[]) {
127
+ names = names || engNames;
128
+ let parts = [];
129
+
130
+ let R = /\{([a-z]+)\}|[^{]+/gi, m;
131
+
132
+ while (m = R.exec(tpl))
133
+ parts.push(m[0][0] == '{' ? subs[m[1]] : m[0]);
134
+
135
+ return d => {
136
+ let out = '';
137
+
138
+ for (let i = 0; i < parts.length; i++)
139
+ out += typeof parts[i] == "string" ? parts[i] : parts[i](d, names);
140
+
141
+ return out;
142
+ }
143
+ }
144
+
145
+ const localTz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
146
+
147
+ export function tzDate(dateOrTs?: any, tz?: any, ..._extra: any[]) {
148
+ if (tz == null || tz == localTz)
149
+ return typeof dateOrTs == 'number' ? new Date(dateOrTs) : dateOrTs;
150
+
151
+ let d = new DateZoned(dateOrTs);
152
+ d.setTimeZone(tz);
153
+ return d;
154
+ }
155
+
156
+ const twoDigit = '2-digit';
157
+
158
+ const fmtrOpts = {
159
+ weekday: "short",
160
+ year: 'numeric',
161
+ month: twoDigit,
162
+ day: twoDigit,
163
+ hour: twoDigit,
164
+ minute: twoDigit,
165
+ second: twoDigit,
166
+ fractionalSecondDigits: 3,
167
+ timeZoneName: 'longOffset',
168
+ };
169
+
170
+ /*
171
+ // this might be a bit easier to parse to avoid negative .slice() offsets
172
+ new Intl.DateTimeFormat('en-US', {
173
+ hour12: false,
174
+ timeZone: 'Europe/London',
175
+ year: 'numeric',
176
+ month: '2-digit',
177
+ day: '2-digit',
178
+ hour: '2-digit',
179
+ minute: '2-digit',
180
+ second: '2-digit',
181
+ timeZoneName: 'longOffset',
182
+ weekday: 'short',
183
+ fractionalSecondDigits: 3,
184
+ }).format(new Date());
185
+
186
+ // Tue, 07/22/2025, 07:02:37.043 GMT+01:00
187
+ */
188
+
189
+ const tzFmt: Record<string, Intl.DateTimeFormat["format"]> = {};
190
+
191
+ function getFormatter(tz?: any, ..._extra: any[]) {
192
+ if (tzFmt[tz] == null)
193
+ tzFmt[tz] = new Intl.DateTimeFormat("sv", {...fmtrOpts, timeZone: tz} as Intl.DateTimeFormatOptions).format;
194
+
195
+ return tzFmt[tz];
196
+ }
197
+
198
+ export class DateZoned extends Date {
199
+ tz = null;
200
+ #utc = false;
201
+ // sön, 1972-10-15 17:25:23,434 GMT+01:00
202
+ #str = null;
203
+
204
+ constructor(...args: any[]) {
205
+ super(...(args as [any, any?, any?, any?, any?, any?, any?]));
206
+
207
+ if (args[0] instanceof DateZoned) {
208
+ this.tz = args[0].tz;
209
+ this.#str = args[0].#str;
210
+ this.#utc = args[0].#utc;
211
+ }
212
+ }
213
+
214
+ #get(utcMeth, locMeth, fr, to, add = 0) {
215
+ let s = this.#str;
216
+ return this.#utc ? utcMeth.call(this) : s == null ? locMeth.call(this) : Number(s.slice(fr,to)) + add;
217
+ }
218
+
219
+ setTimeZone(tz) {
220
+ this.tz = tz;
221
+
222
+ if (tz == 'UTC' || tz == 'Etc/UTC')
223
+ this.#utc = true;
224
+ else {
225
+ let fmt = getFormatter(tz);
226
+ let f = fmt(this);
227
+
228
+ if (f.endsWith('GMT'))
229
+ f += '+00:00';
230
+
231
+ this.#str = f;
232
+ }
233
+ }
234
+
235
+ getFullYear() {
236
+ return this.#get(this.getUTCFullYear, super.getFullYear, -33, -29);
237
+ }
238
+
239
+ getMonth() {
240
+ return this.#get(this.getUTCMonth, super.getMonth, -28, -26, -1);
241
+ }
242
+
243
+ getDate() {
244
+ return this.#get(this.getUTCDate, super.getDate, -25, -23);
245
+ }
246
+
247
+ getHours() {
248
+ return this.#get(this.getUTCHours, super.getHours, -22, -20);
249
+ }
250
+
251
+ getMinutes() {
252
+ return this.#get(this.getUTCMinutes, super.getMinutes, -19, -17);
253
+ }
254
+
255
+ getSeconds() {
256
+ return this.#get(this.getUTCSeconds, super.getSeconds, -16, -14);
257
+ }
258
+
259
+ getMilliseconds() {
260
+ return this.#get(this.getUTCMilliseconds, super.getMilliseconds, -13, -10);
261
+ }
262
+
263
+ getDay() {
264
+ let s = this.#str;
265
+ return this.#utc ? this.getUTCDay() : s == null ? super.getDay() : (
266
+ s[0] == 's' ? 0 : // sön
267
+ s[0] == 'm' ? 1 : // mån
268
+ s[1] == 'i' ? 2 : // tis
269
+ s[0] == 'o' ? 3 : // ons
270
+ s[1] == 'o' ? 4 : // tors
271
+ s[0] == 'f' ? 5 : // fre
272
+ s[0] == 'l' ? 6 : // lör
273
+ -1
274
+ );
275
+ }
276
+
277
+ getTimezoneOffset() {
278
+ let s = this.#str;
279
+ return this.#utc ? 0 : s == null ? super.getTimezoneOffset() : (60 * Number(s.slice(-5,-3)) + Number(s.slice(-2))) * (s.at(-6) == '-' ? -1 : 1);
280
+ }
281
+ }
282
+
283
+ function getDayOfYear(date?: any, ..._extra: any[]) {
284
+ let y = date.getFullYear();
285
+ let m = date.getMonth() + 1;
286
+ let d = date.getDate();
287
+
288
+ // https://stackoverflow.com/a/27790471
289
+ return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d;
290
+ }
291
+
292
+ function leapYear(year?: any, ..._extra: any[]) {
293
+ return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
294
+ }
295
+
296
+ // these can be done through just incrRoundDn of 1e3 or 60 * 1e3
297
+ // export const PERIOD_SECOND = 0;
298
+ // export const PERIOD_MINUTE = 1;
299
+
300
+ // this might be needed for tzs where DST is not whole hours?
301
+ // otherwise incrRoundDn of 3600 * 1e3
302
+ // export const PERIOD_HOUR = 2;
303
+
304
+ // thse need special handling due to day length changing due to DST
305
+ export const PERIOD_DAY = 3;
306
+ export const PERIOD_MONTH = 4;
307
+ export const PERIOD_YEAR = 5;
308
+ // export const PERIOD_WEEK;
309
+
310
+ // get start of period, requires DateZoned and period const
311
+ export function floorSOP(dz?: any, per?: any, ..._extra: any[]) {
312
+ let ts = dz.getTime();
313
+
314
+ // initial guess (assumes no DST)
315
+ let ts2 = ts - (
316
+ dz.getMilliseconds() +
317
+ dz.getSeconds() * 1e3 +
318
+ dz.getMinutes() * 60 * 1e3 +
319
+ dz.getHours() * 3600 * 1e3 +
320
+ (
321
+ (
322
+ per == PERIOD_MONTH ? dz.getDate() - 1:
323
+ per == PERIOD_YEAR ? getDayOfYear(dz) - 1:
324
+ 0
325
+ )
326
+ * 24 * 3600 * 1e3
327
+ )
328
+ );
329
+
330
+ // if (ts2 == ts)
331
+ // return dz;
332
+
333
+ let dz2 = new DateZoned(ts2);
334
+ dz2.setTimeZone(dz.tz);
335
+
336
+ let h2 = dz2.getHours();
337
+
338
+ // we want hours to be 0
339
+ if (h2 > 0) {
340
+ let dstAdj = h2 > 12 ? 24 - h2 : -h2;
341
+ dz2 = new DateZoned(ts2 + dstAdj * 3600 * 1e3);
342
+ dz2.setTimeZone(dz.tz);
343
+ }
344
+
345
+ return dz2;
346
+ }
347
+
348
+ // tweaks the time by +/- 1hr to make sure it lands on 12am
349
+ // used for correcting optimistically-computed ticks from adding fixed increments
350
+ // export function sopNear(dz?: any, per?: any, ..._extra: any[]) {}
351
+
352
+ /*
353
+ let fmt = fmtDate('{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}.{fff}{tzo}');
354
+
355
+ {
356
+ let d = new DateZoned(1554274800000); // post-roll date
357
+ d.setTimeZone('Europe/London');
358
+ let sod = getSOP(d, PERIOD_DAY);
359
+ console.log(sod.getTime() / 1e3);
360
+ console.log(fmt(sod));
361
+ }
362
+
363
+ {
364
+ let d = new DateZoned(1554274800000); // post-roll date
365
+ d.setTimeZone('America/Chicago');
366
+ let sod = getSOP(d, PERIOD_DAY);
367
+ console.log(sod.getTime() / 1e3);
368
+ console.log(fmt(sod));
369
+ }
370
+
371
+ {
372
+ let d = new DateZoned(1554004800000); // few hours after london spring forward
373
+ d.setTimeZone('Europe/London');
374
+ let sod = getSOP(d, PERIOD_DAY);
375
+ console.log(sod.getTime() / 1e3);
376
+ console.log(fmt(sod));
377
+ }
378
+
379
+ {
380
+ let d = new DateZoned(1572156000000); // few hours after london fall back
381
+ d.setTimeZone('Europe/London');
382
+ let sod = getSOP(d, PERIOD_DAY);
383
+ console.log(sod.getTime() / 1e3);
384
+ console.log(fmt(sod));
385
+ }
386
+ */
387
+
388
+
389
+ /*
390
+ TODO:
391
+
392
+ 2024 - leap year
393
+ start of year before feb vs after
394
+ start of month in dst fwd month / bwd month
395
+ start of day in dst fwd day / bwd day
396
+
397
+ Australia/Darwin
398
+ */