uplot-webgpu 0.1.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 (50) hide show
  1. package/CANVAS_PROXY.md +602 -0
  2. package/README.md +854 -0
  3. package/favicon.ico +0 -0
  4. package/index.html +14 -0
  5. package/index.js +21 -0
  6. package/original/paths.canvas2d/bars.js +252 -0
  7. package/original/paths.canvas2d/catmullRomCentrip.js +125 -0
  8. package/original/paths.canvas2d/linear.js +170 -0
  9. package/original/paths.canvas2d/monotoneCubic.js +68 -0
  10. package/original/paths.canvas2d/points.js +66 -0
  11. package/original/paths.canvas2d/spline.js +103 -0
  12. package/original/paths.canvas2d/stepped.js +124 -0
  13. package/original/paths.canvas2d/utils.js +301 -0
  14. package/original/uPlot.canvas2d.js +3548 -0
  15. package/package.json +110 -0
  16. package/paths/bars.js +253 -0
  17. package/paths/catmullRomCentrip.js +126 -0
  18. package/paths/linear.js +171 -0
  19. package/paths/monotoneCubic.js +69 -0
  20. package/paths/points.js +67 -0
  21. package/paths/spline.js +104 -0
  22. package/paths/stepped.js +125 -0
  23. package/paths/utils.js +301 -0
  24. package/scripts/uPlot.css +168 -0
  25. package/scripts/uPlot.d.ts +26 -0
  26. package/scripts/uPlot.js +3687 -0
  27. package/scripts/utils/dom.js +124 -0
  28. package/scripts/utils/domClasses.js +22 -0
  29. package/scripts/utils/feats.js +13 -0
  30. package/scripts/utils/fmtDate.js +398 -0
  31. package/scripts/utils/opts.js +844 -0
  32. package/scripts/utils/strings.js +22 -0
  33. package/scripts/utils/sync.js +27 -0
  34. package/scripts/utils/utils.js +692 -0
  35. package/scripts/webgpu/GPUPath.d.ts +46 -0
  36. package/scripts/webgpu/GPUPath.js +633 -0
  37. package/scripts/webgpu/GPUPath.ts +634 -0
  38. package/scripts/webgpu/WebGPURenderer.d.ts +176 -0
  39. package/scripts/webgpu/WebGPURenderer.js +4256 -0
  40. package/scripts/webgpu/WebGPURenderer.ts +4257 -0
  41. package/scripts/webgpu/browserSmokeHarness.js +105 -0
  42. package/scripts/webgpu/exporters.d.ts +8 -0
  43. package/scripts/webgpu/exporters.js +212 -0
  44. package/scripts/webgpu/shaders.d.ts +2 -0
  45. package/scripts/webgpu/shaders.js +76 -0
  46. package/scripts/webgpu/shaders.ts +77 -0
  47. package/scripts/webgpu/smokeTest.d.ts +2 -0
  48. package/scripts/webgpu/smokeTest.js +144 -0
  49. package/scripts/webgpu/webgpu-ambient.d.ts +41 -0
  50. package/tinybuild.config.js +109 -0
