-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathFormulaWidget.component.ts
More file actions
89 lines (82 loc) · 2.43 KB
/
FormulaWidget.component.ts
File metadata and controls
89 lines (82 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { Component, effect, input, signal } from '@angular/core';
import { MapViewState } from '@deck.gl/core';
import {
createSpatialFilter,
numberFormatter,
WidgetStatus,
} from '../../../utils';
import {
AggregationType,
WidgetSource,
WidgetSourceProps,
} from '@carto/api-client';
/**
* Formula widget, displaying a prominent 'scorecard' number.
*/
@Component({
selector: 'formula-widget',
standalone: true,
template: `
@switch (status()) {
@case ('loading') {
<span class="title">...</span>
}
@case ('error') {
<span class="title">⚠ Error</span>
}
@case ('complete') {
<data class="title" [value]="value()">{{ formatValue(value()) }} </data>
}
}
`,
})
export class FormulaWidgetComponent {
/** Widget-compatible data source, from vectorTableSource, vectorQuerySource, etc. */
data =
input.required<
Promise<{ widgetSource: WidgetSource<WidgetSourceProps> }>
>();
/** Column containing a value to be aggregated. */
column = input<string>();
/** Operation used to aggregate the specified column. */
operation = input<Exclude<AggregationType, 'custom'>>();
/** Map view state. If specified, widget will be filtered to the view. */
viewState = input<MapViewState>();
status = signal<WidgetStatus>('loading');
value = signal(-1);
// Fetches data for the widget to display, watching changes to view state
// and widget configuration to refresh.
private dataEffect = effect(
(onCleanup) => {
const column = this.column() || '';
const operation = this.operation() || 'count';
const viewState = this.viewState();
const abortController = new AbortController();
onCleanup(() => abortController.abort());
this.status.set('loading');
this.data()
.then(({ widgetSource }) =>
widgetSource.getFormula({
column,
operation,
spatialFilter: viewState && createSpatialFilter(viewState),
abortController,
}),
)
.then((response) => {
this.status.set('complete');
this.value.set(response.value as number);
})
.catch(() => {
if (!abortController.signal.aborted) {
this.status.set('error');
}
this.value.set(-1);
});
},
{ allowSignalWrites: true },
);
formatValue(value: number): string {
return numberFormatter.format(value);
}
}