@umriss-ui/charts 0.3.0-rc.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.
@@ -0,0 +1,1033 @@
1
+ import { CSSProperties } from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ export declare type Accessor<T> = (d: T, index: number) => number | null | undefined;
5
+
6
+ export declare function Area<T>(props: AreaProps<T>): null;
7
+
8
+ export declare interface AreaProps<T> {
9
+ /** Upper edge; null/undefined/NaN means a gap (R-2.5). */
10
+ accessor: Accessor<T>;
11
+ /** Lower edge; without a value the fixed baseline 0. */
12
+ baseline?: Accessor<T>;
13
+ /** Binding to an x axis (R-4.12). */
14
+ xAxisId?: string;
15
+ /** Binding to a y axis (R-4.12). */
16
+ yAxisId?: string;
17
+ /** Series-own data; overrides the container data (R-2.4). */
18
+ data?: readonly T[];
19
+ /** The name in legend and tooltip. Without one the series is called
20
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
21
+ nobody can look up. */
22
+ name?: string;
23
+ /** Any CSS colour value; without one the palette --uc-series-N. */
24
+ color?: string;
25
+ /** Opacity of the fill; the outline stays fully opaque. */
26
+ fillOpacity?: number;
27
+ /** Width of the outline along the upper edge; 0 leaves it out. */
28
+ strokeWidth?: number;
29
+ }
30
+
31
+ export declare interface AreaSeriesConfig<T = unknown> extends SeriesBase<T> {
32
+ kind: "area";
33
+ /** Lower edge; without a value the fixed baseline 0. */
34
+ baseline?: Accessor<T>;
35
+ /** Opacity of the fill; the outline stays fully opaque. */
36
+ fillOpacity: number;
37
+ strokeWidth: number;
38
+ }
39
+
40
+ /** What the value is, given the limit set. A pure function of the two.
41
+
42
+ A missing or non-finite value yields `unknown` - and nothing else: the
43
+ deviation of a value nobody has is unknown to everybody too.
44
+
45
+ A bound is violated when the value lies beyond it, not when it lies on it. A
46
+ value exactly on the upper bound is in order. That is decided once here
47
+ (ADR-0006), so that two building blocks on the same screen do not disagree
48
+ about the edge.
49
+
50
+ Where several bounds are violated the most severe wins; among equally severe
51
+ ones the one the value lies furthest beyond. Under a tie in both, the one
52
+ named first.
53
+
54
+ No hysteresis: that would need the previous state, and a function of one
55
+ value has none. Exactly that is the property which makes this module safe to
56
+ duplicate. */
57
+ export declare function assess(value: number | null | undefined, set?: LimitSet): Assessment;
58
+
59
+ /** The verdict and what led to it. */
60
+ export declare interface Assessment {
61
+ verdict: Verdict;
62
+ /** The violated limit - the same object the caller passed in, so that it can
63
+ be recognised against the caller's own data. Absent where none is
64
+ violated. */
65
+ limit?: Limit;
66
+ /** The amount beyond the bound, always positive. Absent where none is
67
+ violated. */
68
+ excess?: number;
69
+ /** The signed distance from the target. Absent where none is set - a missing
70
+ target yields no deviation of zero.
71
+
72
+ Two fields and not one: excess and deviation are two numbers, and a single
73
+ field meaning the one thing when a bound is violated and the other
74
+ otherwise reads well and is wrong at three in the morning. */
75
+ deviation?: number;
76
+ }
77
+
78
+ export declare interface AxisConfig<T = unknown> {
79
+ id: string;
80
+ orientation: AxisOrientation;
81
+ position: AxisPosition;
82
+ accessor: (d: T, index: number) => number;
83
+ label?: string;
84
+ tickCount?: number;
85
+ tickFormat?: (v: number) => string;
86
+ domain: "nice" | "data" | readonly [number, number];
87
+ /** undefined = the default per R-4.15 (only the first registered axis per
88
+ orientation). */
89
+ grid?: boolean;
90
+ /** Fixed tick values instead of the 1-2-5 algorithm. For axes whose values are
91
+ not numbers but places: the lanes of a state stack, the categories of a
92
+ Pareto. */
93
+ ticks?: readonly number[];
94
+ /** Operating calendar: the intervals in which time counts. With it,
95
+ materialisation maps wall clock time onto operating time before the scale
96
+ calculates - the scale stays affine (ADR-0001). */
97
+ calendar?: readonly OperatingInterval[];
98
+ }
99
+
100
+ export declare type AxisOrientation = "x" | "y";
101
+
102
+ export declare type AxisPosition = "bottom" | "top" | "left" | "right";
103
+
104
+ export declare function Bar<T>(props: BarProps<T>): null;
105
+
106
+ export declare interface BarProps<T> {
107
+ /** Height; null/undefined/NaN means a gap (R-2.5). */
108
+ accessor: Accessor<T>;
109
+ /** Binding to an x axis (R-4.12). */
110
+ xAxisId?: string;
111
+ /** Binding to a y axis (R-4.12). */
112
+ yAxisId?: string;
113
+ /** Series-own data; overrides the container data (R-2.4). */
114
+ data?: readonly T[];
115
+ /** The name in legend and tooltip. Without one the series is called
116
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
117
+ nobody can look up. */
118
+ name?: string;
119
+ /** Any CSS colour value; without one the palette --uc-series-N. */
120
+ color?: string;
121
+ /** Width as a fraction of the step; just under 1, so that neighbours do not
122
+ touch. Several bar series share this fraction. */
123
+ barWidth?: number;
124
+ }
125
+
126
+ export declare interface BarSeriesConfig<T = unknown> extends SeriesBase<T> {
127
+ kind: "bar";
128
+ /** Width as a fraction of the step; the group shares this fraction. */
129
+ barWidth: number;
130
+ }
131
+
132
+ /** The breaks in operating time that lie within the extent [from, to] - what the
133
+ axis must mark, in domain units. */
134
+ export declare function breaks(input: CalendarInput, from: number, to: number): number[];
135
+
136
+ /** Calendar from an input - a built calendar is passed straight through, a raw
137
+ list is built once and remembered. */
138
+ export declare function calendarFrom(input: CalendarInput): OperatingCalendar;
139
+
140
+ /** Every function of this module takes either: the raw list as it stands on the
141
+ axis, or the calendar built from it. */
142
+ export declare type CalendarInput = OperatingCalendar | readonly OperatingInterval[];
143
+
144
+ export declare function Chart<T>(props: ChartProps<T>): ReactNode;
145
+
146
+ /** Measurements of the instrumentation for the benchmark page (R-5.1). */
147
+ export declare interface ChartPerf {
148
+ materializeMs: number;
149
+ seriesDrawMs: number;
150
+ points: number;
151
+ }
152
+
153
+ export declare interface ChartProps<T> {
154
+ /** Shared data basis (required); access only through accessors (R-2.4). */
155
+ data: readonly T[];
156
+ /** Width in CSS pixels, or `"100%"` for the host's. Without a value the chart
157
+ measures its host and follows it through a ResizeObserver. */
158
+ width?: number | "100%";
159
+ /** Height in CSS pixels. Without a value the chart takes its host's, which
160
+ then has to have one - a chart in a box of height 0 draws nothing. */
161
+ height?: number;
162
+ /** Outer spacing of the plot area in CSS pixels. */
163
+ padding?: number | Partial<Padding>;
164
+ /** Required in DEV through a warning (R-7.6). */
165
+ ariaLabel?: string;
166
+ /** Goes to the root element, as it does everywhere in this workspace. */
167
+ className?: string;
168
+ /** Goes to the root element. The plot area is measured, never styled from
169
+ here: a height set past the component is a height the scene does not know
170
+ about. */
171
+ style?: CSSProperties;
172
+ /** Instrumentation for the benchmark page (R-5.1); not needed otherwise. */
173
+ onPerf?: (perf: ChartPerf) => void;
174
+ /** The axes, series and companions of this chart. They draw nothing
175
+ themselves: each registers its configuration and the scene draws it
176
+ (R-2.1), and the order in the JSX is the drawing order. */
177
+ children?: ReactNode;
178
+ }
179
+
180
+ declare interface CommonProps {
181
+ /** Axis on which the value lies. */
182
+ axisId?: string;
183
+ /** Whether the value lies on the x or on the y axis. Without one, y: a limit
184
+ is nearly always a value and not a moment. */
185
+ orientation?: "x" | "y";
186
+ /** Two severities, not five: five urgencies are five colours, and five colours
187
+ on a plant screen are noise. */
188
+ severity?: Severity;
189
+ /** What the value means. A line at 90 does not say what 90 is. */
190
+ label?: string;
191
+ /** Any CSS colour value, in place of the one the severity yields. A colour
192
+ handed in instead of a severity puts the rule in the application and the
193
+ presentation in the library, and the two drift apart as soon as a bound
194
+ moves - so this is for the case that has no severity, not for taste. */
195
+ color?: string;
196
+ /** Whether the value widens the axis extent, so that the limit is certainly
197
+ visible. Default true; the head of this file says why. */
198
+ inExtent?: boolean;
199
+ /** A chosen specification limit (the default) or a calculated control limit.
200
+ They look different because they mean different things (ADR-0008). */
201
+ role?: LimitRole;
202
+ }
203
+
204
+ declare interface CommonProps_2<T> {
205
+ /** Axis id, through which series bind themselves (R-4.12). */
206
+ id?: string;
207
+ /** Value access of this axis. */
208
+ accessor: (d: T, index: number) => number;
209
+ /** Axis title. */
210
+ label?: string;
211
+ /** Target value; the 1-2-5 algorithm may deviate. */
212
+ tickCount?: number;
213
+ tickFormat?: (v: number) => string;
214
+ domain?: "nice" | "data" | readonly [number, number];
215
+ /** Grid lines; the default follows R-4.15. */
216
+ grid?: boolean;
217
+ /** Fixed tick values instead of the 1-2-5 algorithm. For axes whose values are
218
+ places and not numbers: the lanes of a state stack, the categories of a
219
+ Pareto. */
220
+ ticks?: readonly number[];
221
+ }
222
+
223
+ export declare function ControlChart<T>(props: ControlChartProps<T>): ReactNode;
224
+
225
+ export declare interface ControlChartProps<T> {
226
+ /** The values of the chart. */
227
+ accessor: Accessor<T>;
228
+ /** Required: the limits arise out of these values, not out of what happens to
229
+ be visible. */
230
+ data: readonly T[];
231
+ /** Given, or from a named reference window - never tacitly from everything on
232
+ the screen (ADR-0008). */
233
+ origin: ControlLimitOrigin;
234
+ /** Binding to an x axis (R-4.12). */
235
+ xAxisId?: string;
236
+ /** Binding to a y axis (R-4.12). */
237
+ yAxisId?: string;
238
+ /** The name in legend and tooltip. Without one the series is called
239
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
240
+ nobody can look up. */
241
+ name?: string;
242
+ /** Any CSS colour value; without one the palette --uc-series-N. */
243
+ color?: string;
244
+ /** Switchable one by one; run lengths are parameters. */
245
+ rules?: Partial<RuleOptions>;
246
+ /** The faint zone lines at one and two sigma. Rule 4 is about the two-sigma
247
+ zone; without them a reader cannot check it. */
248
+ zoneLines?: boolean;
249
+ /** Labels of the control limits in the axis band. Without a value, none: the
250
+ package brings no text along, not even "UCL" and "LCL". */
251
+ labelUpper?: string;
252
+ /** The same for the lower control limit. Named separately because a chart may
253
+ well want one of the two labelled and not the other. */
254
+ labelLower?: string;
255
+ /** Name of the scatter of violations in the legend and the tooltip. Without a
256
+ value, none: a legend then carries it as "Series n" and warns once in DEV.
257
+ Before this, a German suffix stood on the name of the chart. */
258
+ violationName?: string;
259
+ /** The violations as data - they can be listed beside the chart as well as
260
+ marked on it. */
261
+ onViolations?: (found: readonly Violation[]) => void;
262
+ }
263
+
264
+ /** Where the limits come from. There are exactly these two possibilities. */
265
+ export declare type ControlLimitOrigin =
266
+ /** From a baseline the caller has fixed. Taken as it is - even where the
267
+ series would yield something else out of itself. */
268
+ {
269
+ readonly kind: "given";
270
+ readonly center: number;
271
+ readonly sigma: number;
272
+ }
273
+ /** From exactly this index range of the series, half-open [from, to). */
274
+ | {
275
+ readonly kind: "referenceWindow";
276
+ readonly from: number;
277
+ readonly to: number;
278
+ };
279
+
280
+ /** Centre line, estimated spread and the control limits at three sigma. */
281
+ export declare interface ControlLimits {
282
+ readonly center: number;
283
+ /** Estimated spread of a single value, not the distance to the limit. */
284
+ readonly sigma: number;
285
+ readonly upper: number;
286
+ readonly lower: number;
287
+ }
288
+
289
+ /** Centre line and control limits. Either given or calculated from exactly the
290
+ named reference window - never from the whole series and never from the
291
+ visible excerpt. Gaps (NaN) count neither in the centre line nor in the
292
+ moving range. A window without values yields NaN limits, not an error: the
293
+ chart then draws no line instead of bursting. */
294
+ export declare function controlLimits(values: readonly number[], origin: ControlLimitOrigin): ControlLimits;
295
+
296
+ export declare const DAY: number;
297
+
298
+ /** Default gradient: a sequential set, light to dark, so that it stays readable
299
+ as an order of lightness even without colour. It is a default, not a
300
+ restriction - whoever has a scale of their own names it. */
301
+ export declare const DEFAULT_GRADIENT: readonly string[];
302
+
303
+ /** All four rules, with Nelson's run lengths: nine points on one side, six
304
+ points in succession rising or falling. Western Electric counts eight; both
305
+ lengths are therefore parameters. */
306
+ export declare const defaultRules: RuleOptions;
307
+
308
+ export declare const HOUR: number;
309
+
310
+ /** Explicit invalidation: devalue the cache, every living chart reads anew and
311
+ redraws. */
312
+ export declare function invalidateTheme(): void;
313
+
314
+ export declare function Legend({ placement }: LegendProps): ReactNode;
315
+
316
+ export declare interface LegendConfig {
317
+ placement: "top" | "bottom";
318
+ }
319
+
320
+ export declare interface LegendProps {
321
+ /** Which side of the plot area the legend stands on. Without a value, below
322
+ it. */
323
+ placement?: "top" | "bottom";
324
+ }
325
+
326
+ /** A bound: a value, a side and a severity. No more - a tolerance band is
327
+ derived and never an input (two limits of equal severity on opposite sides
328
+ enclose one). That keeps the one-sided case, which is the more common one,
329
+ free of a `null` on the other edge. */
330
+ export declare interface Limit {
331
+ value: number;
332
+ side: Side;
333
+ severity: Severity;
334
+ }
335
+
336
+ export declare function LimitBand(props: LimitBandProps): null;
337
+
338
+ export declare interface LimitBandConfig extends LimitBase {
339
+ kind: "band";
340
+ from: number;
341
+ to: number;
342
+ }
343
+
344
+ export declare interface LimitBandProps extends CommonProps {
345
+ /** Lower edge of the band, in domain units of its axis. */
346
+ from: number;
347
+ /** Upper edge. A band drawn backwards (`from` above `to`) is drawn between
348
+ the two all the same - the pair is a range, not a direction. */
349
+ to: number;
350
+ }
351
+
352
+ declare interface LimitBase {
353
+ /** Axis on which the value lies. */
354
+ axisId: string;
355
+ orientation: AxisOrientation;
356
+ severity: Severity;
357
+ role: LimitRole;
358
+ label?: string;
359
+ /** A colour of its own; without one, that of the role or of the severity out of
360
+ the theme. */
361
+ color?: string;
362
+ /** Pulls the extent of the axis along. Default true: an excluded limit yields a
363
+ chart that looks right and does not show its most important line - and that
364
+ nobody notices. A squashed plot is noticed at once. */
365
+ inExtent: boolean;
366
+ }
367
+
368
+ export declare type LimitConfig = LimitLineConfig | LimitBandConfig;
369
+
370
+ export declare function LimitLine(props: LimitLineProps): null;
371
+
372
+ export declare interface LimitLineConfig extends LimitBase {
373
+ kind: "line";
374
+ value: number;
375
+ }
376
+
377
+ export declare interface LimitLineProps extends CommonProps {
378
+ /** Where the line lies, in domain units of its axis. */
379
+ value: number;
380
+ }
381
+
382
+ /** What a limit stands for. The difference is not cosmetic: a specification
383
+ limit is chosen (what the customer assumes), a control limit is calculated
384
+ (what the process normally does). A process can be in control and outside the
385
+ specification and the other way round, and each of the four cases calls for
386
+ something different - which is why the two lines have to look
387
+ distinguishable (ADR-0008). */
388
+ export declare type LimitRole = "specification" | "control" | "zone";
389
+
390
+ /** The set a value is read against: its bounds and, where there is one, its
391
+ target.
392
+
393
+ The target is not a limit. It is missed, never violated, and it is never the
394
+ edge of a region. Conflating the two is how a tile turns red for being above
395
+ target. */
396
+ export declare interface LimitSet {
397
+ /** In any order; none, one or several. */
398
+ limits?: readonly Limit[];
399
+ target?: number;
400
+ }
401
+
402
+ export declare function Line<T>(props: LineProps<T>): null;
403
+
404
+ export declare class LinearScale implements Scale {
405
+ readonly domain: readonly [number, number];
406
+ readonly range: readonly [number, number];
407
+ /** Pre-computed line equation px = v·m + b - the draw loop uses it directly. */
408
+ readonly m: number;
409
+ readonly b: number;
410
+ constructor(domain: readonly [number, number], range: readonly [number, number]);
411
+ toPx(v: number): number;
412
+ fromPx(px: number): number;
413
+ ticks(n: number): number[];
414
+ }
415
+
416
+ export declare interface LineProps<T> {
417
+ /** Y value; null/undefined/NaN means a gap (R-2.5). */
418
+ accessor: Accessor<T>;
419
+ /** Binding to an x axis (R-4.12). */
420
+ xAxisId?: string;
421
+ /** Binding to a y axis (R-4.12). */
422
+ yAxisId?: string;
423
+ /** Series-own data; overrides the container data (R-2.4). */
424
+ data?: readonly T[];
425
+ /** The name in legend and tooltip. Without one the series is called
426
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
427
+ nobody can look up. */
428
+ name?: string;
429
+ /** Any CSS colour value; without one the palette --uc-series-N. */
430
+ color?: string;
431
+ /** A role instead of a colour value; the theme resolves it. */
432
+ tone?: "ok" | "warning" | "alarm";
433
+ /** Line width in CSS pixels. */
434
+ strokeWidth?: number;
435
+ /** Dash pattern as a run of lengths in CSS pixels; without one a solid line. */
436
+ dash?: readonly number[];
437
+ /** When the individual points are drawn as marks: `auto` from a density at
438
+ which they no longer run into each other, `always`, `never`. */
439
+ markers?: "auto" | "always" | "never";
440
+ }
441
+
442
+ export declare interface LineSeriesConfig<T = unknown> extends SeriesBase<T> {
443
+ kind: "line";
444
+ strokeWidth: number;
445
+ dash?: readonly number[];
446
+ markers: "auto" | "always" | "never";
447
+ }
448
+
449
+ /** Map a whole series inwards - the route materialisation takes when it wants to
450
+ go it in one piece. Only the first n values are touched. */
451
+ export declare function mapSeries(input: CalendarInput, source: Float64Array, n: number, target: Float64Array): void;
452
+
453
+ /** Materialised series: the draw loop works only on this (R-2.7).
454
+ Gaps (null/undefined/NaN out of the accessor) are encoded as NaN (R-2.5). */
455
+ export declare interface MaterializedSeries {
456
+ x: Float64Array;
457
+ y: Float64Array;
458
+ /** Lower edge, where the baseline is an accessor of its own; otherwise null.
459
+ A fixed baseline needs no channel - it is a number (R-2.7). */
460
+ y0: Float64Array | null;
461
+ /** Value channel: the third value per point, which today only the matrix
462
+ needs. Named rather than overloading y0 - a property that only some kinds
463
+ carry does not belong in the shared type with a comment (ADR-0011). null
464
+ for every kind that does not use it. */
465
+ w: Float64Array | null;
466
+ /** Second x channel: the end of a span. Named for the same reason.
467
+ NaN here does not mean a gap but open (ADR-0011). */
468
+ x1: Float64Array | null;
469
+ length: number;
470
+ }
471
+
472
+ export declare function Matrix<T>(props: MatrixProps<T>): null;
473
+
474
+ /** How a matrix colours its cells. Discretely by assessment - the same limits
475
+ that colour a tile - or across a gradient. */
476
+ export declare type MatrixColoring = {
477
+ kind: "assessment";
478
+ limits: LimitSet;
479
+ } | {
480
+ kind: "gradient";
481
+ /** Colour stops from small to large; at least two. The stops ARE the
482
+ steps - the library does not interpolate between them, because that
483
+ would mean a colour parser for arbitrary CSS colour values, which this
484
+ package does not have and is not to get (ADR-0011). Whoever wants a
485
+ finer gradation names more colours. */
486
+ stops: readonly string[];
487
+ /** Value range of the gradient; without a value taken from the data. */
488
+ range?: readonly [number, number];
489
+ };
490
+
491
+ export declare interface MatrixProps<T> {
492
+ /** Row position on the y axis. */
493
+ accessor: Accessor<T>;
494
+ /** The value that decides the colour. */
495
+ value: Accessor<T>;
496
+ /** Without a value the default gradient across the data range. */
497
+ coloring?: MatrixColoring;
498
+ /** Binding to an x axis (R-4.12). */
499
+ xAxisId?: string;
500
+ /** Binding to a y axis (R-4.12). */
501
+ yAxisId?: string;
502
+ /** Series-own data; overrides the container data (R-2.4). */
503
+ data?: readonly T[];
504
+ /** The name in legend and tooltip. Without one the series is called
505
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
506
+ nobody can look up. */
507
+ name?: string;
508
+ }
509
+
510
+ export declare interface MatrixSeriesConfig<T = unknown> extends SeriesBase<T> {
511
+ kind: "matrix";
512
+ /** The value that decides the colour - the third channel (ADR-0011).
513
+ The base accessor yields the row position, not this value. */
514
+ value: Accessor<T>;
515
+ coloring: MatrixColoring;
516
+ }
517
+
518
+ export declare const MINUTE: number;
519
+
520
+ /** An operating calendar: sorted, merged intervals with the operating time
521
+ accumulated before each one begins. An empty calendar is no calendar: it maps
522
+ unchanged.
523
+
524
+ Build once, then pass around: the mapping runs once per point, and were it to
525
+ sort and accumulate every time, the calendar would be the most expensive
526
+ thing about the frame. */
527
+ export declare interface OperatingCalendar {
528
+ readonly intervals: readonly OperatingInterval[];
529
+ /** Operating time accumulated before the respective interval begins. */
530
+ readonly offsets: readonly number[];
531
+ /** The whole operating time - the axis' extent is [0, total]. */
532
+ readonly total: number;
533
+ }
534
+
535
+ /** Builds a calendar: sorts, merges overlapping and abutting intervals and
536
+ throws away empty, reversed and non-finite ones. Merging is not a courtesy
537
+ but a precondition: only over separated intervals is the reverse mapping
538
+ unambiguous. */
539
+ export declare function operatingCalendar(intervals: readonly OperatingInterval[]): OperatingCalendar;
540
+
541
+ /** An interval in which time counts; thought of as half-open, but mappable from
542
+ both sides at its edges: both `from` and `to` have an operating time. */
543
+ export declare interface OperatingInterval {
544
+ readonly from: number;
545
+ readonly to: number;
546
+ }
547
+
548
+ /** Tick values for an axis extent that already stands in OPERATING TIME - the
549
+ route the axis layout takes.
550
+
551
+ The extent is trimmed to the operating time that exists (an extent widened to
552
+ nice boundaries reaches beyond it), calculated back into wall clock time, and
553
+ the candidates arise there. The step comes from the span in operating time and
554
+ not from the one in wall clock time: roughly one candidate per step of
555
+ operating time survives, and calculated from the wall clock span, four out of
556
+ ten wanted ticks would be left. */
557
+ export declare function operatingTicks(input: CalendarInput, from: number, to: number, count: number, offset?: number): number[];
558
+
559
+ /** A tick: where it stands on the clock and where it lies on the axis. */
560
+ export declare interface OperatingTimeTick {
561
+ readonly wallClock: number;
562
+ readonly operatingTime: number;
563
+ }
564
+
565
+ /** Ticks for an operating time axis, from an extent in WALL CLOCK TIME.
566
+
567
+ The candidates arise in wall clock time on multiples of the step - hours,
568
+ shift changes, days - whatever lies in removed time falls away, the rest is
569
+ mapped. Never the other way round: ticks generated in operating time land in
570
+ the middle of a shift and yield an axis labelled 14.5 and 29.0 which nobody
571
+ can read.
572
+
573
+ The offset shifts the grid; with it a local time hits its own midnight without
574
+ this module having to know about time zones.
575
+
576
+ If two candidates fall on the same operating time - the end of one shift and
577
+ the beginning of the next - the earlier one stays: two labels on the same
578
+ pixel would be one too many.
579
+
580
+ Both times come back, because the axis needs both: the operating time to
581
+ place the tick, the wall clock time to label it. */
582
+ export declare function operatingTimeTicks(input: CalendarInput, from: number, to: number, step: number, offset?: number): OperatingTimeTick[];
583
+
584
+ export declare interface Padding {
585
+ top: number;
586
+ right: number;
587
+ bottom: number;
588
+ left: number;
589
+ }
590
+
591
+ /** Sorts descending, accumulates, collects the tail and finds the cutoff
592
+ crossing.
593
+
594
+ Ties keep the input order - explicitly through the input index, not in
595
+ reliance on a stable sort - so that two reasons with the same count do not
596
+ swap places between two frames.
597
+
598
+ The remainder stands last, independently of its value. Two hundred small
599
+ reasons regularly yield a remainder larger than the third real bar; sorted
600
+ into place, the chart would claim there is a fault reason called "other"
601
+ which is the third biggest problem. */
602
+ export declare function pareto(items: readonly ParetoItem[], options?: ParetoSettings): ParetoResult;
603
+
604
+ export declare const paretoDefaults: Omit<ParetoOptions, "remainderName">;
605
+
606
+ /** An item, the way it is drawn. */
607
+ export declare interface ParetoEntry {
608
+ readonly name: string;
609
+ readonly value: number;
610
+ /** Category and at the same time x value: category n lies at x = n
611
+ (ADR-0002). */
612
+ readonly index: number;
613
+ /** Share of the total, 0…1. */
614
+ readonly share: number;
615
+ /** Cumulative share up to and including this entry, 0…1. Exactly 1 at the
616
+ last entry. */
617
+ readonly cumulative: number;
618
+ /** The collected tail. Exactly one entry can be this, and it always stands
619
+ last. */
620
+ readonly remainder: boolean;
621
+ }
622
+
623
+ /** An item, the way the caller counts it. */
624
+ export declare interface ParetoItem {
625
+ readonly name: string;
626
+ readonly value: number;
627
+ }
628
+
629
+ export declare interface ParetoOptions {
630
+ /** The share whose crossing is sought. Whoever lands exactly on it counts as
631
+ the crossing: the question is "which reasons make up eighty per cent", and
632
+ whoever reaches eighty exactly belongs to them. */
633
+ readonly cutoff: number;
634
+ /** How many items stay on their own. Everything behind that becomes a single
635
+ entry. Beyond the number of items no remainder arises at all - not an empty
636
+ one. Default: infinity, so no collecting. */
637
+ readonly collectRank: number;
638
+ /** Name of the collected remainder. `@umriss-ui/charts` has no wording module
639
+ - every string it draws comes from the caller - and no module is introduced
640
+ for a single label. Hence no default either: until library-audit 03 the
641
+ default here was "Sonstige", the one German word the package brought along
642
+ itself. */
643
+ readonly remainderName?: string;
644
+ }
645
+
646
+ export declare interface ParetoResult {
647
+ readonly entries: readonly ParetoEntry[];
648
+ /** Total of the drawn entries - after collecting, the same as before. */
649
+ readonly total: number;
650
+ /** Index of the first entry whose cumulative share reaches the cutoff; -1
651
+ when it is never reached. */
652
+ readonly cutoffIndex: number;
653
+ }
654
+
655
+ /** What a call may specify: a collect rank only together with the name of the
656
+ remainder it creates. */
657
+ export declare type ParetoSettings = {
658
+ readonly cutoff?: number;
659
+ } & ({
660
+ readonly collectRank?: undefined;
661
+ readonly remainderName?: undefined;
662
+ } | {
663
+ readonly collectRank: number;
664
+ readonly remainderName: string;
665
+ });
666
+
667
+ export declare interface Rect {
668
+ x: number;
669
+ y: number;
670
+ width: number;
671
+ height: number;
672
+ }
673
+
674
+ /** The removed spans between the operating intervals, for the mark in the axis
675
+ band. A chart that takes a weekend out and does not say so claims a
676
+ continuity it does not have. Before the first and after the last interval
677
+ there is nothing to mark: that lies outside the axis' extent. */
678
+ export declare function removedIntervals(input: CalendarInput): RemovedSpan[];
679
+
680
+ /** A removed span and the place it collapses onto. */
681
+ export declare interface RemovedSpan {
682
+ readonly from: number;
683
+ readonly to: number;
684
+ /** Operating time on which the whole span lies - a point, not a stretch. */
685
+ readonly operatingTime: number;
686
+ }
687
+
688
+ export declare interface ResolvedTheme {
689
+ colorAxis: string;
690
+ colorGrid: string;
691
+ colorText: string;
692
+ colorBg: string;
693
+ /** Colours of the two limit severities. A limit carries the colour of its
694
+ severity, not that of its series - it belongs to none. */
695
+ colorWarning: string;
696
+ colorAlarm: string;
697
+ /** The third outcome of an assessment. "unknown" deliberately has no
698
+ colour: a missing value becomes a hole like every gap in this library, and
699
+ a hole carries no colour, because a colour would be a claim. */
700
+ colorOk: string;
701
+ font: string;
702
+ fontMono: string;
703
+ series: readonly string[];
704
+ }
705
+
706
+ /** Name of a rule, the way it is switched on and off in `violations`. */
707
+ export declare type RuleName = "outlier" | "run" | "trend" | "twoOfThree";
708
+
709
+ /** Which rules run, and with which run lengths. */
710
+ export declare interface RuleOptions {
711
+ readonly outlier: boolean;
712
+ readonly run: boolean;
713
+ readonly trend: boolean;
714
+ readonly twoOfThree: boolean;
715
+ /** Points on one side of the centre line from which rule 2 fires. */
716
+ readonly runLength: number;
717
+ /** Points in succession from which rule 3 fires. */
718
+ readonly trendLength: number;
719
+ }
720
+
721
+ /** Rule 1 (Nelson 1, Western Electric 1): one point beyond three sigma.
722
+ Beyond, not on it - a point exactly on the limit violates nothing. */
723
+ export declare function ruleOutlier(values: readonly number[], limits: ControlLimits): number[];
724
+
725
+ /** Rule 2 (Nelson 2): a run of points on one side of the centre line. The
726
+ default length is nine - Nelson. Western Electric counts eight; that is why
727
+ the length is a parameter and not a literal, so that a works with a rule of
728
+ its own need not argue with the library. */
729
+ export declare function ruleRun(values: readonly number[], limits: ControlLimits, length?: number): number[];
730
+
731
+ /** Rule 3 (Nelson 3): a run of nothing but rises or nothing but falls. The
732
+ default length is six points, so five steps - Nelson. Two equal values are
733
+ neither a rise nor a fall and break the run. */
734
+ export declare function ruleTrend(values: readonly number[], length?: number): number[];
735
+
736
+ /** Rule 4 (Nelson 5): two of three consecutive points beyond two sigma on the
737
+ same side. Reported are the points beyond the zone, not the one in between -
738
+ that one is unremarkable and, marked, would look like a measurement error. */
739
+ export declare function ruleTwoOfThree(values: readonly number[], limits: ControlLimits): number[];
740
+
741
+ export declare interface Scale {
742
+ domain: readonly [number, number];
743
+ range: readonly [number, number];
744
+ /** Affine coefficients of the mapping px = v·m + b.
745
+
746
+ They stand in the interface because the drawing code reads them and
747
+ computes inline in the point loop instead of calling toPx() per point -
748
+ that is what carries 60 fps at millions of points. Every scale of this
749
+ library is affine; see docs/adr/0001-affine-scale-contract.md, which also
750
+ says what a later log scale would cost. */
751
+ readonly m: number;
752
+ readonly b: number;
753
+ toPx(v: number): number;
754
+ fromPx(px: number): number;
755
+ ticks(n: number): number[];
756
+ }
757
+
758
+ export declare function Scatter<T>(props: ScatterProps<T>): null;
759
+
760
+ export declare interface ScatterProps<T> {
761
+ /** Y value; null/undefined/NaN means a gap (R-2.5). */
762
+ accessor: Accessor<T>;
763
+ /** Binding to an x axis (R-4.12). */
764
+ xAxisId?: string;
765
+ /** Binding to a y axis (R-4.12). */
766
+ yAxisId?: string;
767
+ /** Series-own data; overrides the container data (R-2.4). */
768
+ data?: readonly T[];
769
+ /** The name in legend and tooltip. Without one the series is called
770
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
771
+ nobody can look up. */
772
+ name?: string;
773
+ /** Any CSS colour value; without one the palette --uc-series-N. */
774
+ color?: string;
775
+ /** A role instead of a colour value; the theme resolves it. */
776
+ tone?: "ok" | "warning" | "alarm";
777
+ /** Point radius in CSS pixels. */
778
+ radius?: number;
779
+ }
780
+
781
+ export declare interface ScatterSeriesConfig<T = unknown> extends SeriesBase<T> {
782
+ kind: "scatter";
783
+ /** Point radius in CSS pixels. */
784
+ radius: number;
785
+ }
786
+
787
+ export declare const SECOND = 1000;
788
+
789
+ export declare interface SeriesBase<T = unknown> {
790
+ /** Y value; null/undefined/NaN means a gap (R-2.5). */
791
+ accessor: Accessor<T>;
792
+ /** Series-own data; overrides the container data (R-2.4). */
793
+ data?: readonly T[];
794
+ xAxisId: string;
795
+ yAxisId: string;
796
+ name?: string;
797
+ color?: string;
798
+ /** A role instead of a colour value: the theme resolves it, in both themes.
799
+ For series that mean something rather than just being the next one - the
800
+ violating points of a control chart, say. `color` beats it. */
801
+ tone?: "ok" | "warning" | "alarm";
802
+ }
803
+
804
+ export declare type SeriesConfig<T = unknown> = LineSeriesConfig<T> | AreaSeriesConfig<T> | BarSeriesConfig<T> | ScatterSeriesConfig<T> | StateSeriesConfig<T> | MatrixSeriesConfig<T> | SpanSeriesConfig<T>;
805
+
806
+ export declare type SeriesKind = SeriesConfig["kind"];
807
+
808
+ /** How seriously a violation weighs. Exactly two: one severity that advises and
809
+ one that calls for action. Five severities would be five colours, and five
810
+ colours on a control room screen are noise. Whoever needs a third
811
+ distinction sets a second limit. */
812
+ export declare type Severity = "warning" | "alarm";
813
+
814
+ /** Whether a limit is an upper or a lower bound. */
815
+ export declare type Side = "upper" | "lower";
816
+
817
+ /** Sigma calculated back from a limit that stands on paper. For callers whose
818
+ baseline has been handed down as a centre line and a control limit. */
819
+ export declare function sigmaFromLimit(center: number, upper: number): number;
820
+
821
+ export declare function Span<T>(props: SpanProps<T>): null;
822
+
823
+ export declare interface SpanProps<T> {
824
+ /** Lane position on the y axis. */
825
+ accessor: Accessor<T>;
826
+ /** End on the x axis. Missing means open: the span runs to the edge and is
827
+ drawn as open - a running job is a fact one wants to see. */
828
+ to: Accessor<T>;
829
+ /** Binding to an x axis (R-4.12). */
830
+ xAxisId?: string;
831
+ /** Binding to a y axis (R-4.12). */
832
+ yAxisId?: string;
833
+ /** Series-own data; overrides the container data (R-2.4). */
834
+ data?: readonly T[];
835
+ /** The name in legend and tooltip. Without one the series is called
836
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
837
+ nobody can look up. */
838
+ name?: string;
839
+ /** Any CSS colour value; without one the palette --uc-series-N. */
840
+ color?: string;
841
+ /** Height of a span as a fraction of one domain unit of the y axis. */
842
+ height?: number;
843
+ }
844
+
845
+ export declare interface SpanSeriesConfig<T = unknown> extends SeriesBase<T> {
846
+ kind: "span";
847
+ /** End of the span on the x axis. Missing means open: the span runs to the end
848
+ of the domain and is drawn as open. */
849
+ to: Accessor<T>;
850
+ /** Height of a span as a fraction of one domain unit of the y axis. */
851
+ height?: number;
852
+ }
853
+
854
+ export declare function StateBand<T>(props: StateBandProps<T>): null;
855
+
856
+ export declare interface StateBandProps<T> {
857
+ /** Index of the state in `states`; null/undefined/NaN is a gap - and a gap
858
+ stays a hole, it gets no colour for "unknown". A colour would be a claim
859
+ about the interval. */
860
+ accessor: Accessor<T>;
861
+ /** The closed set of states, in the order of their codes. */
862
+ states: readonly StateEntry[];
863
+ /** Binding to an x axis (R-4.12). */
864
+ xAxisId?: string;
865
+ /** Binding to a y axis (R-4.12). */
866
+ yAxisId?: string;
867
+ /** Series-own data; overrides the container data (R-2.4). */
868
+ data?: readonly T[];
869
+ /** The name in legend and tooltip. Without one the series is called
870
+ "Series n" and a warning stands in DEV - an unnamed series is a colour
871
+ nobody can look up. */
872
+ name?: string;
873
+ /** Lower edge of the lane in domain units of the y axis. */
874
+ laneFrom?: number;
875
+ /** Upper edge of the lane in domain units of the y axis. */
876
+ laneTo?: number;
877
+ }
878
+
879
+ /** One state of the closed set a state series knows. */
880
+ export declare interface StateEntry {
881
+ label: string;
882
+ color: string;
883
+ }
884
+
885
+ export declare interface StateSeriesConfig<T = unknown> extends SeriesBase<T> {
886
+ kind: "state";
887
+ /** The closed set of states. The accessor yields the index into it - a number,
888
+ not a key (ADR-0007). */
889
+ states: readonly StateEntry[];
890
+ /** Lower edge of the lane in domain units of the y axis; without a value the
891
+ beginning of the axis domain. */
892
+ laneFrom?: number;
893
+ /** Upper edge of the lane; without a value the end of the axis domain. */
894
+ laneTo?: number;
895
+ }
896
+
897
+ /** Step for tick candidates in wall clock time, at an intended count. Rounded up
898
+ to the next readable step, so that no more ticks arise than wanted. Above the
899
+ day steps it continues in whole days. */
900
+ export declare function timeStep(span: number, count: number): number;
901
+
902
+ export declare function Tooltip<T>(props: TooltipProps<T>): null;
903
+
904
+ export declare interface TooltipConfig<T = unknown> {
905
+ mode: "x" | "nearest";
906
+ render?: (hit: TooltipHit<T>) => ReactNode;
907
+ }
908
+
909
+ export declare interface TooltipHit<T = unknown> {
910
+ xValue: number;
911
+ points: readonly TooltipPoint<T>[];
912
+ /** Pixel position of the crosshair (snapped to the data point). */
913
+ xPx: number;
914
+ /** Pixel position of the primary hit. */
915
+ yPx: number;
916
+ }
917
+
918
+ /** One hit per series in the tooltip (R-4.4). */
919
+ export declare interface TooltipPoint<T = unknown> {
920
+ seriesName: string;
921
+ color: string;
922
+ yValue: number;
923
+ datum: T;
924
+ index: number;
925
+ /** Only for the matrix: the value out of the value channel. It stands here and
926
+ not in yValue, because yValue is the position on the y axis - for a matrix
927
+ therefore the row. Putting both into one field would be exactly the
928
+ overloading ADR-0011 is written against. */
929
+ value?: number;
930
+ /** Only for state series and spans: the section being pointed at.
931
+ A duration does not stand here - it is the difference of two numbers the
932
+ entry already carries, and formatting it would presuppose knowing what the
933
+ x axis means. The caller knows that, not this library. */
934
+ segment?: {
935
+ from: number;
936
+ to: number;
937
+ label: string;
938
+ open: boolean;
939
+ };
940
+ }
941
+
942
+ export declare interface TooltipProps<T> {
943
+ /** "x": every series at the x position; "nearest": only the nearest point. */
944
+ mode?: "x" | "nearest";
945
+ /** Render prop for content of one's own; without it the built-in tooltip
946
+ applies. */
947
+ render?: (hit: TooltipHit<T>) => ReactNode;
948
+ }
949
+
950
+ /** Wall clock time → operating time.
951
+
952
+ A point in a removed interval is a gap and becomes `NaN` - the encoding every
953
+ gap of this library already uses, and the drawing loop breaks the mark at it
954
+ of its own accord. Not the edge of the interval: a measurement from a time
955
+ which, according to the calendar, did not exist could not be laid there
956
+ honestly; it would pile up on what really does lie there. The same holds
957
+ before the first and after the last interval.
958
+
959
+ The end of one interval and the beginning of the next fall on the same value:
960
+ in operating time they are neighbours, and the line between two points on
961
+ either side is drawn. That is not a lie but the whole purpose of the axis; the
962
+ mark in the axis band tells the reader that time was taken out there. */
963
+ export declare function toOperatingTime(wallClock: number, input: CalendarInput): number;
964
+
965
+ /** Operating time → wall clock time; outside [0, total] there is none.
966
+
967
+ At a seam - the end of an interval which is at the same time the beginning of
968
+ the next - the beginning of the next comes out: from there time counts again,
969
+ and a pointer aiming there aims at the coming shift. Only the end of the last
970
+ interval has no next and comes back as itself. */
971
+ export declare function toWallClock(operatingTime: number, input: CalendarInput): number;
972
+
973
+ /** What a value is. Four outcomes, not three.
974
+
975
+ `unknown` is an outcome of its own and not a `null` return: a `null`
976
+ invites `?? "ok"` at the call site, and that very expression is the defect
977
+ this module exists to prevent. A value nobody has is a reason to look and
978
+ not a reason to relax. */
979
+ export declare type Verdict = "ok" | "unknown" | "warning" | "alarm";
980
+
981
+ /** How heavily a verdict weighs, as a number - for sorting and comparing, as
982
+ when a matrix is to bring its worst cell to the top. It stands here so that
983
+ the order is not reinvented at every call site. */
984
+ export declare function verdictWeight(verdict: Verdict): number;
985
+
986
+ /** All violated indices, ascending and free of duplicates - the scatter drawn
987
+ beside the line. */
988
+ export declare function violatedIndices(found: readonly Violation[]): number[];
989
+
990
+ /** A rule and the indices it violates. */
991
+ export declare interface Violation {
992
+ readonly rule: RuleName;
993
+ readonly indices: readonly number[];
994
+ }
995
+
996
+ /** The rules switched on, each with its indices. Rules without hits do not
997
+ appear in the list. The indices are data, not merely marks: they can be
998
+ listed beside the chart as well as marked on it. */
999
+ export declare function violations(values: readonly number[], limits: ControlLimits, options?: Partial<RuleOptions>): Violation[];
1000
+
1001
+ export declare function XAxis<T>(props: XAxisProps<T>): null;
1002
+
1003
+ export declare interface XAxisProps<T> extends CommonProps_2<T> {
1004
+ /** Which edge the axis stands at. A second x axis on the opposite edge is how
1005
+ a series counts in a unit of its own. */
1006
+ position?: "bottom" | "top";
1007
+ /** Operating calendar: the intervals in which time counts. With it the axis
1008
+ stands in operating time - weekends and night shifts are out, and every
1009
+ removed span gets a break mark. The scale stays affine; the mapping happens
1010
+ in materialisation (ADR-0001). */
1011
+ calendar?: readonly OperatingInterval[];
1012
+ }
1013
+
1014
+ export declare function YAxis<T>(props: YAxisProps<T>): null;
1015
+
1016
+ export declare interface YAxisProps<T> extends CommonProps_2<T> {
1017
+ /** Which edge the axis stands at. Several y axes per side are stacked
1018
+ outwards, so that extents of clearly different magnitude stay readable. */
1019
+ position?: "left" | "right";
1020
+ }
1021
+
1022
+ /** A zone line: k times sigma above and below the centre line. */
1023
+ export declare interface Zone {
1024
+ readonly k: number;
1025
+ readonly upper: number;
1026
+ readonly lower: number;
1027
+ }
1028
+
1029
+ /** The faintly drawn zone lines. Rule 4 is about the two-sigma zone, and a
1030
+ reader cannot check it against a chart that does not show it. */
1031
+ export declare function zones(limits: ControlLimits, multiples?: readonly number[]): Zone[];
1032
+
1033
+ export { }