@@ -0,0 +1,844 @@
1
+ import {
2
+ FEAT_TIME,
3
+ } from './feats.js';
4
+
5
+ import {
6
+ assign,
7
+
8
+ abs,
9
+ min,
10
+ max,
11
+
12
+ inf,
13
+ pow,
14
+ log2,
15
+ log10,
16
+ genIncrs,
17
+ round,
18
+ incrRoundUp,
19
+ roundDec,
20
+ floor,
21
+ fmtNum,
22
+ fixedDec,
23
+
24
+ retArg1,
25
+ noop,
26
+ ceil,
27
+ closestIdx,
28
+ } from './utils.js';
29
+
30
+ import {
31
+ hexBlack,
32
+ WIDTH,
33
+ HEIGHT,
34
+ LEGEND_DISP,
35
+ } from './strings.js';
36
+
37
+ import {
38
+ placeDiv,
39
+ setStylePx,
40
+ } from './dom.js';
41
+
42
+ import { DateZoned, fmtDate, floorSOP, PERIOD_DAY, PERIOD_MONTH, PERIOD_YEAR } from './fmtDate.js';
43
+
44
+ //export const series = [];
45
+
46
+ // default formatters:
47
+
48
+ const onlyWhole = v => v % 1 == 0;
49
+
50
+ const allMults = [1,2,2.5,5];
51
+
52
+ // ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
53
+ export const decIncrs = genIncrs(10, -32, 0, allMults);
54
+
55
+ // 1, 2, 2.5, 5, 10, 20, 25, 50...
56
+ export const oneIncrs = genIncrs(10, 0, 32, allMults);
57
+
58
+ // 1, 2, 5, 10, 20, 25, 50...
59
+ export const wholeIncrs = oneIncrs.filter(onlyWhole);
60
+
61
+ export const numIncrs = decIncrs.concat(oneIncrs);
62
+
63
+ const NL = "\n";
64
+
65
+ const yyyy = "{YYYY}";
66
+ const NLyyyy = NL + yyyy;
67
+ const md = "{M}/{D}";
68
+ const NLmd = NL + md;
69
+ const NLmdyy = NLmd + "/{YY}";
70
+
71
+ const aa = "{aa}";
72
+ const hmm = "{h}:{mm}";
73
+ const hmmaa = hmm + aa;
74
+ const NLhmmaa = NL + hmmaa;
75
+ const ss = ":{ss}";
76
+
77
+ const _ = null;
78
+
79
+ function genTimeStuffs(ms) {
80
+ let s = ms * 1e3,
81
+ m = s * 60,
82
+ h = m * 60,
83
+ d = h * 24,
84
+ mo = d * 30,
85
+ y = d * 365;
86
+
87
+ // min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
88
+ let subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
89
+
90
+ let timeIncrs = subSecIncrs.concat([
91
+ // minute divisors (# of secs)
92
+ s,
93
+ s * 5,
94
+ s * 10,
95
+ s * 15,
96
+ s * 30,
97
+ // hour divisors (# of mins)
98
+ m,
99
+ m * 5,
100
+ m * 10,
101
+ m * 15,
102
+ m * 30,
103
+ // day divisors (# of hrs)
104
+ h,
105
+ h * 2,
106
+ h * 3,
107
+ h * 4,
108
+ h * 6,
109
+ h * 8,
110
+ h * 12,
111
+ // month divisors TODO: need more?
112
+ d,
113
+ d * 2,
114
+ d * 3,
115
+ d * 4,
116
+ d * 5,
117
+ d * 6,
118
+ d * 7,
119
+ d * 8,
120
+ d * 9,
121
+ d * 10,
122
+ d * 15,
123
+ // year divisors (# months, approx)
124
+ mo,
125
+ mo * 2,
126
+ mo * 3,
127
+ mo * 4,
128
+ mo * 6,
129
+ // century divisors
130
+ y,
131
+ y * 2,
132
+ y * 5,
133
+ y * 10,
134
+ y * 25,
135
+ y * 50,
136
+ y * 100,
137
+ ]);
138
+
139
+ // [0]: minimum num secs in the tick incr
140
+ // [1]: default tick format
141
+ // [2-7]: rollover tick formats
142
+ // [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
143
+ const _timeAxisStamps = [
144
+ // tick incr default year month day hour min sec mode
145
+ [y, yyyy, _, _, _, _, _, _, 1],
146
+ [d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
147
+ [d, md, NLyyyy, _, _, _, _, _, 1],
148
+ [h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
149
+ [m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
150
+ [s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
151
+ [ms, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
152
+ ];
153
+
154
+ // the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
155
+ // https://www.timeanddate.com/time/dst/
156
+ // https://www.timeanddate.com/time/dst/2019.html
157
+ // https://www.epochconverter.com/timezones
158
+ function timeAxisSplits(tzDate) {
159
+ return (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {
160
+ let splits = [];
161
+ let isYr = foundIncr >= y;
162
+ let isMo = foundIncr >= mo && foundIncr < y;
163
+ let isDays = foundIncr >= d && foundIncr < mo;
164
+ let isHours = foundIncr > h && foundIncr < d
165
+
166
+ // get the timezone-adjusted date
167
+ let minDate = tzDate(scaleMin);
168
+ let minDateTs = roundDec(minDate * ms, 3);
169
+
170
+ // get ts of 12am (this lands us at or before the original scaleMin)
171
+ let minMin = floorSOP(minDate, isYr || isMo ? PERIOD_YEAR : isDays ? PERIOD_MONTH : PERIOD_DAY); // should we do PERIOD_HOUR?
172
+ let minMinTs = roundDec(minMin * ms, 3);
173
+
174
+ if (isDays) {
175
+ let incrDays = foundIncr / d;
176
+
177
+ // incrs to add to month baseline
178
+ let skip = floor((minDate.getDate() - 1) / incrDays);
179
+ let split = minMinTs + (foundIncr * skip);
180
+
181
+ do {
182
+ let date = tzDate(split);
183
+ // adjust for DST misses
184
+ let hour = date.getHours();
185
+ if (hour != 0) {
186
+ split += hour > 12 ? h : -h;
187
+ date = tzDate(split);
188
+ }
189
+
190
+ // rolled over into next month onto non-divisible incr, reset baseline
191
+ if ((date.getDate() - 1) % incrDays > 0) {
192
+ date = floorSOP(date, PERIOD_MONTH);
193
+ split = date.getTime() * ms;
194
+
195
+ // make sure we're not rendering a collision between 31 and 1
196
+ if (split - splits[splits.length - 1] < foundIncr * 0.7)
197
+ splits.pop();
198
+ }
199
+
200
+ if (split > scaleMax)
201
+ break;
202
+
203
+ if (split >= scaleMin)
204
+ splits.push(split);
205
+
206
+ split += foundIncr;
207
+ } while (1);
208
+ }
209
+ else if (isMo || isYr) {
210
+ let subIncrs = 1;
211
+ let subIncrDays = 1;
212
+ let periodType = 0;
213
+ let periodMin = 0;
214
+
215
+ if (isMo) {
216
+ subIncrs = foundIncr / mo;
217
+ subIncrDays = 32;
218
+ periodType = PERIOD_MONTH;
219
+ periodMin = minDate.getMonth();
220
+ }
221
+ else if (isYr) {
222
+ subIncrs = foundIncr / y;
223
+ subIncrDays = 366;
224
+ periodType = PERIOD_YEAR;
225
+ periodMin = minDate.getYear();
226
+ }
227
+
228
+ foundIncr = subIncrs * subIncrDays * d;
229
+
230
+ let skip = floor(periodMin / subIncrDays);
231
+ let split = minMinTs + (foundIncr * skip);
232
+
233
+ do {
234
+ let date = floorSOP(tzDate(split), periodType);
235
+ split = date.getTime() * ms;
236
+
237
+ if (split > scaleMax)
238
+ break;
239
+
240
+ if (split >= scaleMin)
241
+ splits.push(split);
242
+
243
+ split += foundIncr;
244
+ } while (1);
245
+ }
246
+ else if (isHours) {
247
+ let incrHours = foundIncr / h;
248
+
249
+ let skip = floor(minDate.getHours() / incrHours);
250
+ let split = minMinTs + (foundIncr * skip);
251
+
252
+ do {
253
+ let date = tzDate(split);
254
+
255
+ // adjust for DST misses
256
+ let hour = date.getHours();
257
+ if (hour % incrHours > 0) {
258
+ let hour2 = tzDate(split - h).getHours();
259
+ split += hour2 % incrHours == 0 ? -h : h;
260
+ }
261
+
262
+ if (split > scaleMax)
263
+ break;
264
+
265
+ if (split >= scaleMin)
266
+ splits.push(split);
267
+
268
+ split += foundIncr;
269
+ } while (1);
270
+ }
271
+ else {
272
+ let split = minMinTs + incrRoundUp(minDateTs - minMinTs, foundIncr);
273
+
274
+ do {
275
+ if (split > scaleMax)
276
+ break;
277
+
278
+ if (split >= scaleMin)
279
+ splits.push(split);
280
+
281
+ split += foundIncr;
282
+ } while (1);
283
+ }
284
+
285
+ return splits;
286
+ }
287
+ }
288
+
289
+ return [
290
+ timeIncrs,
291
+ _timeAxisStamps,
292
+ timeAxisSplits,
293
+ ];
294
+ }
295
+
296
+ export const [ timeIncrsMs, _timeAxisStampsMs, timeAxisSplitsMs ] = FEAT_TIME && genTimeStuffs(1);
297
+ export const [ timeIncrsS, _timeAxisStampsS, timeAxisSplitsS ] = FEAT_TIME && genTimeStuffs(1e-3);
298
+
299
+ // base 2
300
+ const binIncrs = genIncrs(2, -53, 53, [1]);
301
+
302
+ /*
303
+ console.log({
304
+ decIncrs,
305
+ oneIncrs,
306
+ wholeIncrs,
307
+ numIncrs,
308
+ timeIncrs,
309
+ fixedDec,
310
+ });
311
+ */
312
+
313
+ export function timeAxisStamps(stampCfg, fmtDate) {
314
+ return stampCfg.map(s => s.map((v, i) =>
315
+ i == 0 || i == 8 || v == null ? v : fmtDate(i == 1 || s[8] == 0 ? v : s[1] + v)
316
+ ));
317
+ }
318
+
319
+ // TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
320
+ // currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
321
+ export function timeAxisVals(tzDate, stamps) {
322
+ return (self, splits, axisIdx, foundSpace, foundIncr) => {
323
+ let s = stamps.find(s => foundIncr >= s[0]) || stamps[stamps.length - 1];
324
+
325
+ // these track boundaries when a full label is needed again
326
+ let prevYear;
327
+ let prevMnth;
328
+ let prevDate;
329
+ let prevHour;
330
+ let prevMins;
331
+ let prevSecs;
332
+
333
+ return splits.map(split => {
334
+ let date = tzDate(split);
335
+
336
+ let newYear = date.getFullYear();
337
+ let newMnth = date.getMonth();
338
+ let newDate = date.getDate();
339
+ let newHour = date.getHours();
340
+ let newMins = date.getMinutes();
341
+ let newSecs = date.getSeconds();
342
+
343
+ let stamp = (
344
+ newYear != prevYear && s[2] ||
345
+ newMnth != prevMnth && s[3] ||
346
+ newDate != prevDate && s[4] ||
347
+ newHour != prevHour && s[5] ||
348
+ newMins != prevMins && s[6] ||
349
+ newSecs != prevSecs && s[7] ||
350
+ s[1]
351
+ );
352
+
353
+ prevYear = newYear;
354
+ prevMnth = newMnth;
355
+ prevDate = newDate;
356
+ prevHour = newHour;
357
+ prevMins = newMins;
358
+ prevSecs = newSecs;
359
+
360
+ return stamp(date);
361
+ });
362
+ }
363
+ }
364
+
365
+ // for when axis.values is defined as a static fmtDate template string
366
+ export function timeAxisVal(tzDate, dateTpl) {
367
+ let stamp = fmtDate(dateTpl);
368
+ return (self, splits, axisIdx, foundSpace, foundIncr) => splits.map(split => stamp(tzDate(split)));
369
+ }
370
+
371
+ function mkDate(y, m, d) {
372
+ return new Date(y, m, d);
373
+ }
374
+
375
+ export function timeSeriesStamp(stampCfg, fmtDate) {
376
+ return fmtDate(stampCfg);
377
+ };
378
+
379
+ export const _timeSeriesStamp = '{YYYY}-{MM}-{DD} {h}:{mm}{aa}';
380
+
381
+ export function timeSeriesVal(tzDate, stamp) {
382
+ return (self, val, seriesIdx, dataIdx) => dataIdx == null ? LEGEND_DISP : stamp(tzDate(val));
383
+ }
384
+
385
+ export function legendStroke(self, seriesIdx) {
386
+ let s = self.series[seriesIdx];
387
+ return s.width ? s.stroke(self, seriesIdx) : s.points.width ? s.points.stroke(self, seriesIdx) : null;
388
+ }
389
+
390
+ export function legendFill(self, seriesIdx) {
391
+ return self.series[seriesIdx].fill(self, seriesIdx);
392
+ }
393
+
394
+ export const legendOpts = {
395
+ show: true,
396
+ live: true,
397
+ isolate: false,
398
+ mount: noop,
399
+ markers: {
400
+ show: true,
401
+ width: 2,
402
+ stroke: legendStroke,
403
+ fill: legendFill,
404
+ dash: "solid",
405
+ },
406
+ idx: null,
407
+ idxs: null,
408
+ values: [],
409
+ };
410
+
411
+ function cursorPointShow(self, si) {
412
+ let o = self.cursor.points;
413
+
414
+ let pt = placeDiv();
415
+
416
+ let size = o.size(self, si);
417
+ setStylePx(pt, WIDTH, size);
418
+ setStylePx(pt, HEIGHT, size);
419
+
420
+ let mar = size / -2;
421
+ setStylePx(pt, "marginLeft", mar);
422
+ setStylePx(pt, "marginTop", mar);
423
+
424
+ let width = o.width(self, si, size);
425
+ width && setStylePx(pt, "borderWidth", width);
426
+
427
+ return pt;
428
+ }
429
+
430
+ function cursorPointFill(self, si) {
431
+ let sp = self.series[si].points;
432
+ return sp._fill || sp._stroke;
433
+ }
434
+
435
+ function cursorPointStroke(self, si) {
436
+ let sp = self.series[si].points;
437
+ return sp._stroke || sp._fill;
438
+ }
439
+
440
+ function cursorPointSize(self, si) {
441
+ let sp = self.series[si].points;
442
+ return sp.size;
443
+ }
444
+
445
+ const moveTuple = [0,0];
446
+
447
+ function cursorMove(self, mouseLeft1, mouseTop1) {
448
+ moveTuple[0] = mouseLeft1;
449
+ moveTuple[1] = mouseTop1;
450
+ return moveTuple;
451
+ }
452
+
453
+ function filtBtn0(self, targ, handle, onlyTarg = true) {
454
+ return e => {
455
+ e.button == 0 && (!onlyTarg || e.target == targ) && handle(e);
456
+ };
457
+ }
458
+
459
+ function filtTarg(self, targ, handle, onlyTarg = true) {
460
+ return e => {
461
+ (!onlyTarg || e.target == targ) && handle(e);
462
+ };
463
+ }
464
+
465
+ export const cursorOpts = {
466
+ show: true,
467
+ x: true,
468
+ y: true,
469
+ lock: false,
470
+ move: cursorMove,
471
+ points: {
472
+ one: false,
473
+ show: cursorPointShow,
474
+ size: cursorPointSize,
475
+ width: 0,
476
+ stroke: cursorPointStroke,
477
+ fill: cursorPointFill,
478
+ },
479
+
480
+ bind: {
481
+ mousedown: filtBtn0,
482
+ mouseup: filtBtn0,
483
+ click: filtBtn0, // legend clicks, not .u-over clicks
484
+ dblclick: filtBtn0,
485
+
486
+ mousemove: filtTarg,
487
+ mouseleave: filtTarg,
488
+ mouseenter: filtTarg,
489
+ },
490
+
491
+ drag: {
492
+ setScale: true,
493
+ x: true,
494
+ y: false,
495
+ dist: 0,
496
+ uni: null,
497
+ click: (self, e) => {
498
+ // e.preventDefault();
499
+ e.stopPropagation();
500
+ e.stopImmediatePropagation();
501
+ },
502
+ _x: false,
503
+ _y: false,
504
+ },
505
+
506
+ focus: {
507
+ dist: (self, seriesIdx, dataIdx, valPos, curPos) => valPos - curPos,
508
+ prox: -1,
509
+ bias: 0,
510
+ },
511
+
512
+ hover: {
513
+ skip: [void 0],
514
+ prox: null,
515
+ bias: 0,
516
+ },
517
+
518
+ left: -10,
519
+ top: -10,
520
+ idx: null,
521
+ dataIdx: null,
522
+ idxs: null,
523
+
524
+ event: null,
525
+ };
526
+
527
+ const axisLines = {
528
+ show: true,
529
+ stroke: "rgba(0,0,0,0.07)",
530
+ width: 2,
531
+ // dash: [],
532
+ };
533
+
534
+ const grid = assign({}, axisLines, {
535
+ filter: retArg1,
536
+ });
537
+
538
+ const ticks = assign({}, grid, {
539
+ size: 10,
540
+ });
541
+
542
+ const border = assign({}, axisLines, {
543
+ show: false,
544
+ });
545
+
546
+ const font = '12px system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
547
+ const labelFont = "bold " + font;
548
+ const lineGap = 1.5; // font-size multiplier
549
+
550
+ export const xAxisOpts = {
551
+ show: true,
552
+ scale: "x",
553
+ stroke: hexBlack,
554
+ space: 50,
555
+ gap: 5,
556
+ alignTo: 1,
557
+ size: 50,
558
+ labelGap: 0,
559
+ labelSize: 30,
560
+ labelFont,
561
+ side: 2,
562
+ // class: "x-vals",
563
+ // incrs: timeIncrs,
564
+ // values: timeVals,
565
+ // filter: retArg1,
566
+ grid,
567
+ ticks,
568
+ border,
569
+ font,
570
+ lineGap,
571
+ rotate: 0,
572
+ };
573
+
574
+ export const numSeriesLabel = "Value";
575
+ export const timeSeriesLabel = "Time";
576
+
577
+ export const xSeriesOpts = {
578
+ show: true,
579
+ scale: "x",
580
+ auto: false,
581
+ sorted: 1,
582
+ // label: "Time",
583
+ // value: v => stamp(new Date(v * 1e3)),
584
+
585
+ // internal caches
586
+ min: inf,
587
+ max: -inf,
588
+ idxs: [],
589
+ };
590
+
591
+ export function numAxisVals(self, splits, axisIdx, foundSpace, foundIncr) {
592
+ return splits.map(v => v == null ? "" : fmtNum(v));
593
+ }
594
+
595
+ export function numAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {
596
+ let splits = [];
597
+
598
+ let numDec = fixedDec.get(foundIncr) || 0;
599
+
600
+ scaleMin = forceMin ? scaleMin : roundDec(incrRoundUp(scaleMin, foundIncr), numDec);
601
+
602
+ for (let val = scaleMin; val <= scaleMax; val = roundDec(val + foundIncr, numDec))
603
+ splits.push(Object.is(val, -0) ? 0 : val); // coalesces -0
604
+
605
+ return splits;
606
+ }
607
+
608
+ // this doesnt work for sin, which needs to come off from 0 independently in pos and neg dirs
609
+ export function logAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {
610
+ const splits = [];
611
+
612
+ const logBase = self.scales[self.axes[axisIdx].scale].log;
613
+
614
+ const logFn = logBase == 10 ? log10 : log2;
615
+
616
+ const exp = floor(logFn(scaleMin));
617
+
618
+ foundIncr = pow(logBase, exp);
619
+
620
+ // boo: 10 ** -24 === 1.0000000000000001e-24
621
+ // this grabs the proper 1e-24 one
622
+ if (logBase == 10)
623
+ foundIncr = numIncrs[closestIdx(foundIncr, numIncrs)];
624
+
625
+ let split = foundIncr;
626
+ let nextMagIncr = foundIncr * logBase;
627
+
628
+ if (logBase == 10)
629
+ nextMagIncr = numIncrs[closestIdx(nextMagIncr, numIncrs)];
630
+
631
+ do {
632
+ if (split >= scaleMin)
633
+ splits.push(split);
634
+
635
+ split = split + foundIncr;
636
+
637
+ if (logBase == 10 && !fixedDec.has(split))
638
+ split = roundDec(split, fixedDec.get(foundIncr));
639
+
640
+ if (split >= nextMagIncr) {
641
+ foundIncr = split;
642
+ nextMagIncr = foundIncr * logBase;
643
+
644
+ if (logBase == 10)
645
+ nextMagIncr = numIncrs[closestIdx(nextMagIncr, numIncrs)];
646
+ }
647
+ } while (split <= scaleMax);
648
+
649
+ return splits;
650
+ }
651
+
652
+ export function asinhAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {
653
+ let sc = self.scales[self.axes[axisIdx].scale];
654
+
655
+ let linthresh = sc.asinh;
656
+
657
+ let posSplits = scaleMax > linthresh ? logAxisSplits(self, axisIdx, max(linthresh, scaleMin), scaleMax, foundIncr, foundSpace, forceMin) : [linthresh];
658
+ let zero = scaleMax >= 0 && scaleMin <= 0 ? [0] : [];
659
+ let negSplits = scaleMin < -linthresh ? logAxisSplits(self, axisIdx, max(linthresh, -scaleMax), -scaleMin, foundIncr, foundSpace, forceMin): [linthresh];
660
+
661
+ return negSplits.reverse().map(v => -v).concat(zero, posSplits);
662
+ }
663
+
664
+ const RE_ALL = /./;
665
+ const RE_12357 = /[12357]/;
666
+ const RE_125 = /[125]/;
667
+ const RE_1 = /1/;
668
+
669
+ const _filt = (splits, distr, re, keepMod) => splits.map((v, i) => ((distr == 4 && v == 0) || i % keepMod == 0 && re.test(v.toExponential()[v < 0 ? 1 : 0])) ? v : null);
670
+
671
+ export function log10AxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {
672
+ let axis = self.axes[axisIdx];
673
+ let scaleKey = axis.scale;
674
+ let sc = self.scales[scaleKey];
675
+
676
+ // if (sc.distr == 3 && sc.log == 2)
677
+ // return splits;
678
+
679
+ let valToPos = self.valToPos;
680
+
681
+ let minSpace = axis._space;
682
+
683
+ let _10 = valToPos(10, scaleKey);
684
+
685
+ let re = (
686
+ valToPos(9, scaleKey) - _10 >= minSpace ? RE_ALL :
687
+ valToPos(7, scaleKey) - _10 >= minSpace ? RE_12357 :
688
+ valToPos(5, scaleKey) - _10 >= minSpace ? RE_125 :
689
+ RE_1
690
+ );
691
+
692
+ if (re == RE_1) {
693
+ let magSpace = abs(valToPos(1, scaleKey) - _10);
694
+
695
+ if (magSpace < minSpace)
696
+ return _filt(splits.slice().reverse(), sc.distr, re, ceil(minSpace / magSpace)).reverse(); // max->min skip
697
+ }
698
+
699
+ return _filt(splits, sc.distr, re, 1);
700
+ }
701
+
702
+ export function log2AxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {
703
+ let axis = self.axes[axisIdx];
704
+ let scaleKey = axis.scale;
705
+ let minSpace = axis._space;
706
+ let valToPos = self.valToPos;
707
+
708
+ let magSpace = abs(valToPos(1, scaleKey) - valToPos(2, scaleKey));
709
+
710
+ if (magSpace < minSpace)
711
+ return _filt(splits.slice().reverse(), 3, RE_ALL, ceil(minSpace / magSpace)).reverse(); // max->min skip
712
+
713
+ return splits;
714
+ }
715
+
716
+ export function numSeriesVal(self, val, seriesIdx, dataIdx) {
717
+ return dataIdx == null ? LEGEND_DISP : val == null ? "" : fmtNum(val);
718
+ }
719
+
720
+ export const yAxisOpts = {
721
+ show: true,
722
+ scale: "y",
723
+ stroke: hexBlack,
724
+ space: 30,
725
+ gap: 5,
726
+ alignTo: 1,
727
+ size: 50,
728
+ labelGap: 0,
729
+ labelSize: 30,
730
+ labelFont,
731
+ side: 3,
732
+ // class: "y-vals",
733
+ // incrs: numIncrs,
734
+ // values: (vals, space) => vals,
735
+ // filter: retArg1,
736
+ grid,
737
+ ticks,
738
+ border,
739
+ font,
740
+ lineGap,
741
+ rotate: 0,
742
+ };
743
+
744
+ // takes stroke width
745
+ export function ptDia(width, mult) {
746
+ let dia = 3 + (width || 1) * 2;
747
+ return roundDec(dia * mult, 3);
748
+ }
749
+
750
+ function seriesPointsShow(self, si) {
751
+ let { scale, idxs } = self.series[0];
752
+ let xData = self._data[0];
753
+ let p0 = self.valToPos(xData[idxs[0]], scale, true);
754
+ let p1 = self.valToPos(xData[idxs[1]], scale, true);
755
+ let dim = abs(p1 - p0);
756
+
757
+ let s = self.series[si];
758
+ // const dia = ptDia(s.width, self.pxRatio);
759
+ let maxPts = dim / (s.points.space * self.pxRatio);
760
+ return idxs[1] - idxs[0] <= maxPts;
761
+ }
762
+
763
+ const facet = {
764
+ scale: null,
765
+ auto: true,
766
+ sorted: 0,
767
+
768
+ // internal caches
769
+ min: inf,
770
+ max: -inf,
771
+ };
772
+
773
+ const gaps = (self, seriesIdx, idx0, idx1, nullGaps) => nullGaps;
774
+
775
+ export const xySeriesOpts = {
776
+ show: true,
777
+ auto: true,
778
+ sorted: 0,
779
+ gaps,
780
+ alpha: 1,
781
+ facets: [
782
+ assign({}, facet, {scale: 'x'}),
783
+ assign({}, facet, {scale: 'y'}),
784
+ ],
785
+ };
786
+
787
+ export const ySeriesOpts = {
788
+ scale: "y",
789
+ auto: true,
790
+ sorted: 0,
791
+ show: true,
792
+ spanGaps: false,
793
+ gaps,
794
+ alpha: 1,
795
+ points: {
796
+ show: seriesPointsShow,
797
+ filter: null,
798
+ // paths:
799
+ // stroke: "#000",
800
+ // fill: "#fff",
801
+ // width: 1,
802
+ // size: 10,
803
+ },
804
+ // label: "Value",
805
+ // value: v => v,
806
+ values: null,
807
+
808
+ // internal caches
809
+ min: inf,
810
+ max: -inf,
811
+ idxs: [],
812
+
813
+ path: null,
814
+ clip: null,
815
+ };
816
+
817
+ export function clampScale(self, val, scaleMin, scaleMax, scaleKey) {
818
+ /*
819
+ if (val < 0) {
820
+ let cssHgt = self.bbox.height / self.pxRatio;
821
+ let absPos = self.valToPos(abs(val), scaleKey);
822
+ let fromBtm = cssHgt - absPos;
823
+ return self.posToVal(cssHgt + fromBtm, scaleKey);
824
+ }
825
+ */
826
+ return scaleMin / 10;
827
+ }
828
+
829
+ export const xScaleOpts = {
830
+ time: FEAT_TIME,
831
+ auto: true,
832
+ distr: 1,
833
+ log: 10,
834
+ asinh: 1,
835
+ min: null,
836
+ max: null,
837
+ dir: 1,
838
+ ori: 0,
839
+ };
840
+
841
+ export const yScaleOpts = assign({}, xScaleOpts, {
842
+ time: false,
843
+ ori: 1,
844
+ });