@sinequa/atomic-angular 1.17.0 → 2.0.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.
- package/README.md +23 -18
- package/components/navbar-tabs/i18n/de.json +4 -2
- package/components/navbar-tabs/i18n/en.json +4 -2
- package/components/navbar-tabs/i18n/fr.json +5 -3
- package/components/preview/i18n/de.json +12 -0
- package/components/preview/i18n/en.json +12 -0
- package/components/preview/i18n/fr.json +12 -0
- package/components/sort-selector/i18n/de.json +1 -0
- package/components/sort-selector/i18n/en.json +1 -0
- package/components/sort-selector/i18n/fr.json +1 -0
- package/components/sponsored-results/i18n/de.json +3 -0
- package/components/sponsored-results/i18n/en.json +3 -0
- package/components/sponsored-results/i18n/fr.json +3 -0
- package/document-workspaces/i18n/de.json +2 -0
- package/document-workspaces/i18n/en.json +2 -0
- package/document-workspaces/i18n/fr.json +2 -0
- package/document-workspaces/i18n/ja.json +2 -0
- package/features/{drawer → advanced-search}/i18n/de.json +12 -1
- package/features/{drawer → advanced-search}/i18n/en.json +12 -1
- package/features/{drawer → advanced-search}/i18n/fr.json +13 -2
- package/features/alerts/i18n/de.json +7 -1
- package/features/alerts/i18n/en.json +7 -1
- package/features/alerts/i18n/fr.json +7 -1
- package/features/auth/i18n/de.json +6 -0
- package/features/auth/i18n/en.json +6 -0
- package/features/auth/i18n/fr.json +6 -1
- package/features/collections/i18n/de.json +4 -1
- package/features/collections/i18n/en.json +4 -1
- package/features/collections/i18n/fr.json +4 -1
- package/features/dialogs/i18n/de.json +11 -1
- package/features/dialogs/i18n/en.json +11 -1
- package/features/dialogs/i18n/fr.json +11 -1
- package/features/export/i18n/de.json +5 -1
- package/features/export/i18n/en.json +5 -1
- package/features/export/i18n/fr.json +5 -1
- package/features/feedback/i18n/de.json +2 -1
- package/features/feedback/i18n/en.json +2 -1
- package/features/feedback/i18n/fr.json +2 -1
- package/features/filters/i18n/de.json +10 -3
- package/features/filters/i18n/en.json +10 -3
- package/features/filters/i18n/fr.json +11 -4
- package/features/labels/i18n/de.json +5 -1
- package/features/labels/i18n/en.json +5 -1
- package/features/labels/i18n/fr.json +5 -1
- package/features/list-panel/i18n/de.json +4 -0
- package/features/list-panel/i18n/en.json +4 -0
- package/features/list-panel/i18n/fr.json +4 -0
- package/features/searches/i18n/de.json +2 -1
- package/features/searches/i18n/en.json +2 -1
- package/features/searches/i18n/fr.json +3 -2
- package/features/sheet/i18n/de.json +3 -0
- package/features/sheet/i18n/en.json +3 -0
- package/features/sheet/i18n/fr.json +3 -0
- package/features/user-profile/i18n/de.json +22 -1
- package/features/user-profile/i18n/en.json +22 -1
- package/features/user-profile/i18n/fr.json +22 -1
- package/fesm2022/sinequa-atomic-angular-charts-heatmap.mjs +294 -0
- package/fesm2022/sinequa-atomic-angular-charts-heatmap.mjs.map +1 -0
- package/fesm2022/sinequa-atomic-angular-charts.mjs +969 -0
- package/fesm2022/sinequa-atomic-angular-charts.mjs.map +1 -0
- package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs +11197 -7899
- package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs.map +1 -1
- package/fesm2022/sinequa-atomic-angular-workspace-elements.mjs +85 -152
- package/fesm2022/sinequa-atomic-angular-workspace-elements.mjs.map +1 -1
- package/fesm2022/sinequa-atomic-angular.mjs +30683 -17302
- package/fesm2022/sinequa-atomic-angular.mjs.map +1 -1
- package/package.json +60 -19
- package/styles/calendar.css +88 -0
- package/types/sinequa-atomic-angular-charts-heatmap.d.ts +154 -0
- package/types/sinequa-atomic-angular-charts.d.ts +462 -0
- package/types/sinequa-atomic-angular-document-workspaces.d.ts +2527 -0
- package/types/sinequa-atomic-angular-workspace-elements.d.ts +49 -0
- package/types/sinequa-atomic-angular.d.ts +19918 -0
- package/workspace-elements/styles/lexiq-workspaces.css +7310 -4010
- package/document-workspaces/index.d.ts +0 -2159
- package/index.d.ts +0 -16119
- package/workspace-elements/index.d.ts +0 -37
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { InputSignal, Signal } from "@angular/core";
|
|
3
|
+
import { ChartConfiguration, Plugin } from "chart.js";
|
|
4
|
+
import { AggregationLike } from "@sinequa/atomic-angular";
|
|
5
|
+
/**
|
|
6
|
+
* The Chart.js canvas, and the whole of its lifecycle.
|
|
7
|
+
*
|
|
8
|
+
* Every chart in this entry point is built on this one component. Chart.js has no Angular binding,
|
|
9
|
+
* so the integration work is entirely the canvas lifecycle — and that is where every bug lives.
|
|
10
|
+
* Four rules, all of them enforced here so no caller has to think about them:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Create after the first render.** A canvas created during construction has no layout and
|
|
13
|
+
* Chart.js measures it as 0x0. `afterNextRender` is the zoneless-safe hook.
|
|
14
|
+
* 2. **Always destroy.** Chart.js attaches a `ResizeObserver` and global listeners; leaking an
|
|
15
|
+
* instance leaks both.
|
|
16
|
+
* 3. **Rebuild when `type` changes.** Chart.js cannot swap controller on a live instance.
|
|
17
|
+
* 4. **Rebuild when the theme changes.** `Chart.defaults` is read at construction time only, so
|
|
18
|
+
* `update()` would leave the axes in the previous colour.
|
|
19
|
+
*
|
|
20
|
+
* Rules 3 and 4 are why this component owns an `effect()` — the only one in the entry point.
|
|
21
|
+
* Everything else is `computed()`.
|
|
22
|
+
*
|
|
23
|
+
* Named `ChartCanvas` rather than `Chart` deliberately: this file imports `Chart` from `chart.js`.
|
|
24
|
+
*
|
|
25
|
+
* **The host must have a resolved height.** The canvas fills its host and Chart.js sizes itself from
|
|
26
|
+
* the canvas' parent box, so put it in a container with a height (`class="h-80"`). A blank chart is
|
|
27
|
+
* nearly always this.
|
|
28
|
+
*/
|
|
29
|
+
export declare class ChartCanvasComponent {
|
|
30
|
+
cn: import("cn").CnFunction;
|
|
31
|
+
/**
|
|
32
|
+
* Extra classes for the host element.
|
|
33
|
+
* @default ""
|
|
34
|
+
*/
|
|
35
|
+
readonly class: InputSignal<string>;
|
|
36
|
+
/**
|
|
37
|
+
* The Chart.js configuration. Rebuilt automatically when its `type` changes.
|
|
38
|
+
*
|
|
39
|
+
* Explicitly annotated, like `plugins` below, and for a second reason on top of portability: an
|
|
40
|
+
* inferred type is emitted into the .d.ts with the default type arguments already expanded, which
|
|
41
|
+
* freezes the union of known chart types at the moment THIS entry point was compiled. A caller in
|
|
42
|
+
* another entry point that augments `chart.js` — `/charts/heatmap` registers the `matrix`
|
|
43
|
+
* controller — would then be handing over a `ChartConfiguration` that no longer matches. Keeping
|
|
44
|
+
* the annotation keeps the name in the .d.ts, so it re-resolves in the caller's own context.
|
|
45
|
+
*/
|
|
46
|
+
readonly config: InputSignal<ChartConfiguration>;
|
|
47
|
+
/**
|
|
48
|
+
* Local plugins, kept separate from `config.plugins` for readability. Build them once, outside any
|
|
49
|
+
* `computed()`: a plugin holding drag state would lose it on every recompute.
|
|
50
|
+
* @default []
|
|
51
|
+
*/
|
|
52
|
+
readonly plugins: InputSignal<Plugin[]>;
|
|
53
|
+
private readonly canvas;
|
|
54
|
+
private readonly destroyRef;
|
|
55
|
+
private readonly theme;
|
|
56
|
+
private chart?;
|
|
57
|
+
private currentType?;
|
|
58
|
+
private currentDark?;
|
|
59
|
+
constructor();
|
|
60
|
+
/**
|
|
61
|
+
* `responsive` and `maintainAspectRatio: false` are forced here: together they make the chart
|
|
62
|
+
* follow its container instead of a fixed 2:1 ratio, and no caller should have to remember them.
|
|
63
|
+
*/
|
|
64
|
+
private withDefaults;
|
|
65
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ChartCanvasComponent, never>;
|
|
66
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ChartCanvasComponent, "ChartCanvas, chart-canvas, chartcanvas", never, {
|
|
67
|
+
"class": {
|
|
68
|
+
"alias": "class";
|
|
69
|
+
"required": false;
|
|
70
|
+
"isSignal": true;
|
|
71
|
+
};
|
|
72
|
+
"config": {
|
|
73
|
+
"alias": "config";
|
|
74
|
+
"required": true;
|
|
75
|
+
"isSignal": true;
|
|
76
|
+
};
|
|
77
|
+
"plugins": {
|
|
78
|
+
"alias": "plugins";
|
|
79
|
+
"required": false;
|
|
80
|
+
"isSignal": true;
|
|
81
|
+
};
|
|
82
|
+
}, {}, never, never, true, never>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Registers the Chart.js controllers, scales and elements the charts need.
|
|
86
|
+
*
|
|
87
|
+
* Chart.js 4 ships nothing by default. This is idempotent on purpose: it is called from the
|
|
88
|
+
* constructor of every `<ChartCanvas>`, so it must be safe to call many times. Registering from a
|
|
89
|
+
* component rather than from application bootstrap keeps the entry point self-contained — an
|
|
90
|
+
* application that never imports `@sinequa/atomic-angular/charts` never runs this, and never needs
|
|
91
|
+
* `chart.js` installed.
|
|
92
|
+
*/
|
|
93
|
+
export declare function setupCharts(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Applies theme-dependent defaults: axis and legend text colour, and grid line colour.
|
|
96
|
+
*
|
|
97
|
+
* These read *semantic* galactik tokens, not primitive ramps — semantic tokens are exactly the ones
|
|
98
|
+
* `galactik-tokens-dark.css` reassigns under `:root.dark`, so the chart chrome follows the theme
|
|
99
|
+
* while series colours (built from primitives) keep their identity.
|
|
100
|
+
*
|
|
101
|
+
* Chart.js reads `Chart.defaults` when an instance is CONSTRUCTED, never afterwards. Calling
|
|
102
|
+
* `chart.update()` after a theme switch therefore leaves the axes in the previous colour — the
|
|
103
|
+
* instance has to be destroyed and rebuilt. `<ChartCanvas>` does exactly that.
|
|
104
|
+
*/
|
|
105
|
+
export declare function applyChartTheme(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Dark mode, exposed as a signal.
|
|
108
|
+
*
|
|
109
|
+
* galactik switches theme through a `dark` class on the document root (`:root.dark`), so this
|
|
110
|
+
* observes the DOM rather than depending on a particular store. That keeps the charts usable in any
|
|
111
|
+
* host application, whatever drives its theme.
|
|
112
|
+
*
|
|
113
|
+
* A canvas cannot react to a CSS class on its own: `<ChartCanvas>` reads this signal and rebuilds
|
|
114
|
+
* its Chart.js instance when it flips. See `applyChartTheme`.
|
|
115
|
+
*/
|
|
116
|
+
export declare class ChartThemeService {
|
|
117
|
+
private readonly dark;
|
|
118
|
+
/** `true` when the document root carries the `dark` class. Updates on its own. */
|
|
119
|
+
readonly isDark: Signal<boolean>;
|
|
120
|
+
constructor();
|
|
121
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ChartThemeService, never>;
|
|
122
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Creates the brush plugin.
|
|
126
|
+
*
|
|
127
|
+
* @param onSelect called on mouse release with the first and last category LABELS covered by the
|
|
128
|
+
* drag. Labels (not pixels, not dates) because the timeline uses a `category` axis:
|
|
129
|
+
* what the caller gets back is exactly what it put into `data.labels`.
|
|
130
|
+
*/
|
|
131
|
+
export declare function createTimelineBrushPlugin(onSelect: (from: string, to: string) => void): Plugin;
|
|
132
|
+
/** A click on an axis label: which axis, which category index, and the label as it was drawn. */
|
|
133
|
+
export interface AxisLabelHit {
|
|
134
|
+
readonly axis: "x" | "y";
|
|
135
|
+
/** Index of the category on that axis, i.e. its position in the scale's labels. */
|
|
136
|
+
readonly index: number;
|
|
137
|
+
readonly label: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Makes axis labels clickable — SBA v2's `axisClicked`, on a canvas.
|
|
141
|
+
*
|
|
142
|
+
* On a DOM chart (`<Heatmap>`) an axis label is a `<button>` and this is free. On a canvas it is
|
|
143
|
+
* painted pixels, so the hit test has to be written. Three things make it work, and each of them is
|
|
144
|
+
* a failure mode of the naive version:
|
|
145
|
+
*
|
|
146
|
+
* 1. **`options.onClick` cannot do this.** Chart.js only calls it when the pointer is inside
|
|
147
|
+
* `chartArea` (`Chart#_handleEvent`), and axis labels are outside it by construction. A
|
|
148
|
+
* plugin's `afterEvent` sees every event on the canvas, in or out of the area.
|
|
149
|
+
* 2. **No `options.events` change is needed**, unlike the timeline brush: `click`, `mousemove`
|
|
150
|
+
* and `mouseout` are already in the Chart.js default list — only `mousedown`/`mouseup` are not.
|
|
151
|
+
* 3. **Hit-test the scale's own box** (`scale.left/top/right/bottom`), not a band derived from
|
|
152
|
+
* `chartArea`. It is exactly the strip Chart.js reserved for that axis, the two axis boxes
|
|
153
|
+
* never overlap, and the corner between them — which belongs to neither — is excluded for free.
|
|
154
|
+
*
|
|
155
|
+
* Generic: any chart with a category axis can use it, not just the heatmap.
|
|
156
|
+
*
|
|
157
|
+
* @param onSelect called on a click over an axis label.
|
|
158
|
+
* @param axes which axes react. Defaults to both.
|
|
159
|
+
*/
|
|
160
|
+
export declare function createAxisClickPlugin(onSelect: (hit: AxisLabelHit) => void, axes?: ReadonlyArray<"x" | "y">): Plugin;
|
|
161
|
+
/**
|
|
162
|
+
* The date masks Sinequa uses for time aggregations. The mask is configured server-side on the
|
|
163
|
+
* aggregation and tells you the width of one bucket.
|
|
164
|
+
*/
|
|
165
|
+
export type TimelineMask = "YYYY" | "YYYY-MM" | "YYYY-WW" | "YYYY-MM-DD" | "YYYY-MM-DD-hh" | "YYYY-MM-DD-hh-mm";
|
|
166
|
+
/** One input series, before the shared axis is built. */
|
|
167
|
+
export interface TimelineSeriesInput {
|
|
168
|
+
readonly label: string;
|
|
169
|
+
/** Only primary series determine the extent of the axis; secondary ones are just plotted on it. */
|
|
170
|
+
readonly primary?: boolean;
|
|
171
|
+
/** Aggregation whose items are date buckets: `value` is the bucket key, `count` the measure. */
|
|
172
|
+
readonly aggregation: AggregationLike | undefined;
|
|
173
|
+
/** Read this operator result instead of `count` (e.g. "avg" for a response-time curve). */
|
|
174
|
+
readonly weightField?: string;
|
|
175
|
+
}
|
|
176
|
+
/** One output series, aligned on the shared axis: `values[i]` belongs to `labels[i]`. */
|
|
177
|
+
export interface TimelineSeries {
|
|
178
|
+
readonly label: string;
|
|
179
|
+
readonly primary: boolean;
|
|
180
|
+
readonly values: Array<number | null>;
|
|
181
|
+
}
|
|
182
|
+
export interface TimelineData {
|
|
183
|
+
readonly labels: string[];
|
|
184
|
+
readonly series: TimelineSeries[];
|
|
185
|
+
}
|
|
186
|
+
export interface TimelineOptions {
|
|
187
|
+
/** Bucket width. Without it, no gap filling happens: the axis is just the keys that exist. */
|
|
188
|
+
readonly mask?: TimelineMask;
|
|
189
|
+
/** Safety valve for generated buckets. A one-minute mask over a year would produce ~525 600. */
|
|
190
|
+
readonly maxBuckets?: number;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Builds a shared category axis and aligns every series onto it.
|
|
194
|
+
*
|
|
195
|
+
* The gap filling is the point. Without it, three days with no activity are not drawn as a flat
|
|
196
|
+
* line at zero -- they simply do not exist, and the line jumps straight from one populated day to
|
|
197
|
+
* the next, silently misrepresenting the data. SBA v2 did this in createDatapoints(); the comment
|
|
198
|
+
* there drew it as:
|
|
199
|
+
*
|
|
200
|
+
* aggregation: [ # # # # # # # # # # # ]
|
|
201
|
+
* series: [ 0 # # 0 0 # # # 0 # 0 0 # # 0 0 # # # 0 ]
|
|
202
|
+
*/
|
|
203
|
+
export declare function buildTimeline(inputs: readonly TimelineSeriesInput[], options?: TimelineOptions): TimelineData;
|
|
204
|
+
/**
|
|
205
|
+
* Parses a Sinequa bucket key: "2026", "2026-01", "2026-01-13", "2026-01-13 14:00:00", ...
|
|
206
|
+
*
|
|
207
|
+
* Everything is read in LOCAL time, including date-only keys. This is deliberate: `new Date("2026-01-13")`
|
|
208
|
+
* is parsed as UTC by the specification, while `new Date(2026, 0, 13)` is local. Mixing the two puts
|
|
209
|
+
* the generated buckets half a day out of step with the parsed ones near a DST boundary.
|
|
210
|
+
*/
|
|
211
|
+
export declare function parseBucketDate(key: string): Date | null;
|
|
212
|
+
/** A candidate aggregation for adaptive resolution. */
|
|
213
|
+
export interface ResolutionCandidate<T> {
|
|
214
|
+
readonly mask: TimelineMask;
|
|
215
|
+
/**
|
|
216
|
+
* Widest range, in months, this candidate should serve. Use -1 for "no limit".
|
|
217
|
+
* Mirrors SBA v2's maxNMonths.
|
|
218
|
+
*/
|
|
219
|
+
readonly maxMonths: number;
|
|
220
|
+
readonly value: T;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Picks the finest resolution that still covers the requested range.
|
|
224
|
+
*
|
|
225
|
+
* This is what keeps a timeline usable across scales: a daily aggregation over twenty years is
|
|
226
|
+
* 7 300 points, unreadable and slow, while a yearly aggregation over one month is a single dot.
|
|
227
|
+
* SBA v2 called this "combined aggregations". Feed it the range currently displayed (after a brush
|
|
228
|
+
* selection, say) and re-fetch with the aggregation it returns.
|
|
229
|
+
*/
|
|
230
|
+
export declare function pickResolution<T>(candidates: readonly ResolutionCandidate<T>[], rangeMonths: number): ResolutionCandidate<T> | undefined;
|
|
231
|
+
/** Whole months between two dates, for feeding pickResolution(). */
|
|
232
|
+
export declare function monthsBetween(from: Date, to: Date): number;
|
|
233
|
+
/** The chart types this component supports. A narrow union keeps `strictTemplates` useful. */
|
|
234
|
+
export type AggregationChartType = "bar" | "pie" | "doughnut";
|
|
235
|
+
/**
|
|
236
|
+
* A Sinequa aggregation rendered as a bar, pie or doughnut chart.
|
|
237
|
+
*
|
|
238
|
+
* Note what this component does **not** do:
|
|
239
|
+
*
|
|
240
|
+
* - **it does not fetch.** It takes an `Aggregation` as an input, like `<Aggregation>` in
|
|
241
|
+
* controlled mode. Feed it from `AggregationsStore`, from `QueryService.search()` or from
|
|
242
|
+
* `fetchQuery()` — the component does not care, and stays testable without a server.
|
|
243
|
+
* - **it does not transform.** `toSeries()` does that, as a pure function.
|
|
244
|
+
* - **it does not touch the canvas.** `<ChartCanvas>` owns the Chart.js lifecycle.
|
|
245
|
+
*
|
|
246
|
+
* What is left is one `computed()` building a `ChartConfiguration`. That is the whole component.
|
|
247
|
+
*/
|
|
248
|
+
export declare class AggregationChartComponent {
|
|
249
|
+
cn: import("cn").CnFunction;
|
|
250
|
+
/**
|
|
251
|
+
* Extra classes for the host element.
|
|
252
|
+
* @default ""
|
|
253
|
+
*/
|
|
254
|
+
readonly class: import("@angular/core").InputSignal<string>;
|
|
255
|
+
/**
|
|
256
|
+
* The aggregation to render.
|
|
257
|
+
* @default undefined
|
|
258
|
+
*/
|
|
259
|
+
readonly aggregation: import("@angular/core").InputSignal<AggregationLike | undefined>;
|
|
260
|
+
/**
|
|
261
|
+
* Chart type.
|
|
262
|
+
* @default "bar"
|
|
263
|
+
*/
|
|
264
|
+
readonly type: import("@angular/core").InputSignal<AggregationChartType>;
|
|
265
|
+
/**
|
|
266
|
+
* Dataset label, shown in the legend and the tooltip.
|
|
267
|
+
* @default ""
|
|
268
|
+
*/
|
|
269
|
+
readonly label: import("@angular/core").InputSignal<string>;
|
|
270
|
+
/**
|
|
271
|
+
* Number of items kept, largest first. Charts stop being readable long before the data runs out.
|
|
272
|
+
* @default 10
|
|
273
|
+
*/
|
|
274
|
+
readonly limit: import("@angular/core").InputSignal<number>;
|
|
275
|
+
/**
|
|
276
|
+
* Plot each item as a share of the total instead of a raw count.
|
|
277
|
+
* @default false
|
|
278
|
+
*/
|
|
279
|
+
readonly asPercentage: import("@angular/core").InputSignal<boolean>;
|
|
280
|
+
/**
|
|
281
|
+
* Read `operatorResults[weightField]` instead of `count` — for an average response time, say.
|
|
282
|
+
* @default undefined
|
|
283
|
+
*/
|
|
284
|
+
readonly weightField: import("@angular/core").InputSignal<string | undefined>;
|
|
285
|
+
/**
|
|
286
|
+
* Text shown when there is nothing to display.
|
|
287
|
+
* @default "No data"
|
|
288
|
+
*/
|
|
289
|
+
readonly emptyLabel: import("@angular/core").InputSignal<string>;
|
|
290
|
+
/**
|
|
291
|
+
* Emitted with the label of the clicked slice. Wire it to `AggregationsService.toFilter()` and
|
|
292
|
+
* `QueryParamsStore.updateFilter()` to turn this chart into a facet.
|
|
293
|
+
*/
|
|
294
|
+
readonly itemSelected: import("@angular/core").OutputEmitterRef<string>;
|
|
295
|
+
/** Resolved after the first render: `getComputedStyle` is useless before styles have applied. */
|
|
296
|
+
private readonly palette;
|
|
297
|
+
constructor();
|
|
298
|
+
private readonly series;
|
|
299
|
+
protected readonly isEmpty: import("@angular/core").Signal<boolean>;
|
|
300
|
+
protected readonly config: import("@angular/core").Signal<ChartConfiguration<keyof import("chart.js").ChartTypeRegistry, (number | [number, number] | import("chart.js").Point | import("chart.js").BubbleDataPoint | null)[], unknown>>;
|
|
301
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AggregationChartComponent, never>;
|
|
302
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<AggregationChartComponent, "AggregationChart, aggregation-chart, aggregationchart", never, {
|
|
303
|
+
"class": {
|
|
304
|
+
"alias": "class";
|
|
305
|
+
"required": false;
|
|
306
|
+
"isSignal": true;
|
|
307
|
+
};
|
|
308
|
+
"aggregation": {
|
|
309
|
+
"alias": "aggregation";
|
|
310
|
+
"required": false;
|
|
311
|
+
"isSignal": true;
|
|
312
|
+
};
|
|
313
|
+
"type": {
|
|
314
|
+
"alias": "type";
|
|
315
|
+
"required": false;
|
|
316
|
+
"isSignal": true;
|
|
317
|
+
};
|
|
318
|
+
"label": {
|
|
319
|
+
"alias": "label";
|
|
320
|
+
"required": false;
|
|
321
|
+
"isSignal": true;
|
|
322
|
+
};
|
|
323
|
+
"limit": {
|
|
324
|
+
"alias": "limit";
|
|
325
|
+
"required": false;
|
|
326
|
+
"isSignal": true;
|
|
327
|
+
};
|
|
328
|
+
"asPercentage": {
|
|
329
|
+
"alias": "asPercentage";
|
|
330
|
+
"required": false;
|
|
331
|
+
"isSignal": true;
|
|
332
|
+
};
|
|
333
|
+
"weightField": {
|
|
334
|
+
"alias": "weightField";
|
|
335
|
+
"required": false;
|
|
336
|
+
"isSignal": true;
|
|
337
|
+
};
|
|
338
|
+
"emptyLabel": {
|
|
339
|
+
"alias": "emptyLabel";
|
|
340
|
+
"required": false;
|
|
341
|
+
"isSignal": true;
|
|
342
|
+
};
|
|
343
|
+
}, {
|
|
344
|
+
"itemSelected": "itemSelected";
|
|
345
|
+
}, never, never, true, never>;
|
|
346
|
+
}
|
|
347
|
+
/** A brushed range, expressed with the same bucket labels the caller supplied. */
|
|
348
|
+
export interface TimelineRange {
|
|
349
|
+
readonly from: string;
|
|
350
|
+
readonly to: string;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* A time series with drag-to-select range selection, on Chart.js, with no d3.
|
|
354
|
+
*
|
|
355
|
+
* The d3 timeline this replaces was ~800 lines. The mapping:
|
|
356
|
+
*
|
|
357
|
+
* | d3 | here |
|
|
358
|
+
* |---|---|
|
|
359
|
+
* | `d3.curveStep` | `stepped: "middle"` |
|
|
360
|
+
* | `d3.area()` | `fill: true` + `withAlpha(colour, 0.18)` |
|
|
361
|
+
* | `d3.scaleUtc` + axis | a `category` axis over labels resolved in `timeline-data.ts` |
|
|
362
|
+
* | `d3.brushX` | `createTimelineBrushPlugin()`, ~60 lines |
|
|
363
|
+
* | `d3.bisector` tooltip | `interaction: { mode: "index", intersect: false }` |
|
|
364
|
+
* | gap filling, resolution picking | pure functions in `timeline-data.ts` |
|
|
365
|
+
*
|
|
366
|
+
* The real gain is not the removed dependency: it is that all the time-axis logic became pure and
|
|
367
|
+
* testable instead of being welded to the rendering.
|
|
368
|
+
*
|
|
369
|
+
* **A `category` axis, never `time`.** Chart.js can do a real time axis, but only with a date
|
|
370
|
+
* adapter, which this library does not ship. Setting `scales.x.type = "time"` without one compiles
|
|
371
|
+
* perfectly and then throws at runtime.
|
|
372
|
+
*
|
|
373
|
+
* **`(rangeSelected)` only reports.** If the host does nothing with it, you drag, the rectangle
|
|
374
|
+
* appears, it vanishes, and nothing moves — the component is fine, the loop is simply not closed.
|
|
375
|
+
* Keep a stack of ranges: a drag pushes one (zoom in), a control pops it (zoom out).
|
|
376
|
+
*/
|
|
377
|
+
export declare class AggregationTimelineComponent {
|
|
378
|
+
cn: import("cn").CnFunction;
|
|
379
|
+
/**
|
|
380
|
+
* Extra classes for the host element.
|
|
381
|
+
* @default ""
|
|
382
|
+
*/
|
|
383
|
+
readonly class: import("@angular/core").InputSignal<string>;
|
|
384
|
+
/**
|
|
385
|
+
* The series to plot. Each carries an aggregation whose items are date buckets.
|
|
386
|
+
* @default []
|
|
387
|
+
*/
|
|
388
|
+
readonly series: import("@angular/core").InputSignal<readonly TimelineSeriesInput[]>;
|
|
389
|
+
/**
|
|
390
|
+
* Bucket width. Without it there is no gap filling: empty buckets are skipped rather than drawn
|
|
391
|
+
* flat at zero, which silently misrepresents the data.
|
|
392
|
+
* @default "YYYY-MM-DD"
|
|
393
|
+
*/
|
|
394
|
+
readonly mask: import("@angular/core").InputSignal<TimelineMask | undefined>;
|
|
395
|
+
/**
|
|
396
|
+
* Enable the drag-to-select brush.
|
|
397
|
+
* @default true
|
|
398
|
+
*/
|
|
399
|
+
readonly enableSelection: import("@angular/core").InputSignal<boolean>;
|
|
400
|
+
/**
|
|
401
|
+
* Render every second series dashed — the "previous period" convention.
|
|
402
|
+
* @default false
|
|
403
|
+
*/
|
|
404
|
+
readonly dashSecondary: import("@angular/core").InputSignal<boolean>;
|
|
405
|
+
/**
|
|
406
|
+
* Text shown when there is nothing to display.
|
|
407
|
+
* @default "No data"
|
|
408
|
+
*/
|
|
409
|
+
readonly emptyLabel: import("@angular/core").InputSignal<string>;
|
|
410
|
+
/** Emitted on mouse release with the first and last bucket labels covered by the drag. */
|
|
411
|
+
readonly rangeSelected: import("@angular/core").OutputEmitterRef<TimelineRange>;
|
|
412
|
+
/**
|
|
413
|
+
* Built ONCE, as a field, never inside a `computed()`.
|
|
414
|
+
*
|
|
415
|
+
* The brush keeps its drag state in a closure. Rebuilding it mid-drag would hand Chart.js a fresh
|
|
416
|
+
* object with empty state and cancel the selection — producing a brush that "sometimes does not
|
|
417
|
+
* work", which is worse than one that never does.
|
|
418
|
+
*/
|
|
419
|
+
private readonly brush;
|
|
420
|
+
/** Resolved after the first render: `getComputedStyle` is useless before styles have applied. */
|
|
421
|
+
private readonly palette;
|
|
422
|
+
constructor();
|
|
423
|
+
protected readonly plugins: Signal<Plugin[]>;
|
|
424
|
+
private readonly timeline;
|
|
425
|
+
protected readonly isEmpty: Signal<boolean>;
|
|
426
|
+
protected readonly config: Signal<ChartConfiguration<keyof import("chart.js").ChartTypeRegistry, (number | [number, number] | import("chart.js").Point | import("chart.js").BubbleDataPoint | null)[], unknown>>;
|
|
427
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AggregationTimelineComponent, never>;
|
|
428
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<AggregationTimelineComponent, "AggregationTimeline, aggregation-timeline, aggregationtimeline", never, {
|
|
429
|
+
"class": {
|
|
430
|
+
"alias": "class";
|
|
431
|
+
"required": false;
|
|
432
|
+
"isSignal": true;
|
|
433
|
+
};
|
|
434
|
+
"series": {
|
|
435
|
+
"alias": "series";
|
|
436
|
+
"required": false;
|
|
437
|
+
"isSignal": true;
|
|
438
|
+
};
|
|
439
|
+
"mask": {
|
|
440
|
+
"alias": "mask";
|
|
441
|
+
"required": false;
|
|
442
|
+
"isSignal": true;
|
|
443
|
+
};
|
|
444
|
+
"enableSelection": {
|
|
445
|
+
"alias": "enableSelection";
|
|
446
|
+
"required": false;
|
|
447
|
+
"isSignal": true;
|
|
448
|
+
};
|
|
449
|
+
"dashSecondary": {
|
|
450
|
+
"alias": "dashSecondary";
|
|
451
|
+
"required": false;
|
|
452
|
+
"isSignal": true;
|
|
453
|
+
};
|
|
454
|
+
"emptyLabel": {
|
|
455
|
+
"alias": "emptyLabel";
|
|
456
|
+
"required": false;
|
|
457
|
+
"isSignal": true;
|
|
458
|
+
};
|
|
459
|
+
}, {
|
|
460
|
+
"rangeSelected": "rangeSelected";
|
|
461
|
+
}, never, never, true, never>;
|
|
462
|
+
}
|