@ojiepermana/angular 22.1.14 → 22.2.1
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 +8 -6
- package/SUPPORT.md +3 -3
- package/chart/README.md +1 -1
- package/component/README.md +2 -2
- package/component/calendar/README.md +3 -15
- package/component/drawer/README.md +1 -2
- package/fesm2022/ojiepermana-angular-chart-area.mjs +352 -137
- package/fesm2022/ojiepermana-angular-chart-bar.mjs +744 -524
- package/fesm2022/ojiepermana-angular-chart-core.mjs +1140 -1344
- package/fesm2022/ojiepermana-angular-chart-line.mjs +393 -147
- package/fesm2022/ojiepermana-angular-chart-pie.mjs +408 -179
- package/fesm2022/ojiepermana-angular-chart-primitives.mjs +1262 -920
- package/fesm2022/ojiepermana-angular-chart-radar.mjs +473 -205
- package/fesm2022/ojiepermana-angular-chart-radial.mjs +425 -182
- package/fesm2022/ojiepermana-angular-chart-scatter.mjs +386 -210
- package/fesm2022/ojiepermana-angular-chart.mjs +3 -19
- package/fesm2022/ojiepermana-angular-component-accordion.mjs +485 -243
- package/fesm2022/ojiepermana-angular-component-alert-dialog.mjs +963 -325
- package/fesm2022/ojiepermana-angular-component-alert.mjs +266 -103
- package/fesm2022/ojiepermana-angular-component-aspect-ratio.mjs +80 -35
- package/fesm2022/ojiepermana-angular-component-avatar.mjs +402 -135
- package/fesm2022/ojiepermana-angular-component-badge.mjs +109 -59
- package/fesm2022/ojiepermana-angular-component-breadcrumb.mjs +410 -142
- package/fesm2022/ojiepermana-angular-component-button-group.mjs +249 -96
- package/fesm2022/ojiepermana-angular-component-button.mjs +153 -75
- package/fesm2022/ojiepermana-angular-component-calendar.mjs +531 -418
- package/fesm2022/ojiepermana-angular-component-card.mjs +457 -171
- package/fesm2022/ojiepermana-angular-component-carousel.mjs +642 -272
- package/fesm2022/ojiepermana-angular-component-checkbox.mjs +312 -108
- package/fesm2022/ojiepermana-angular-component-collapsible.mjs +299 -115
- package/fesm2022/ojiepermana-angular-component-combobox.mjs +396 -183
- package/fesm2022/ojiepermana-angular-component-command.mjs +807 -347
- package/fesm2022/ojiepermana-angular-component-composer.mjs +807 -330
- package/fesm2022/ojiepermana-angular-component-context-menu.mjs +196 -161
- package/fesm2022/ojiepermana-angular-component-date-picker.mjs +650 -338
- package/fesm2022/ojiepermana-angular-component-dialog.mjs +710 -316
- package/fesm2022/ojiepermana-angular-component-drawer.mjs +1 -5
- package/fesm2022/ojiepermana-angular-component-dropdown-menu.mjs +1212 -646
- package/fesm2022/ojiepermana-angular-component-editor.mjs +987 -502
- package/fesm2022/ojiepermana-angular-component-empty.mjs +350 -137
- package/fesm2022/ojiepermana-angular-component-form.mjs +813 -434
- package/fesm2022/ojiepermana-angular-component-hover-card.mjs +486 -277
- package/fesm2022/ojiepermana-angular-component-icon.mjs +241 -140
- package/fesm2022/ojiepermana-angular-component-input-group.mjs +449 -176
- package/fesm2022/ojiepermana-angular-component-input-otp.mjs +891 -488
- package/fesm2022/ojiepermana-angular-component-input.mjs +86 -55
- package/fesm2022/ojiepermana-angular-component-item.mjs +713 -261
- package/fesm2022/ojiepermana-angular-component-kanban.mjs +714 -216
- package/fesm2022/ojiepermana-angular-component-kbd.mjs +124 -52
- package/fesm2022/ojiepermana-angular-component-label.mjs +82 -31
- package/fesm2022/ojiepermana-angular-component-menubar.mjs +479 -329
- package/fesm2022/ojiepermana-angular-component-native-select.mjs +167 -65
- package/fesm2022/ojiepermana-angular-component-navigation-menu.mjs +683 -380
- package/fesm2022/ojiepermana-angular-component-pagination.mjs +277 -94
- package/fesm2022/ojiepermana-angular-component-pillbox.mjs +1283 -607
- package/fesm2022/ojiepermana-angular-component-popover.mjs +291 -204
- package/fesm2022/ojiepermana-angular-component-progress.mjs +176 -53
- package/fesm2022/ojiepermana-angular-component-radio.mjs +449 -142
- package/fesm2022/ojiepermana-angular-component-resizable.mjs +659 -453
- package/fesm2022/ojiepermana-angular-component-scroll-area.mjs +117 -39
- package/fesm2022/ojiepermana-angular-component-segmented-control.mjs +351 -172
- package/fesm2022/ojiepermana-angular-component-select.mjs +475 -345
- package/fesm2022/ojiepermana-angular-component-separator.mjs +102 -35
- package/fesm2022/ojiepermana-angular-component-sheet.mjs +797 -347
- package/fesm2022/ojiepermana-angular-component-skeleton.mjs +62 -29
- package/fesm2022/ojiepermana-angular-component-slider.mjs +592 -376
- package/fesm2022/ojiepermana-angular-component-spinner.mjs +135 -38
- package/fesm2022/ojiepermana-angular-component-switch.mjs +315 -103
- package/fesm2022/ojiepermana-angular-component-table.mjs +440 -153
- package/fesm2022/ojiepermana-angular-component-tabs.mjs +590 -317
- package/fesm2022/ojiepermana-angular-component-textarea.mjs +85 -50
- package/fesm2022/ojiepermana-angular-component-timeline.mjs +609 -231
- package/fesm2022/ojiepermana-angular-component-toast.mjs +229 -243
- package/fesm2022/ojiepermana-angular-component-toggle-group.mjs +573 -288
- package/fesm2022/ojiepermana-angular-component-toggle.mjs +187 -78
- package/fesm2022/ojiepermana-angular-component-tooltip.mjs +798 -517
- package/fesm2022/ojiepermana-angular-component-utils-core.mjs +159 -292
- package/fesm2022/ojiepermana-angular-component-utils-overlay.mjs +46 -58
- package/fesm2022/ojiepermana-angular-component-utils-scale.mjs +76 -38
- package/fesm2022/ojiepermana-angular-component-utils.mjs +2 -8
- package/fesm2022/ojiepermana-angular-component.mjs +0 -10
- package/fesm2022/ojiepermana-angular-navigation-core.mjs +13 -23
- package/fesm2022/ojiepermana-angular-navigation-icon.mjs +35 -24
- package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-DYuysKVf.mjs +129 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-COiTaw34.mjs +812 -0
- package/fesm2022/{ojiepermana-angular-navigation-navigation-entry-grid.component-COQ-60DS.mjs → ojiepermana-angular-navigation-navigation-entry-grid.component-YIz0IsIb.mjs} +392 -207
- package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-D2vwEwBY.mjs +650 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-B5D7yXfb.mjs +662 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-item.component-CUb68MZH.mjs +1219 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-list.component-CrK16trj.mjs +327 -0
- package/fesm2022/ojiepermana-angular-navigation-service.mjs +544 -724
- package/fesm2022/ojiepermana-angular-navigation-types.mjs +139 -56
- package/fesm2022/ojiepermana-angular-navigation.mjs +3256 -4
- package/fesm2022/ojiepermana-angular-sdk.mjs +91 -201
- package/fesm2022/ojiepermana-angular-theme-component-settings.mjs +1125 -737
- package/fesm2022/ojiepermana-angular-theme-layout-services.mjs +245 -328
- package/fesm2022/ojiepermana-angular-theme-layout-types.mjs +35 -38
- package/fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs +1928 -553
- package/fesm2022/ojiepermana-angular-theme-layout.mjs +847 -496
- package/fesm2022/ojiepermana-angular-theme-page-core.mjs +288 -358
- package/fesm2022/ojiepermana-angular-theme-page-filter.mjs +362 -224
- package/fesm2022/ojiepermana-angular-theme-page-overview.mjs +88 -0
- package/fesm2022/ojiepermana-angular-theme-page-root.mjs +576 -254
- package/fesm2022/ojiepermana-angular-theme-page-side.mjs +317 -177
- package/fesm2022/ojiepermana-angular-theme-page-slots.mjs +256 -112
- package/fesm2022/ojiepermana-angular-theme-page.mjs +7 -12
- package/fesm2022/ojiepermana-angular-theme-shell-services.mjs +215 -326
- package/fesm2022/ojiepermana-angular-theme-shell-types.mjs +68 -129
- package/fesm2022/ojiepermana-angular-theme-shell.mjs +907 -378
- package/fesm2022/ojiepermana-angular-theme-styles.mjs +521 -720
- package/fesm2022/ojiepermana-angular-theme.mjs +0 -10
- package/fesm2022/ojiepermana-angular.mjs +5 -24
- package/navigation/README.md +69 -18
- package/package.json +16 -12
- package/sdk/README.md +1 -1
- package/sdk/src/writer/index.js +2 -2
- package/theme/README.md +1 -1
- package/theme/layout/README.md +2 -4
- package/theme/page/README.md +50 -0
- package/theme/styles/README.md +10 -10
- package/theme/styles/css/base/prefers-dark.css +1 -1
- package/theme/styles/css/base/status.css +1 -1
- package/theme/styles/css/color/amber.css +1 -1
- package/theme/styles/css/color/blue.css +1 -1
- package/theme/styles/css/color/cyan.css +1 -1
- package/theme/styles/css/color/emerald.css +1 -1
- package/theme/styles/css/color/fuchsia.css +1 -1
- package/theme/styles/css/color/green.css +1 -1
- package/theme/styles/css/color/indigo.css +1 -1
- package/theme/styles/css/color/lime.css +1 -1
- package/theme/styles/css/color/orange.css +1 -1
- package/theme/styles/css/color/pink.css +1 -1
- package/theme/styles/css/color/purple.css +1 -1
- package/theme/styles/css/color/red.css +1 -1
- package/theme/styles/css/color/rose.css +1 -1
- package/theme/styles/css/color/sky.css +1 -1
- package/theme/styles/css/color/teal.css +1 -1
- package/theme/styles/css/color/violet.css +1 -1
- package/theme/styles/css/color/yellow.css +1 -1
- package/theme/styles/css/neutral/gray.css +1 -1
- package/theme/styles/css/neutral/mauve.css +1 -1
- package/theme/styles/css/neutral/mist.css +1 -1
- package/theme/styles/css/neutral/neutral.css +1 -1
- package/theme/styles/css/neutral/olive.css +1 -1
- package/theme/styles/css/neutral/slate.css +1 -1
- package/theme/styles/css/neutral/stone.css +1 -1
- package/theme/styles/css/neutral/taupe.css +1 -1
- package/theme/styles/css/neutral/zinc.css +1 -1
- package/types/ojiepermana-angular-chart-area.d.ts +126 -63
- package/types/ojiepermana-angular-chart-bar.d.ts +244 -154
- package/types/ojiepermana-angular-chart-core.d.ts +409 -398
- package/types/ojiepermana-angular-chart-line.d.ts +141 -68
- package/types/ojiepermana-angular-chart-pie.d.ts +192 -121
- package/types/ojiepermana-angular-chart-primitives.d.ts +283 -214
- package/types/ojiepermana-angular-chart-radar.d.ts +189 -108
- package/types/ojiepermana-angular-chart-radial.d.ts +177 -106
- package/types/ojiepermana-angular-chart-scatter.d.ts +166 -110
- package/types/ojiepermana-angular-chart.d.ts +3 -2
- package/types/ojiepermana-angular-component-accordion.d.ts +135 -81
- package/types/ojiepermana-angular-component-alert-dialog.d.ts +271 -123
- package/types/ojiepermana-angular-component-alert.d.ts +69 -39
- package/types/ojiepermana-angular-component-aspect-ratio.d.ts +20 -12
- package/types/ojiepermana-angular-component-avatar.d.ts +103 -49
- package/types/ojiepermana-angular-component-badge.d.ts +36 -24
- package/types/ojiepermana-angular-component-breadcrumb.d.ts +79 -40
- package/types/ojiepermana-angular-component-button-group.d.ts +48 -24
- package/types/ojiepermana-angular-component-button.d.ts +44 -27
- package/types/ojiepermana-angular-component-calendar.d.ts +145 -107
- package/types/ojiepermana-angular-component-card.d.ts +112 -63
- package/types/ojiepermana-angular-component-carousel.d.ts +150 -81
- package/types/ojiepermana-angular-component-checkbox.d.ts +96 -38
- package/types/ojiepermana-angular-component-collapsible.d.ts +65 -39
- package/types/ojiepermana-angular-component-combobox.d.ts +100 -55
- package/types/ojiepermana-angular-component-command.d.ts +206 -121
- package/types/ojiepermana-angular-component-composer.d.ts +184 -84
- package/types/ojiepermana-angular-component-context-menu.d.ts +51 -41
- package/types/ojiepermana-angular-component-date-picker.d.ts +199 -109
- package/types/ojiepermana-angular-component-dialog.d.ts +200 -105
- package/types/ojiepermana-angular-component-drawer.d.ts +2 -1
- package/types/ojiepermana-angular-component-dropdown-menu.d.ts +324 -202
- package/types/ojiepermana-angular-component-editor.d.ts +215 -117
- package/types/ojiepermana-angular-component-empty.d.ts +80 -45
- package/types/ojiepermana-angular-component-form.d.ts +185 -121
- package/types/ojiepermana-angular-component-hover-card.d.ts +130 -72
- package/types/ojiepermana-angular-component-icon.d.ts +87 -57
- package/types/ojiepermana-angular-component-input-group.d.ts +93 -46
- package/types/ojiepermana-angular-component-input-otp.d.ts +243 -150
- package/types/ojiepermana-angular-component-input.d.ts +27 -17
- package/types/ojiepermana-angular-component-item.d.ts +160 -84
- package/types/ojiepermana-angular-component-kanban.d.ts +157 -62
- package/types/ojiepermana-angular-component-kbd.d.ts +24 -15
- package/types/ojiepermana-angular-component-label.d.ts +19 -11
- package/types/ojiepermana-angular-component-menubar.d.ts +120 -90
- package/types/ojiepermana-angular-component-native-select.d.ts +37 -24
- package/types/ojiepermana-angular-component-navigation-menu.d.ts +157 -98
- package/types/ojiepermana-angular-component-pagination.d.ts +78 -28
- package/types/ojiepermana-angular-component-pillbox.d.ts +361 -204
- package/types/ojiepermana-angular-component-popover.d.ts +94 -64
- package/types/ojiepermana-angular-component-progress.d.ts +45 -17
- package/types/ojiepermana-angular-component-radio.d.ts +129 -53
- package/types/ojiepermana-angular-component-resizable.d.ts +160 -112
- package/types/ojiepermana-angular-component-scroll-area.d.ts +33 -15
- package/types/ojiepermana-angular-component-segmented-control.d.ts +94 -50
- package/types/ojiepermana-angular-component-select.d.ts +94 -77
- package/types/ojiepermana-angular-component-separator.d.ts +26 -14
- package/types/ojiepermana-angular-component-sheet.d.ts +226 -116
- package/types/ojiepermana-angular-component-skeleton.d.ts +13 -10
- package/types/ojiepermana-angular-component-slider.d.ts +140 -75
- package/types/ojiepermana-angular-component-spinner.d.ts +31 -13
- package/types/ojiepermana-angular-component-switch.d.ts +97 -40
- package/types/ojiepermana-angular-component-table.d.ts +102 -50
- package/types/ojiepermana-angular-component-tabs.d.ts +174 -115
- package/types/ojiepermana-angular-component-textarea.d.ts +27 -17
- package/types/ojiepermana-angular-component-timeline.d.ts +141 -59
- package/types/ojiepermana-angular-component-toast.d.ts +51 -55
- package/types/ojiepermana-angular-component-toggle-group.d.ts +159 -88
- package/types/ojiepermana-angular-component-toggle.d.ts +47 -25
- package/types/ojiepermana-angular-component-tooltip.d.ts +222 -132
- package/types/ojiepermana-angular-component-utils-core.d.ts +81 -90
- package/types/ojiepermana-angular-component-utils-overlay.d.ts +7 -11
- package/types/ojiepermana-angular-component-utils-scale.d.ts +20 -12
- package/types/ojiepermana-angular-component-utils.d.ts +2 -2
- package/types/ojiepermana-angular-component.d.ts +1 -2
- package/types/ojiepermana-angular-navigation-core.d.ts +46 -50
- package/types/ojiepermana-angular-navigation-icon.d.ts +9 -12
- package/types/ojiepermana-angular-navigation-service.d.ts +112 -115
- package/types/ojiepermana-angular-navigation-types.d.ts +166 -125
- package/types/ojiepermana-angular-navigation.d.ts +708 -375
- package/types/ojiepermana-angular-sdk.d.ts +69 -71
- package/types/ojiepermana-angular-theme-component-settings.d.ts +120 -86
- package/types/ojiepermana-angular-theme-layout-services.d.ts +119 -124
- package/types/ojiepermana-angular-theme-layout-types.d.ts +27 -31
- package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +446 -187
- package/types/ojiepermana-angular-theme-layout.d.ts +201 -113
- package/types/ojiepermana-angular-theme-page-core.d.ts +136 -142
- package/types/ojiepermana-angular-theme-page-filter.d.ts +112 -62
- package/types/ojiepermana-angular-theme-page-overview.d.ts +28 -0
- package/types/ojiepermana-angular-theme-page-root.d.ts +172 -88
- package/types/ojiepermana-angular-theme-page-side.d.ts +89 -49
- package/types/ojiepermana-angular-theme-page-slots.d.ts +58 -37
- package/types/ojiepermana-angular-theme-page.d.ts +7 -5
- package/types/ojiepermana-angular-theme-shell-services.d.ts +119 -125
- package/types/ojiepermana-angular-theme-shell-types.d.ts +38 -41
- package/types/ojiepermana-angular-theme-shell.d.ts +139 -61
- package/types/ojiepermana-angular-theme-styles.d.ts +184 -196
- package/types/ojiepermana-angular-theme.d.ts +1 -2
- package/types/ojiepermana-angular.d.ts +5 -5
- package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-Be3IqzG4.mjs +0 -91
- package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-Bc7DWK3R.mjs +0 -522
- package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-DA8VPEn7.mjs +0 -404
- package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-U2TJTzlW.mjs +0 -466
- package/fesm2022/ojiepermana-angular-navigation-ojiepermana-angular-navigation-CIUhmytH.mjs +0 -2668
|
@@ -1,706 +1,588 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
];
|
|
15
|
-
/**
|
|
16
|
-
* Characters and sequences that could close the current declaration or rule and
|
|
17
|
-
* start a new one. A series color is interpolated into a `<style>` block, so any
|
|
18
|
-
* of these turns a color into arbitrary CSS.
|
|
19
|
-
*
|
|
20
|
-
* Control characters (newlines included) need no entry here: they are absent from
|
|
21
|
-
* {@link CSS_COLOR_CHARACTERS}, so the allow-list rejects them on its own.
|
|
22
|
-
*/
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { Component, DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, Renderer2, Service, afterNextRender, computed, effect, inject, input, signal, viewChild } from "@angular/core";
|
|
3
|
+
import { DOCUMENT, isPlatformBrowser } from "@angular/common";
|
|
4
|
+
import { scaleBand, scaleLinear, scalePoint } from "d3-scale";
|
|
5
|
+
import { max, min } from "d3-array";
|
|
6
|
+
import { area, curveLinear, curveMonotoneX, curveStep, line, stack, stackOffsetExpand } from "d3-shape";
|
|
7
|
+
const CHART_DATA_ATTRIBUTE = "data-chart";
|
|
8
|
+
const CHART_THEMES = [{
|
|
9
|
+
key: "light",
|
|
10
|
+
selector: ""
|
|
11
|
+
}, {
|
|
12
|
+
key: "dark",
|
|
13
|
+
selector: "[data-mode=\"dark\"]"
|
|
14
|
+
}];
|
|
23
15
|
const CSS_CONTEXT_BREAKERS = /[;{}<>@\\"']|\/\*|\*\//;
|
|
24
|
-
/** Characters a CSS color value may legitimately contain. */
|
|
25
16
|
const CSS_COLOR_CHARACTERS = /^[a-zA-Z0-9#%.,+\-_()/ ]+$/;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
'oklch',
|
|
41
|
-
'color',
|
|
42
|
-
'color-mix',
|
|
43
|
-
'light-dark',
|
|
44
|
-
'var',
|
|
17
|
+
const ALLOWED_COLOR_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
18
|
+
"rgb",
|
|
19
|
+
"rgba",
|
|
20
|
+
"hsl",
|
|
21
|
+
"hsla",
|
|
22
|
+
"hwb",
|
|
23
|
+
"lab",
|
|
24
|
+
"lch",
|
|
25
|
+
"oklab",
|
|
26
|
+
"oklch",
|
|
27
|
+
"color",
|
|
28
|
+
"color-mix",
|
|
29
|
+
"light-dark",
|
|
30
|
+
"var"
|
|
45
31
|
]);
|
|
46
|
-
/**
|
|
47
|
-
* Whether a value is safe to interpolate into the generated `<style>` block.
|
|
48
|
-
*
|
|
49
|
-
* The check is deliberately layered rather than one clever regular expression:
|
|
50
|
-
*
|
|
51
|
-
* 1. reject anything containing a character that can end a declaration or a
|
|
52
|
-
* rule, which is what actually stops an injection;
|
|
53
|
-
* 2. restrict the remaining characters to those a color can be built from;
|
|
54
|
-
* 3. require balanced parentheses, so a truncated function cannot swallow the
|
|
55
|
-
* rest of the block;
|
|
56
|
-
* 4. require every function called to be a color function.
|
|
57
|
-
*
|
|
58
|
-
* Real values keep working: `#2563eb`, `red`, `var(--chart-2)`,
|
|
59
|
-
* `hsl(var(--chart-1))`, `rgb(0 0 0 / 50%)`, `color-mix(in srgb, red, blue)`.
|
|
60
|
-
*/
|
|
61
32
|
function isSafeCssColorValue(value) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (depth < 0)
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (depth !== 0)
|
|
80
|
-
return false;
|
|
81
|
-
for (const match of trimmed.matchAll(/([a-zA-Z][a-zA-Z0-9-]*)\s*\(/g)) {
|
|
82
|
-
if (!ALLOWED_COLOR_FUNCTIONS.has(match[1].toLowerCase()))
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
return true;
|
|
33
|
+
const trimmed = value.trim();
|
|
34
|
+
if (!trimmed || trimmed.length > 200) return false;
|
|
35
|
+
if (CSS_CONTEXT_BREAKERS.test(trimmed)) return false;
|
|
36
|
+
if (!CSS_COLOR_CHARACTERS.test(trimmed)) return false;
|
|
37
|
+
let depth = 0;
|
|
38
|
+
for (const character of trimmed) if (character === "(") depth += 1;
|
|
39
|
+
else if (character === ")") {
|
|
40
|
+
depth -= 1;
|
|
41
|
+
if (depth < 0) return false;
|
|
42
|
+
}
|
|
43
|
+
if (depth !== 0) return false;
|
|
44
|
+
for (const match of trimmed.matchAll(/([a-zA-Z][a-zA-Z0-9-]*)\s*\(/g)) if (!ALLOWED_COLOR_FUNCTIONS.has(match[1].toLowerCase())) return false;
|
|
45
|
+
return true;
|
|
86
46
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Generate the CSS rule-set for a chart instance: one `--color-<key>` per
|
|
89
|
-
* series, scoped to the owning `[data-chart]` element, with optional dark
|
|
90
|
-
* variant via `[data-mode="dark"] [data-chart="…"]`.
|
|
91
|
-
*
|
|
92
|
-
* Series without any color are skipped (consumer can fall back to a default), and
|
|
93
|
-
* so is any series whose color fails {@link isSafeCssColorValue}: the value never
|
|
94
|
-
* reaches the stylesheet, and the series falls back to its default exactly as an
|
|
95
|
-
* unset color would. `chartId` is escaped, so it cannot break out of the
|
|
96
|
-
* attribute selector either.
|
|
97
|
-
*
|
|
98
|
-
* @param chartId Unique chart id (used as attribute value).
|
|
99
|
-
* @param config Series configuration map.
|
|
100
|
-
*/
|
|
101
47
|
function buildChartCss(chartId, config) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return ` --color-${escapeCssIdent(seriesKey)}: ${value.trim()};`;
|
|
115
|
-
})
|
|
116
|
-
.filter(Boolean)
|
|
117
|
-
.join('\n');
|
|
118
|
-
if (!vars) {
|
|
119
|
-
return '';
|
|
120
|
-
}
|
|
121
|
-
const scope = selector
|
|
122
|
-
? `${selector} [${CHART_DATA_ATTRIBUTE}="${scopeId}"]`
|
|
123
|
-
: `[${CHART_DATA_ATTRIBUTE}="${scopeId}"]`;
|
|
124
|
-
return `${scope} {\n${vars}\n}`;
|
|
125
|
-
})
|
|
126
|
-
.filter(Boolean)
|
|
127
|
-
.join('\n');
|
|
48
|
+
const entries = Object.entries(config).filter(([, cfg]) => cfg.color || cfg.theme);
|
|
49
|
+
if (entries.length === 0) return "";
|
|
50
|
+
const scopeId = escapeCssIdent(chartId);
|
|
51
|
+
return CHART_THEMES.map(({ key, selector }) => {
|
|
52
|
+
const vars = entries.map(([seriesKey, cfg]) => {
|
|
53
|
+
const value = cfg.theme?.[key] ?? cfg.color;
|
|
54
|
+
if (!value || !isSafeCssColorValue(value)) return "";
|
|
55
|
+
return ` --color-${escapeCssIdent(seriesKey)}: ${value.trim()};`;
|
|
56
|
+
}).filter(Boolean).join("\n");
|
|
57
|
+
if (!vars) return "";
|
|
58
|
+
return `${selector ? `${selector} [${CHART_DATA_ATTRIBUTE}="${scopeId}"]` : `[${CHART_DATA_ATTRIBUTE}="${scopeId}"]`} {\n${vars}\n}`;
|
|
59
|
+
}).filter(Boolean).join("\n");
|
|
128
60
|
}
|
|
129
|
-
/** What a CSS custom-property identifier and an attribute selector value may hold. */
|
|
130
61
|
const CSS_IDENT_CHARACTERS = /^[a-zA-Z0-9_-]*$/;
|
|
131
|
-
/**
|
|
132
|
-
* The suffix {@link escapeCssIdent} appends. A key that already ends this way is
|
|
133
|
-
* fingerprinted too, so a key that passes through untouched can never land on
|
|
134
|
-
* the identifier some other key was escaped into.
|
|
135
|
-
*/
|
|
136
62
|
const CSS_IDENT_FINGERPRINTED = /_h[0-9a-f]{8}$/;
|
|
137
|
-
/**
|
|
138
|
-
* Escape a string so it is safe to use as a CSS custom-property identifier or as
|
|
139
|
-
* an attribute selector value. The result only ever holds `[A-Za-z0-9_-]`.
|
|
140
|
-
*
|
|
141
|
-
* A string that is ALREADY an identifier passes through untouched, which is
|
|
142
|
-
* every real series key: `sales` stays `--color-sales`.
|
|
143
|
-
*
|
|
144
|
-
* Anything else has its unsafe characters replaced with `_` AND gains a short
|
|
145
|
-
* fingerprint of the ORIGINAL string, because the replacement alone is not
|
|
146
|
-
* injective. `'a b'` and `'a_b'` both collapse to `a_b`, and two series sharing
|
|
147
|
-
* one custom property is silent data loss: {@link buildChartCss} emits both
|
|
148
|
-
* declarations into the same rule so the last one wins, and
|
|
149
|
-
* {@link seriesColorVar} then resolves both series to that one token.
|
|
150
|
-
*/
|
|
151
63
|
function escapeCssIdent(input) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
return `${input.replace(/[^a-zA-Z0-9_-]/g, '_')}_h${fingerprint(input)}`;
|
|
64
|
+
if (CSS_IDENT_CHARACTERS.test(input) && !CSS_IDENT_FINGERPRINTED.test(input)) return input;
|
|
65
|
+
return `${input.replace(/[^a-zA-Z0-9_-]/g, "_")}_h${fingerprint(input)}`;
|
|
156
66
|
}
|
|
157
|
-
/**
|
|
158
|
-
* FNV-1a, 32 bits, hex. A short stable fingerprint used only to keep two escaped
|
|
159
|
-
* keys apart — not a security hash, and never parsed back.
|
|
160
|
-
*/
|
|
161
67
|
function fingerprint(input) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
68
|
+
let hash = 2166136261;
|
|
69
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
70
|
+
hash ^= input.charCodeAt(index);
|
|
71
|
+
hash = Math.imul(hash, 16777619);
|
|
72
|
+
}
|
|
73
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
168
74
|
}
|
|
169
|
-
/** Resolve the `var(--color-<key>)` reference for a given series. */
|
|
170
75
|
function seriesColorVar(seriesKey) {
|
|
171
|
-
|
|
76
|
+
return `var(--color-${escapeCssIdent(seriesKey)})`;
|
|
172
77
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Resolve a raw per-datum colour to a paint value for an SVG attribute
|
|
175
|
-
* (`[attr.fill]`, `[attr.stroke]`).
|
|
176
|
-
*
|
|
177
|
-
* `raw` is `unknown` so a caller can hand over `datum[colorKey]` directly
|
|
178
|
-
* without its own `typeof` guard.
|
|
179
|
-
*
|
|
180
|
-
* The rule, which is the union of the two copies this replaces:
|
|
181
|
-
* 1. not a string, or empty -> `fallback`
|
|
182
|
-
* 2. looks like a CSS colour or calls a
|
|
183
|
-
* function (`var(`, `#`, `rgb`,
|
|
184
|
-
* `hsl`, or a `(` anywhere) -> used verbatim
|
|
185
|
-
* 3. anything else is a series key -> `var(--color-<key>)`
|
|
186
|
-
*
|
|
187
|
-
* Deliberately NOT added: no `.trim()`, and no named-colour detector. Either
|
|
188
|
-
* would move an input that today lands on branch 3, so `'red'` stays a series
|
|
189
|
-
* key rather than becoming the colour red. That is the existing behaviour and
|
|
190
|
-
* changing it is a separate decision.
|
|
191
|
-
*/
|
|
192
78
|
function resolveSeriesColor(raw, fallback) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (raw.startsWith('var(') ||
|
|
197
|
-
raw.startsWith('#') ||
|
|
198
|
-
raw.startsWith('rgb') ||
|
|
199
|
-
raw.startsWith('hsl') ||
|
|
200
|
-
raw.includes('(')) {
|
|
201
|
-
return raw;
|
|
202
|
-
}
|
|
203
|
-
return seriesColorVar(raw);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Shared chart state provided by `ChartContainer` to all nested chart
|
|
208
|
-
* components (axes, grid, tooltip, legend, chart types).
|
|
209
|
-
*
|
|
210
|
-
* All state is exposed as signals so consumers can derive computed state
|
|
211
|
-
* (scales, visible series, tooltip position) without manual subscriptions.
|
|
212
|
-
*/
|
|
213
|
-
class ChartContext {
|
|
214
|
-
/** Stable instance id — used in the `data-chart` attribute and CSS scope. */
|
|
215
|
-
id = signal('', /* @ts-ignore */
|
|
216
|
-
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
217
|
-
/** User-provided series config. */
|
|
218
|
-
config = signal({}, /* @ts-ignore */
|
|
219
|
-
...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
|
|
220
|
-
/** Measured render-area dimensions (ResizeObserver-driven). */
|
|
221
|
-
dimensions = signal({ width: 0, height: 0 }, /* @ts-ignore */
|
|
222
|
-
...(ngDevMode ? [{ debugName: "dimensions" }] : /* istanbul ignore next */ []));
|
|
223
|
-
/** Currently highlighted data point (tooltip / crosshair). */
|
|
224
|
-
activePoint = signal(null, /* @ts-ignore */
|
|
225
|
-
...(ngDevMode ? [{ debugName: "activePoint" }] : /* istanbul ignore next */ []));
|
|
226
|
-
/** Series keys the user has toggled off via legend. */
|
|
227
|
-
hiddenSeries = signal(new Set(), /* @ts-ignore */
|
|
228
|
-
...(ngDevMode ? [{ debugName: "hiddenSeries" }] : /* istanbul ignore next */ []));
|
|
229
|
-
/** Ordered list of series keys (from `config`). */
|
|
230
|
-
seriesKeys = computed(() => Object.keys(this.config()), /* @ts-ignore */
|
|
231
|
-
...(ngDevMode ? [{ debugName: "seriesKeys" }] : /* istanbul ignore next */ []));
|
|
232
|
-
/** Series keys currently visible (config order minus `hiddenSeries`). */
|
|
233
|
-
visibleSeriesKeys = computed(() => {
|
|
234
|
-
const hidden = this.hiddenSeries();
|
|
235
|
-
return this.seriesKeys().filter((k) => !hidden.has(k));
|
|
236
|
-
}, /* @ts-ignore */
|
|
237
|
-
...(ngDevMode ? [{ debugName: "visibleSeriesKeys" }] : /* istanbul ignore next */ []));
|
|
238
|
-
/** Toggle visibility of a series. */
|
|
239
|
-
toggleSeries(key) {
|
|
240
|
-
this.hiddenSeries.update((set) => {
|
|
241
|
-
const next = new Set(set);
|
|
242
|
-
if (next.has(key)) {
|
|
243
|
-
next.delete(key);
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
next.add(key);
|
|
247
|
-
}
|
|
248
|
-
return next;
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartContext, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
252
|
-
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: ChartContext, autoProvided: false });
|
|
79
|
+
if (typeof raw !== "string" || raw.length === 0) return fallback;
|
|
80
|
+
if (raw.startsWith("var(") || raw.startsWith("#") || raw.startsWith("rgb") || raw.startsWith("hsl") || raw.includes("(")) return raw;
|
|
81
|
+
return seriesColorVar(raw);
|
|
253
82
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
83
|
+
var ChartContext = class ChartContext {
|
|
84
|
+
id = signal("", ...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
|
|
85
|
+
config = signal({}, ...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
|
|
86
|
+
dimensions = signal({
|
|
87
|
+
width: 0,
|
|
88
|
+
height: 0
|
|
89
|
+
}, ...ngDevMode ? [{ debugName: "dimensions" }] : /* istanbul ignore next */ []);
|
|
90
|
+
activePoint = signal(null, ...ngDevMode ? [{ debugName: "activePoint" }] : /* istanbul ignore next */ []);
|
|
91
|
+
hiddenSeries = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "hiddenSeries" }] : /* istanbul ignore next */ []);
|
|
92
|
+
seriesKeys = computed(() => Object.keys(this.config()), ...ngDevMode ? [{ debugName: "seriesKeys" }] : /* istanbul ignore next */ []);
|
|
93
|
+
visibleSeriesKeys = computed(() => {
|
|
94
|
+
const hidden = this.hiddenSeries();
|
|
95
|
+
return this.seriesKeys().filter((k) => !hidden.has(k));
|
|
96
|
+
}, ...ngDevMode ? [{ debugName: "visibleSeriesKeys" }] : /* istanbul ignore next */ []);
|
|
97
|
+
toggleSeries(key) {
|
|
98
|
+
this.hiddenSeries.update((set) => {
|
|
99
|
+
const next = new Set(set);
|
|
100
|
+
if (next.has(key)) next.delete(key);
|
|
101
|
+
else next.add(key);
|
|
102
|
+
return next;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
106
|
+
minVersion: "12.0.0",
|
|
107
|
+
version: "22.2.2",
|
|
108
|
+
ngImport: i0,
|
|
109
|
+
type: ChartContext,
|
|
110
|
+
deps: [],
|
|
111
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
112
|
+
});
|
|
113
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
114
|
+
minVersion: "22.0.0",
|
|
115
|
+
version: "22.2.2",
|
|
116
|
+
ngImport: i0,
|
|
117
|
+
type: ChartContext,
|
|
118
|
+
autoProvided: false
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
122
|
+
minVersion: "12.0.0",
|
|
123
|
+
version: "22.2.2",
|
|
124
|
+
ngImport: i0,
|
|
125
|
+
type: ChartContext,
|
|
126
|
+
decorators: [{
|
|
127
|
+
type: Service,
|
|
128
|
+
args: [{ autoProvided: false }]
|
|
129
|
+
}]
|
|
130
|
+
});
|
|
265
131
|
function nearestCategoryIndex(ctx, localX, localY) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
// Ignore clicks far outside any band (> 1 step away).
|
|
287
|
-
if (bestDelta > step) {
|
|
288
|
-
return -1;
|
|
289
|
-
}
|
|
290
|
-
return bestIndex;
|
|
132
|
+
const scale = ctx.categoryScale();
|
|
133
|
+
const categories = ctx.categories();
|
|
134
|
+
if (!scale || categories.length === 0) return -1;
|
|
135
|
+
const pointerAlong = ctx.orientation() === "vertical" ? localX : localY;
|
|
136
|
+
const bandwidth = scale.bandwidth();
|
|
137
|
+
const step = scale.step?.() ?? bandwidth;
|
|
138
|
+
let bestIndex = -1;
|
|
139
|
+
let bestDelta = Infinity;
|
|
140
|
+
for (let i = 0; i < categories.length; i++) {
|
|
141
|
+
const center = (scale(categories[i]) ?? 0) + bandwidth / 2;
|
|
142
|
+
const delta = Math.abs(pointerAlong - center);
|
|
143
|
+
if (delta < bestDelta) {
|
|
144
|
+
bestDelta = delta;
|
|
145
|
+
bestIndex = i;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (bestDelta > step) return -1;
|
|
149
|
+
return bestIndex;
|
|
291
150
|
}
|
|
292
|
-
/** Resolve the client-space center point of a focused or clicked SVG/HTML element. */
|
|
293
151
|
function elementClientCenter(target) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
clientY: rect.top + rect.height / 2,
|
|
302
|
-
};
|
|
152
|
+
const el = target;
|
|
153
|
+
if (!el || typeof el.getBoundingClientRect !== "function") return null;
|
|
154
|
+
const rect = el.getBoundingClientRect();
|
|
155
|
+
return {
|
|
156
|
+
clientX: rect.left + rect.width / 2,
|
|
157
|
+
clientY: rect.top + rect.height / 2
|
|
158
|
+
};
|
|
303
159
|
}
|
|
304
|
-
/**
|
|
305
|
-
* Where the tooltip should sit for whichever gesture activated a mark.
|
|
306
|
-
*
|
|
307
|
-
* A pointer carries a real cursor position, so the tooltip follows it. Keyboard
|
|
308
|
-
* focus carries none, and falls back to the centre of the mark that took focus.
|
|
309
|
-
*/
|
|
310
160
|
function activationClientPoint(event) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
161
|
+
return event instanceof PointerEvent ? {
|
|
162
|
+
clientX: event.clientX,
|
|
163
|
+
clientY: event.clientY
|
|
164
|
+
} : elementClientCenter(event.currentTarget ?? event.target);
|
|
314
165
|
}
|
|
315
|
-
|
|
316
166
|
function clamp(value, min, max) {
|
|
317
|
-
|
|
167
|
+
return Math.min(max, Math.max(min, value));
|
|
318
168
|
}
|
|
319
169
|
function normalizeIndexRange(start, end, maxCount) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return { startIndex: lo, endIndex: hi };
|
|
170
|
+
if (maxCount <= 0) return null;
|
|
171
|
+
return {
|
|
172
|
+
startIndex: clamp(Math.floor(Math.min(start, end)), 0, maxCount - 1),
|
|
173
|
+
endIndex: clamp(Math.floor(Math.max(start, end)), 0, maxCount - 1)
|
|
174
|
+
};
|
|
326
175
|
}
|
|
327
176
|
function effectiveIndexRange(range, maxCount) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
: { startIndex: 0, endIndex: maxCount - 1 };
|
|
177
|
+
if (maxCount <= 0) return null;
|
|
178
|
+
return range ? normalizeIndexRange(range.startIndex, range.endIndex, maxCount) : {
|
|
179
|
+
startIndex: 0,
|
|
180
|
+
endIndex: maxCount - 1
|
|
181
|
+
};
|
|
334
182
|
}
|
|
335
183
|
function indexRangeSize(range, maxCount) {
|
|
336
|
-
|
|
337
|
-
|
|
184
|
+
const effective = effectiveIndexRange(range, maxCount);
|
|
185
|
+
return effective ? effective.endIndex - effective.startIndex + 1 : 0;
|
|
338
186
|
}
|
|
339
187
|
function sliceByIndexRange(data, range) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
return data.slice(range.startIndex, range.endIndex + 1);
|
|
188
|
+
if (!range) return data;
|
|
189
|
+
return data.slice(range.startIndex, range.endIndex + 1);
|
|
344
190
|
}
|
|
345
191
|
function zoomIndexRange(current, maxCount, anchorIndex, factor) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return { startIndex: start, endIndex: start + nextSize - 1 };
|
|
192
|
+
const base = effectiveIndexRange(current, maxCount);
|
|
193
|
+
if (!base) return null;
|
|
194
|
+
const currentSize = base.endIndex - base.startIndex + 1;
|
|
195
|
+
const nextSize = clamp(Math.round(currentSize * factor), 2, maxCount);
|
|
196
|
+
if (nextSize >= maxCount) return null;
|
|
197
|
+
const boundedAnchor = clamp(anchorIndex, base.startIndex, base.endIndex);
|
|
198
|
+
const ratio = currentSize <= 1 ? .5 : (boundedAnchor - base.startIndex) / (currentSize - 1);
|
|
199
|
+
let start = Math.round(boundedAnchor - ratio * (nextSize - 1));
|
|
200
|
+
start = clamp(start, 0, maxCount - nextSize);
|
|
201
|
+
return {
|
|
202
|
+
startIndex: start,
|
|
203
|
+
endIndex: start + nextSize - 1
|
|
204
|
+
};
|
|
360
205
|
}
|
|
361
206
|
function panIndexRange(current, maxCount, deltaSteps) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return { startIndex: start, endIndex: start + size - 1 };
|
|
207
|
+
const base = effectiveIndexRange(current, maxCount);
|
|
208
|
+
if (!base) return null;
|
|
209
|
+
const size = base.endIndex - base.startIndex + 1;
|
|
210
|
+
if (size >= maxCount) return null;
|
|
211
|
+
const start = clamp(base.startIndex + deltaSteps, 0, maxCount - size);
|
|
212
|
+
return {
|
|
213
|
+
startIndex: start,
|
|
214
|
+
endIndex: start + size - 1
|
|
215
|
+
};
|
|
372
216
|
}
|
|
373
|
-
/**
|
|
374
|
-
* The value domain for a chart drawn against a zero baseline.
|
|
375
|
-
*
|
|
376
|
-
* A bar, a line, or an area is read against the origin, so the domain has to
|
|
377
|
-
* reach it in both directions: negative data below, positive above. Clamping
|
|
378
|
-
* one end at zero is what pushed negative marks outside the plot.
|
|
379
|
-
*
|
|
380
|
-
* A dataset that is entirely zero would collapse the domain onto a point, which
|
|
381
|
-
* d3 maps to the middle of the range for every value, so it is opened by one
|
|
382
|
-
* unit instead.
|
|
383
|
-
*/
|
|
384
217
|
function zeroBaselineDomain(minValue, maxValue) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
218
|
+
const min = Math.min(0, minValue);
|
|
219
|
+
const max = Math.max(0, maxValue);
|
|
220
|
+
return min === max ? [min, max + 1] : [min, max];
|
|
388
221
|
}
|
|
389
222
|
function normalizeNumericDomain(a, b) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
return a < b ? [a, b] : [b, a];
|
|
223
|
+
if (a === b) return [a - 1, b + 1];
|
|
224
|
+
return a < b ? [a, b] : [b, a];
|
|
394
225
|
}
|
|
395
226
|
function zoomNumericDomain(current, full, anchor, factor) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
let start = anchor - ratio * nextWidth;
|
|
404
|
-
start = clamp(start, full[0], full[1] - nextWidth);
|
|
405
|
-
return [start, start + nextWidth];
|
|
227
|
+
const currentWidth = current[1] - current[0];
|
|
228
|
+
const fullWidth = full[1] - full[0];
|
|
229
|
+
const nextWidth = clamp(currentWidth * factor, fullWidth / 50, fullWidth);
|
|
230
|
+
if (nextWidth >= fullWidth) return full;
|
|
231
|
+
let start = anchor - (currentWidth === 0 ? .5 : (anchor - current[0]) / currentWidth) * nextWidth;
|
|
232
|
+
start = clamp(start, full[0], full[1] - nextWidth);
|
|
233
|
+
return [start, start + nextWidth];
|
|
406
234
|
}
|
|
407
235
|
function panNumericDomain(current, full, delta) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
236
|
+
const width = current[1] - current[0];
|
|
237
|
+
const start = clamp(current[0] + delta, full[0], full[1] - width);
|
|
238
|
+
return [start, start + width];
|
|
411
239
|
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Build the shared cartesian scaffolding.
|
|
415
|
-
*
|
|
416
|
-
* MUST be called in an injection context, so a field initializer or the
|
|
417
|
-
* constructor: it injects `ChartContext` and creates one `effect`.
|
|
418
|
-
*/
|
|
419
240
|
function setupCartesianChart(options) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const center = activationClientPoint(event);
|
|
474
|
-
root.activePoint.set({
|
|
475
|
-
// `index` stays visible-local (it addresses the rendered mark) while
|
|
476
|
-
// `datumIndex` is absolute (it addresses the data row). Both are needed.
|
|
477
|
-
index: mark.datumIndex,
|
|
478
|
-
datumIndex: resolveDatumIndex(mark),
|
|
479
|
-
seriesKey: mark.seriesKey,
|
|
480
|
-
clientX: center?.clientX,
|
|
481
|
-
clientY: center?.clientY,
|
|
482
|
-
});
|
|
483
|
-
},
|
|
484
|
-
clearActivePoint: () => root.activePoint.set(null),
|
|
485
|
-
};
|
|
241
|
+
const root = inject(ChartContext);
|
|
242
|
+
const innerWidth = computed(() => Math.max(0, root.dimensions().width - options.margin().left - options.margin().right), ...ngDevMode ? [{ debugName: "innerWidth" }] : /* istanbul ignore next */ []);
|
|
243
|
+
const innerHeight = computed(() => Math.max(0, root.dimensions().height - options.margin().top - options.margin().bottom), ...ngDevMode ? [{ debugName: "innerHeight" }] : /* istanbul ignore next */ []);
|
|
244
|
+
const viewBox = computed(() => {
|
|
245
|
+
const { width, height } = root.dimensions();
|
|
246
|
+
return `0 0 ${Math.max(0, width)} ${Math.max(0, height)}`;
|
|
247
|
+
}, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
|
|
248
|
+
const innerTransform = computed(() => `translate(${options.margin().left},${options.margin().top})`, ...ngDevMode ? [{ debugName: "innerTransform" }] : /* istanbul ignore next */ []);
|
|
249
|
+
const windowRange = computed(() => options.viewport ? effectiveIndexRange(options.viewport.zoomRange(), options.data().length) : null, ...ngDevMode ? [{ debugName: "windowRange" }] : /* istanbul ignore next */ []);
|
|
250
|
+
const visibleStartIndex = computed(() => windowRange()?.startIndex ?? 0, ...ngDevMode ? [{ debugName: "visibleStartIndex" }] : /* istanbul ignore next */ []);
|
|
251
|
+
const visibleData = computed(() => options.viewport ? sliceByIndexRange(options.data(), windowRange()) : options.data(), ...ngDevMode ? [{ debugName: "visibleData" }] : /* istanbul ignore next */ []);
|
|
252
|
+
const resolveDatumIndex = (mark) => visibleStartIndex() + mark.datumIndex;
|
|
253
|
+
const seriesLabel = (seriesKey) => root.config()[seriesKey]?.label ?? seriesKey;
|
|
254
|
+
effect(() => {
|
|
255
|
+
options.viewport?.dataCount.set(options.data().length);
|
|
256
|
+
const cartesian = options.cartesian;
|
|
257
|
+
if (cartesian) {
|
|
258
|
+
cartesian.context.orientation.set(cartesian.orientation());
|
|
259
|
+
cartesian.context.margin.set(options.margin());
|
|
260
|
+
cartesian.context.innerWidth.set(innerWidth());
|
|
261
|
+
cartesian.context.innerHeight.set(innerHeight());
|
|
262
|
+
}
|
|
263
|
+
options.publishLayout?.({
|
|
264
|
+
width: innerWidth(),
|
|
265
|
+
height: innerHeight()
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
return {
|
|
269
|
+
innerWidth,
|
|
270
|
+
innerHeight,
|
|
271
|
+
viewBox,
|
|
272
|
+
innerTransform,
|
|
273
|
+
visibleStartIndex,
|
|
274
|
+
visibleData,
|
|
275
|
+
resolveDatumIndex,
|
|
276
|
+
seriesLabel,
|
|
277
|
+
pointAriaLabel: (mark) => options.ariaLabel(mark, seriesLabel(mark.seriesKey)),
|
|
278
|
+
emitClick: (mark) => {
|
|
279
|
+
const datumIndex = resolveDatumIndex(mark);
|
|
280
|
+
options.click.emit(options.click.payload(mark, datumIndex, options.data()[datumIndex]));
|
|
281
|
+
},
|
|
282
|
+
setActivePoint: (event, mark) => {
|
|
283
|
+
const center = activationClientPoint(event);
|
|
284
|
+
root.activePoint.set({
|
|
285
|
+
index: mark.datumIndex,
|
|
286
|
+
datumIndex: resolveDatumIndex(mark),
|
|
287
|
+
seriesKey: mark.seriesKey,
|
|
288
|
+
clientX: center?.clientX,
|
|
289
|
+
clientY: center?.clientY
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
clearActivePoint: () => root.activePoint.set(null)
|
|
293
|
+
};
|
|
486
294
|
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Build the shared polar scaffolding.
|
|
490
|
-
*
|
|
491
|
-
* MUST be called in an injection context, so a field initializer or the
|
|
492
|
-
* constructor: it injects `ChartContext`.
|
|
493
|
-
*/
|
|
494
295
|
function setupPolarChart(options) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// index are the same number. Both are set because the tooltip and the
|
|
518
|
-
// crosshair read different ones.
|
|
519
|
-
index: mark.datumIndex,
|
|
520
|
-
datumIndex: mark.datumIndex,
|
|
521
|
-
seriesKey: mark.seriesKey,
|
|
522
|
-
clientX: location?.clientX,
|
|
523
|
-
clientY: location?.clientY,
|
|
524
|
-
});
|
|
525
|
-
},
|
|
526
|
-
clearActivePoint: () => root.activePoint.set(null),
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Emits a scoped `<style>` block mapping every series key in the current
|
|
532
|
-
* `ChartConfig` to a `--color-<key>` CSS custom property, scoped to
|
|
533
|
-
* `[data-chart="<id>"]`. Dark-mode values are scoped under `[data-mode="dark"]`.
|
|
534
|
-
*
|
|
535
|
-
* Implemented as an empty component that injects a real `<style>` element
|
|
536
|
-
* into its host via `Renderer2`. We avoid rendering `<style>` directly in a
|
|
537
|
-
* template — Angular hoists those into component CSS and strips
|
|
538
|
-
* interpolations from them.
|
|
539
|
-
*
|
|
540
|
-
* Consumers never instantiate this directly — `ChartContainer` renders it.
|
|
541
|
-
*/
|
|
542
|
-
class ChartStyle {
|
|
543
|
-
ctx = inject(ChartContext);
|
|
544
|
-
host = inject((ElementRef));
|
|
545
|
-
renderer = inject(Renderer2);
|
|
546
|
-
styleEl = null;
|
|
547
|
-
css = computed(() => buildChartCss(this.ctx.id(), this.ctx.config()), /* @ts-ignore */
|
|
548
|
-
...(ngDevMode ? [{ debugName: "css" }] : /* istanbul ignore next */ []));
|
|
549
|
-
constructor() {
|
|
550
|
-
effect(() => {
|
|
551
|
-
const css = this.css();
|
|
552
|
-
if (!this.styleEl) {
|
|
553
|
-
this.styleEl = this.renderer.createElement('style');
|
|
554
|
-
this.renderer.appendChild(this.host.nativeElement, this.styleEl);
|
|
555
|
-
}
|
|
556
|
-
this.styleEl.textContent = css;
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartStyle, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
560
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: ChartStyle, isStandalone: true, selector: "ChartStyle", ngImport: i0, template: '', isInline: true });
|
|
296
|
+
const root = inject(ChartContext);
|
|
297
|
+
return {
|
|
298
|
+
innerWidth: computed(() => Math.max(0, root.dimensions().width - options.margin().left - options.margin().right), ...ngDevMode ? [{ debugName: "innerWidth" }] : /* istanbul ignore next */ []),
|
|
299
|
+
innerHeight: computed(() => Math.max(0, root.dimensions().height - options.margin().top - options.margin().bottom), ...ngDevMode ? [{ debugName: "innerHeight" }] : /* istanbul ignore next */ []),
|
|
300
|
+
viewBox: computed(() => {
|
|
301
|
+
const { width, height } = root.dimensions();
|
|
302
|
+
return `0 0 ${Math.max(0, width)} ${Math.max(0, height)}`;
|
|
303
|
+
}, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []),
|
|
304
|
+
innerTransform: computed(() => `translate(${options.margin().left},${options.margin().top})`, ...ngDevMode ? [{ debugName: "innerTransform" }] : /* istanbul ignore next */ []),
|
|
305
|
+
seriesLabel: (seriesKey) => root.config()[seriesKey]?.label ?? seriesKey,
|
|
306
|
+
setActivePoint: (event, mark) => {
|
|
307
|
+
const location = activationClientPoint(event);
|
|
308
|
+
root.activePoint.set({
|
|
309
|
+
index: mark.datumIndex,
|
|
310
|
+
datumIndex: mark.datumIndex,
|
|
311
|
+
seriesKey: mark.seriesKey,
|
|
312
|
+
clientX: location?.clientX,
|
|
313
|
+
clientY: location?.clientY
|
|
314
|
+
});
|
|
315
|
+
},
|
|
316
|
+
clearActivePoint: () => root.activePoint.set(null)
|
|
317
|
+
};
|
|
561
318
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
319
|
+
var ChartStyle = class ChartStyle {
|
|
320
|
+
ctx = inject(ChartContext);
|
|
321
|
+
host = inject(ElementRef);
|
|
322
|
+
renderer = inject(Renderer2);
|
|
323
|
+
styleEl = null;
|
|
324
|
+
css = computed(() => buildChartCss(this.ctx.id(), this.ctx.config()), ...ngDevMode ? [{ debugName: "css" }] : /* istanbul ignore next */ []);
|
|
325
|
+
constructor() {
|
|
326
|
+
effect(() => {
|
|
327
|
+
const css = this.css();
|
|
328
|
+
if (!this.styleEl) {
|
|
329
|
+
this.styleEl = this.renderer.createElement("style");
|
|
330
|
+
this.renderer.appendChild(this.host.nativeElement, this.styleEl);
|
|
331
|
+
}
|
|
332
|
+
this.styleEl.textContent = css;
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
336
|
+
minVersion: "12.0.0",
|
|
337
|
+
version: "22.2.2",
|
|
338
|
+
ngImport: i0,
|
|
339
|
+
type: ChartStyle,
|
|
340
|
+
deps: [],
|
|
341
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
342
|
+
});
|
|
343
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
344
|
+
minVersion: "14.0.0",
|
|
345
|
+
version: "22.2.2",
|
|
346
|
+
type: ChartStyle,
|
|
347
|
+
isStandalone: true,
|
|
348
|
+
selector: "ChartStyle",
|
|
349
|
+
ngImport: i0,
|
|
350
|
+
template: "",
|
|
351
|
+
isInline: true
|
|
352
|
+
});
|
|
353
|
+
};
|
|
354
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
355
|
+
minVersion: "12.0.0",
|
|
356
|
+
version: "22.2.2",
|
|
357
|
+
ngImport: i0,
|
|
358
|
+
type: ChartStyle,
|
|
359
|
+
decorators: [{
|
|
360
|
+
type: Component,
|
|
361
|
+
args: [{
|
|
362
|
+
selector: "ChartStyle",
|
|
363
|
+
template: ""
|
|
364
|
+
}]
|
|
365
|
+
}],
|
|
366
|
+
ctorParameters: () => []
|
|
367
|
+
});
|
|
584
368
|
function resolveChartStyle(styleVariant, styles) {
|
|
585
|
-
|
|
369
|
+
return computed(() => styleVariant() ?? styles());
|
|
586
370
|
}
|
|
587
|
-
|
|
588
371
|
let chartIdCounter = 0;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
372
|
+
var ChartContainer = class ChartContainer {
|
|
373
|
+
ctx = inject(ChartContext);
|
|
374
|
+
zone = inject(NgZone);
|
|
375
|
+
platformId = inject(PLATFORM_ID);
|
|
376
|
+
destroyRef = inject(DestroyRef);
|
|
377
|
+
areaRef = viewChild.required("area", ...ngDevMode ? [{ debugName: "areaRef" }] : /* istanbul ignore next */ []);
|
|
378
|
+
config = input.required(...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
|
|
379
|
+
aspect = input("aspect-video", ...ngDevMode ? [{ debugName: "aspect" }] : /* istanbul ignore next */ []);
|
|
380
|
+
areaClass = computed(() => `relative flex ${this.aspect()} w-full justify-center`, ...ngDevMode ? [{ debugName: "areaClass" }] : /* istanbul ignore next */ []);
|
|
381
|
+
chartId = input(null, ...ngDevMode ? [{ debugName: "chartId" }] : /* istanbul ignore next */ []);
|
|
382
|
+
constructor() {
|
|
383
|
+
const autoId = `chart-${++chartIdCounter}`;
|
|
384
|
+
effect(() => {
|
|
385
|
+
this.ctx.id.set(this.chartId() ?? autoId);
|
|
386
|
+
});
|
|
387
|
+
effect(() => {
|
|
388
|
+
this.ctx.config.set(this.config());
|
|
389
|
+
});
|
|
390
|
+
if (isPlatformBrowser(this.platformId)) afterNextRender(() => this.observeSize());
|
|
391
|
+
}
|
|
392
|
+
observeSize() {
|
|
393
|
+
const el = this.areaRef().nativeElement;
|
|
394
|
+
if (typeof ResizeObserver === "undefined") {
|
|
395
|
+
const rect = el.getBoundingClientRect();
|
|
396
|
+
this.ctx.dimensions.set({
|
|
397
|
+
width: rect.width,
|
|
398
|
+
height: rect.height
|
|
399
|
+
});
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const observer = new ResizeObserver((entries) => {
|
|
403
|
+
for (const entry of entries) {
|
|
404
|
+
const { width, height } = entry.contentRect;
|
|
405
|
+
this.zone.run(() => this.ctx.dimensions.set({
|
|
406
|
+
width,
|
|
407
|
+
height
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
observer.observe(el);
|
|
412
|
+
this.destroyRef.onDestroy(() => observer.disconnect());
|
|
413
|
+
}
|
|
414
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
415
|
+
minVersion: "12.0.0",
|
|
416
|
+
version: "22.2.2",
|
|
417
|
+
ngImport: i0,
|
|
418
|
+
type: ChartContainer,
|
|
419
|
+
deps: [],
|
|
420
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
421
|
+
});
|
|
422
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
423
|
+
minVersion: "17.2.0",
|
|
424
|
+
version: "22.2.2",
|
|
425
|
+
type: ChartContainer,
|
|
426
|
+
isStandalone: true,
|
|
427
|
+
selector: "Chart",
|
|
428
|
+
inputs: {
|
|
429
|
+
config: {
|
|
430
|
+
classPropertyName: "config",
|
|
431
|
+
publicName: "config",
|
|
432
|
+
isSignal: true,
|
|
433
|
+
isRequired: true,
|
|
434
|
+
transformFunction: null
|
|
435
|
+
},
|
|
436
|
+
aspect: {
|
|
437
|
+
classPropertyName: "aspect",
|
|
438
|
+
publicName: "aspect",
|
|
439
|
+
isSignal: true,
|
|
440
|
+
isRequired: false,
|
|
441
|
+
transformFunction: null
|
|
442
|
+
},
|
|
443
|
+
chartId: {
|
|
444
|
+
classPropertyName: "chartId",
|
|
445
|
+
publicName: "chartId",
|
|
446
|
+
isSignal: true,
|
|
447
|
+
isRequired: false,
|
|
448
|
+
transformFunction: null
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
host: {
|
|
452
|
+
properties: { "attr.data-chart": "ctx.id()" },
|
|
453
|
+
classAttribute: "relative flex flex-col text-xs"
|
|
454
|
+
},
|
|
455
|
+
providers: [ChartContext],
|
|
456
|
+
viewQueries: [{
|
|
457
|
+
propertyName: "areaRef",
|
|
458
|
+
first: true,
|
|
459
|
+
predicate: ["area"],
|
|
460
|
+
descendants: true,
|
|
461
|
+
isSignal: true
|
|
462
|
+
}],
|
|
463
|
+
ngImport: i0,
|
|
464
|
+
template: `
|
|
665
465
|
<ChartStyle />
|
|
666
466
|
<div #area data-chart-area [class]="areaClass()">
|
|
667
467
|
<ng-content />
|
|
668
468
|
</div>
|
|
669
469
|
<ng-content select="ChartLegend" />
|
|
670
|
-
`,
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
470
|
+
`,
|
|
471
|
+
isInline: true,
|
|
472
|
+
dependencies: [{
|
|
473
|
+
kind: "component",
|
|
474
|
+
type: ChartStyle,
|
|
475
|
+
selector: "ChartStyle"
|
|
476
|
+
}]
|
|
477
|
+
});
|
|
478
|
+
};
|
|
479
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
480
|
+
minVersion: "12.0.0",
|
|
481
|
+
version: "22.2.2",
|
|
482
|
+
ngImport: i0,
|
|
483
|
+
type: ChartContainer,
|
|
484
|
+
decorators: [{
|
|
485
|
+
type: Component,
|
|
486
|
+
args: [{
|
|
487
|
+
selector: "Chart",
|
|
488
|
+
providers: [ChartContext],
|
|
489
|
+
imports: [ChartStyle],
|
|
490
|
+
host: {
|
|
491
|
+
"[attr.data-chart]": "ctx.id()",
|
|
492
|
+
class: "relative flex flex-col text-xs"
|
|
493
|
+
},
|
|
494
|
+
template: `
|
|
683
495
|
<ChartStyle />
|
|
684
496
|
<div #area data-chart-area [class]="areaClass()">
|
|
685
497
|
<ng-content />
|
|
686
498
|
</div>
|
|
687
499
|
<ng-content select="ChartLegend" />
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
500
|
+
`
|
|
501
|
+
}]
|
|
502
|
+
}],
|
|
503
|
+
ctorParameters: () => [],
|
|
504
|
+
propDecorators: {
|
|
505
|
+
areaRef: [{
|
|
506
|
+
type: i0.ViewChild,
|
|
507
|
+
args: ["area", { isSignal: true }]
|
|
508
|
+
}],
|
|
509
|
+
config: [{
|
|
510
|
+
type: i0.Input,
|
|
511
|
+
args: [{
|
|
512
|
+
isSignal: true,
|
|
513
|
+
alias: "config",
|
|
514
|
+
required: true
|
|
515
|
+
}]
|
|
516
|
+
}],
|
|
517
|
+
aspect: [{
|
|
518
|
+
type: i0.Input,
|
|
519
|
+
args: [{
|
|
520
|
+
isSignal: true,
|
|
521
|
+
alias: "aspect",
|
|
522
|
+
required: false
|
|
523
|
+
}]
|
|
524
|
+
}],
|
|
525
|
+
chartId: [{
|
|
526
|
+
type: i0.Input,
|
|
527
|
+
args: [{
|
|
528
|
+
isSignal: true,
|
|
529
|
+
alias: "chartId",
|
|
530
|
+
required: false
|
|
531
|
+
}]
|
|
532
|
+
}]
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
var ChartDataTable = class ChartDataTable {
|
|
536
|
+
data = input.required(...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
|
|
537
|
+
columns = input.required(...ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []);
|
|
538
|
+
label = input("Chart data", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
539
|
+
rowHeaderKey = input(null, ...ngDevMode ? [{ debugName: "rowHeaderKey" }] : /* istanbul ignore next */ []);
|
|
540
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
541
|
+
minVersion: "12.0.0",
|
|
542
|
+
version: "22.2.2",
|
|
543
|
+
ngImport: i0,
|
|
544
|
+
type: ChartDataTable,
|
|
545
|
+
deps: [],
|
|
546
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
547
|
+
});
|
|
548
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
549
|
+
minVersion: "17.0.0",
|
|
550
|
+
version: "22.2.2",
|
|
551
|
+
type: ChartDataTable,
|
|
552
|
+
isStandalone: true,
|
|
553
|
+
selector: "ChartDataTable",
|
|
554
|
+
inputs: {
|
|
555
|
+
data: {
|
|
556
|
+
classPropertyName: "data",
|
|
557
|
+
publicName: "data",
|
|
558
|
+
isSignal: true,
|
|
559
|
+
isRequired: true,
|
|
560
|
+
transformFunction: null
|
|
561
|
+
},
|
|
562
|
+
columns: {
|
|
563
|
+
classPropertyName: "columns",
|
|
564
|
+
publicName: "columns",
|
|
565
|
+
isSignal: true,
|
|
566
|
+
isRequired: true,
|
|
567
|
+
transformFunction: null
|
|
568
|
+
},
|
|
569
|
+
label: {
|
|
570
|
+
classPropertyName: "label",
|
|
571
|
+
publicName: "label",
|
|
572
|
+
isSignal: true,
|
|
573
|
+
isRequired: false,
|
|
574
|
+
transformFunction: null
|
|
575
|
+
},
|
|
576
|
+
rowHeaderKey: {
|
|
577
|
+
classPropertyName: "rowHeaderKey",
|
|
578
|
+
publicName: "rowHeaderKey",
|
|
579
|
+
isSignal: true,
|
|
580
|
+
isRequired: false,
|
|
581
|
+
transformFunction: null
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
ngImport: i0,
|
|
585
|
+
template: `
|
|
704
586
|
<table class="sr-only" [attr.aria-label]="label()">
|
|
705
587
|
<thead>
|
|
706
588
|
<tr>
|
|
@@ -723,13 +605,20 @@ class ChartDataTable {
|
|
|
723
605
|
}
|
|
724
606
|
</tbody>
|
|
725
607
|
</table>
|
|
726
|
-
`,
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
608
|
+
`,
|
|
609
|
+
isInline: true
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
613
|
+
minVersion: "12.0.0",
|
|
614
|
+
version: "22.2.2",
|
|
615
|
+
ngImport: i0,
|
|
616
|
+
type: ChartDataTable,
|
|
617
|
+
decorators: [{
|
|
618
|
+
type: Component,
|
|
619
|
+
args: [{
|
|
620
|
+
selector: "ChartDataTable",
|
|
621
|
+
template: `
|
|
733
622
|
<table class="sr-only" [attr.aria-label]="label()">
|
|
734
623
|
<thead>
|
|
735
624
|
<tr>
|
|
@@ -752,735 +641,642 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
752
641
|
}
|
|
753
642
|
</tbody>
|
|
754
643
|
</table>
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
644
|
+
`
|
|
645
|
+
}]
|
|
646
|
+
}],
|
|
647
|
+
propDecorators: {
|
|
648
|
+
data: [{
|
|
649
|
+
type: i0.Input,
|
|
650
|
+
args: [{
|
|
651
|
+
isSignal: true,
|
|
652
|
+
alias: "data",
|
|
653
|
+
required: true
|
|
654
|
+
}]
|
|
655
|
+
}],
|
|
656
|
+
columns: [{
|
|
657
|
+
type: i0.Input,
|
|
658
|
+
args: [{
|
|
659
|
+
isSignal: true,
|
|
660
|
+
alias: "columns",
|
|
661
|
+
required: true
|
|
662
|
+
}]
|
|
663
|
+
}],
|
|
664
|
+
label: [{
|
|
665
|
+
type: i0.Input,
|
|
666
|
+
args: [{
|
|
667
|
+
isSignal: true,
|
|
668
|
+
alias: "label",
|
|
669
|
+
required: false
|
|
670
|
+
}]
|
|
671
|
+
}],
|
|
672
|
+
rowHeaderKey: [{
|
|
673
|
+
type: i0.Input,
|
|
674
|
+
args: [{
|
|
675
|
+
isSignal: true,
|
|
676
|
+
alias: "rowHeaderKey",
|
|
677
|
+
required: false
|
|
678
|
+
}]
|
|
679
|
+
}]
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
var ChartRovingFocus = class ChartRovingFocus {
|
|
683
|
+
host = inject(ElementRef);
|
|
684
|
+
destroyRef = inject(DestroyRef);
|
|
685
|
+
activeMark = null;
|
|
686
|
+
constructor() {
|
|
687
|
+
afterNextRender(() => {
|
|
688
|
+
this.syncTabStops(this.marks());
|
|
689
|
+
if (typeof MutationObserver === "undefined") return;
|
|
690
|
+
const observer = new MutationObserver(() => this.syncTabStops(this.marks()));
|
|
691
|
+
observer.observe(this.host.nativeElement, {
|
|
692
|
+
childList: true,
|
|
693
|
+
subtree: true
|
|
694
|
+
});
|
|
695
|
+
this.destroyRef.onDestroy(() => observer.disconnect());
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
onFocusIn(event) {
|
|
699
|
+
const target = event.target;
|
|
700
|
+
if (!(target instanceof Element) || !this.marks().includes(target)) return;
|
|
701
|
+
this.activeMark = target;
|
|
702
|
+
this.syncTabStops(this.marks());
|
|
703
|
+
}
|
|
704
|
+
onKeydown(event) {
|
|
705
|
+
const marks = this.marks();
|
|
706
|
+
const target = event.target;
|
|
707
|
+
const currentIndex = target instanceof Element ? marks.indexOf(target) : -1;
|
|
708
|
+
if (currentIndex < 0 || marks.length < 2) return;
|
|
709
|
+
let targetIndex = null;
|
|
710
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") targetIndex = (currentIndex + 1) % marks.length;
|
|
711
|
+
else if (event.key === "ArrowLeft" || event.key === "ArrowUp") targetIndex = (currentIndex - 1 + marks.length) % marks.length;
|
|
712
|
+
else if (event.key === "Home") targetIndex = 0;
|
|
713
|
+
else if (event.key === "End") targetIndex = marks.length - 1;
|
|
714
|
+
if (targetIndex === null) return;
|
|
715
|
+
event.preventDefault();
|
|
716
|
+
const next = marks[targetIndex];
|
|
717
|
+
this.activeMark = next;
|
|
718
|
+
this.syncTabStops(marks);
|
|
719
|
+
next.focus();
|
|
720
|
+
}
|
|
721
|
+
marks() {
|
|
722
|
+
return Array.from(this.host.nativeElement.querySelectorAll("[role=\"img\"][tabindex]"));
|
|
723
|
+
}
|
|
724
|
+
syncTabStops(marks) {
|
|
725
|
+
if (marks.length === 0) {
|
|
726
|
+
this.activeMark = null;
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
const active = this.activeMark && marks.includes(this.activeMark) ? this.activeMark : marks[0];
|
|
730
|
+
this.activeMark = active;
|
|
731
|
+
for (const mark of marks) mark.setAttribute("tabindex", mark === active ? "0" : "-1");
|
|
732
|
+
}
|
|
733
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
734
|
+
minVersion: "12.0.0",
|
|
735
|
+
version: "22.2.2",
|
|
736
|
+
ngImport: i0,
|
|
737
|
+
type: ChartRovingFocus,
|
|
738
|
+
deps: [],
|
|
739
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
740
|
+
});
|
|
741
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
742
|
+
minVersion: "14.0.0",
|
|
743
|
+
version: "22.2.2",
|
|
744
|
+
type: ChartRovingFocus,
|
|
745
|
+
isStandalone: true,
|
|
746
|
+
selector: "svg[ChartRovingFocus]",
|
|
747
|
+
host: { listeners: {
|
|
748
|
+
"focusin": "onFocusIn($event)",
|
|
749
|
+
"keydown": "onKeydown($event)"
|
|
750
|
+
} },
|
|
751
|
+
ngImport: i0
|
|
752
|
+
});
|
|
753
|
+
};
|
|
754
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
755
|
+
minVersion: "12.0.0",
|
|
756
|
+
version: "22.2.2",
|
|
757
|
+
ngImport: i0,
|
|
758
|
+
type: ChartRovingFocus,
|
|
759
|
+
decorators: [{
|
|
760
|
+
type: Directive,
|
|
761
|
+
args: [{
|
|
762
|
+
selector: "svg[ChartRovingFocus]",
|
|
763
|
+
host: {
|
|
764
|
+
"(focusin)": "onFocusIn($event)",
|
|
765
|
+
"(keydown)": "onKeydown($event)"
|
|
766
|
+
}
|
|
767
|
+
}]
|
|
768
|
+
}],
|
|
769
|
+
ctorParameters: () => []
|
|
770
|
+
});
|
|
771
|
+
var ChartMarkFocus = class ChartMarkFocus {
|
|
772
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
773
|
+
minVersion: "12.0.0",
|
|
774
|
+
version: "22.2.2",
|
|
775
|
+
ngImport: i0,
|
|
776
|
+
type: ChartMarkFocus,
|
|
777
|
+
deps: [],
|
|
778
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
779
|
+
});
|
|
780
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
781
|
+
minVersion: "14.0.0",
|
|
782
|
+
version: "22.2.2",
|
|
783
|
+
type: ChartMarkFocus,
|
|
784
|
+
isStandalone: true,
|
|
785
|
+
selector: "[ChartMarkFocus]",
|
|
786
|
+
host: { classAttribute: "outline-none focus-visible:stroke-ring focus-visible:stroke-2" },
|
|
787
|
+
ngImport: i0
|
|
788
|
+
});
|
|
789
|
+
};
|
|
790
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
791
|
+
minVersion: "12.0.0",
|
|
792
|
+
version: "22.2.2",
|
|
793
|
+
ngImport: i0,
|
|
794
|
+
type: ChartMarkFocus,
|
|
795
|
+
decorators: [{
|
|
796
|
+
type: Directive,
|
|
797
|
+
args: [{
|
|
798
|
+
selector: "[ChartMarkFocus]",
|
|
799
|
+
host: { class: "outline-none focus-visible:stroke-ring focus-visible:stroke-2" }
|
|
800
|
+
}]
|
|
801
|
+
}]
|
|
802
|
+
});
|
|
803
|
+
const DEFAULT_CARTESIAN_MARGIN = {
|
|
804
|
+
top: 8,
|
|
805
|
+
right: 8,
|
|
806
|
+
bottom: 24,
|
|
807
|
+
left: 40
|
|
808
|
+
};
|
|
809
|
+
const DEFAULT_POLAR_MARGIN = {
|
|
810
|
+
top: 8,
|
|
811
|
+
right: 8,
|
|
812
|
+
bottom: 8,
|
|
813
|
+
left: 8
|
|
814
|
+
};
|
|
815
|
+
const DEFAULT_RADAR_MARGIN = {
|
|
816
|
+
top: 24,
|
|
817
|
+
right: 24,
|
|
818
|
+
bottom: 24,
|
|
819
|
+
left: 24
|
|
820
|
+
};
|
|
899
821
|
const DEFAULT_CARTESIAN_MARGIN_UNITS = {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
822
|
+
top: 2,
|
|
823
|
+
right: 2,
|
|
824
|
+
bottom: 6,
|
|
825
|
+
left: 10
|
|
826
|
+
};
|
|
827
|
+
const DEFAULT_POLAR_MARGIN_UNITS = {
|
|
828
|
+
top: 2,
|
|
829
|
+
right: 2,
|
|
830
|
+
bottom: 2,
|
|
831
|
+
left: 2
|
|
904
832
|
};
|
|
905
|
-
const DEFAULT_POLAR_MARGIN_UNITS = { top: 2, right: 2, bottom: 2, left: 2 };
|
|
906
833
|
const DEFAULT_RADAR_MARGIN_UNITS = {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
834
|
+
top: 6,
|
|
835
|
+
right: 6,
|
|
836
|
+
bottom: 6,
|
|
837
|
+
left: 6
|
|
911
838
|
};
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
*/
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
type: Service,
|
|
947
|
-
args: [{ autoProvided: false }]
|
|
948
|
-
}] });
|
|
949
|
-
/** Resolve the scale that maps to the X axis for a given orientation. */
|
|
839
|
+
var CartesianContext = class CartesianContext {
|
|
840
|
+
innerWidth = signal(0, ...ngDevMode ? [{ debugName: "innerWidth" }] : /* istanbul ignore next */ []);
|
|
841
|
+
innerHeight = signal(0, ...ngDevMode ? [{ debugName: "innerHeight" }] : /* istanbul ignore next */ []);
|
|
842
|
+
margin = signal(DEFAULT_CARTESIAN_MARGIN, ...ngDevMode ? [{ debugName: "margin" }] : /* istanbul ignore next */ []);
|
|
843
|
+
orientation = signal("vertical", ...ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []);
|
|
844
|
+
categoryScale = signal(null, ...ngDevMode ? [{ debugName: "categoryScale" }] : /* istanbul ignore next */ []);
|
|
845
|
+
valueScale = signal(null, ...ngDevMode ? [{ debugName: "valueScale" }] : /* istanbul ignore next */ []);
|
|
846
|
+
categories = signal([], ...ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []);
|
|
847
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
848
|
+
minVersion: "12.0.0",
|
|
849
|
+
version: "22.2.2",
|
|
850
|
+
ngImport: i0,
|
|
851
|
+
type: CartesianContext,
|
|
852
|
+
deps: [],
|
|
853
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
854
|
+
});
|
|
855
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
856
|
+
minVersion: "22.0.0",
|
|
857
|
+
version: "22.2.2",
|
|
858
|
+
ngImport: i0,
|
|
859
|
+
type: CartesianContext,
|
|
860
|
+
autoProvided: false
|
|
861
|
+
});
|
|
862
|
+
};
|
|
863
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
864
|
+
minVersion: "12.0.0",
|
|
865
|
+
version: "22.2.2",
|
|
866
|
+
ngImport: i0,
|
|
867
|
+
type: CartesianContext,
|
|
868
|
+
decorators: [{
|
|
869
|
+
type: Service,
|
|
870
|
+
args: [{ autoProvided: false }]
|
|
871
|
+
}]
|
|
872
|
+
});
|
|
950
873
|
function xScale(ctx) {
|
|
951
|
-
|
|
874
|
+
return computed(() => ctx.orientation() === "vertical" ? ctx.categoryScale() : ctx.valueScale());
|
|
952
875
|
}
|
|
953
|
-
/** Resolve the scale that maps to the Y axis for a given orientation. */
|
|
954
876
|
function yScale(ctx) {
|
|
955
|
-
|
|
877
|
+
return computed(() => ctx.orientation() === "vertical" ? ctx.valueScale() : ctx.categoryScale());
|
|
956
878
|
}
|
|
957
|
-
/**
|
|
958
|
-
* The plot margin actually in effect: the consumer's `margin` input when they
|
|
959
|
-
* set one, otherwise the default scaled by the live spacing unit.
|
|
960
|
-
*
|
|
961
|
-
* An explicit `margin` always wins. A consumer who has already tuned their
|
|
962
|
-
* gutters chose those exact numbers, and quietly rescaling them when the
|
|
963
|
-
* density axis moves would override a decision they made on purpose.
|
|
964
|
-
*
|
|
965
|
-
* This is why the `margin` inputs accept `null` and default to it: a chart has
|
|
966
|
-
* to be able to tell "the caller wants 8px here" apart from "nobody said", and
|
|
967
|
-
* an eagerly-defaulted object cannot express the difference.
|
|
968
|
-
*/
|
|
969
879
|
function resolveChartMargin(margin, units, space) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
};
|
|
981
|
-
});
|
|
880
|
+
return computed(() => {
|
|
881
|
+
const explicit = margin();
|
|
882
|
+
if (explicit) return explicit;
|
|
883
|
+
return {
|
|
884
|
+
top: space.scale(units.top),
|
|
885
|
+
right: space.scale(units.right),
|
|
886
|
+
bottom: space.scale(units.bottom),
|
|
887
|
+
left: space.scale(units.left)
|
|
888
|
+
};
|
|
889
|
+
});
|
|
982
890
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
891
|
+
var CategoricalViewportContext = class CategoricalViewportContext {
|
|
892
|
+
dataCount = signal(0, ...ngDevMode ? [{ debugName: "dataCount" }] : /* istanbul ignore next */ []);
|
|
893
|
+
brushRange = signal(null, ...ngDevMode ? [{ debugName: "brushRange" }] : /* istanbul ignore next */ []);
|
|
894
|
+
zoomRange = signal(null, ...ngDevMode ? [{ debugName: "zoomRange" }] : /* istanbul ignore next */ []);
|
|
895
|
+
hasZoom = computed(() => {
|
|
896
|
+
const range = this.zoomRange();
|
|
897
|
+
const count = this.dataCount();
|
|
898
|
+
return !!range && count > 0 && (range.startIndex > 0 || range.endIndex < count - 1);
|
|
899
|
+
}, ...ngDevMode ? [{ debugName: "hasZoom" }] : /* istanbul ignore next */ []);
|
|
900
|
+
resetZoom() {
|
|
901
|
+
this.brushRange.set(null);
|
|
902
|
+
this.zoomRange.set(null);
|
|
903
|
+
}
|
|
904
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
905
|
+
minVersion: "12.0.0",
|
|
906
|
+
version: "22.2.2",
|
|
907
|
+
ngImport: i0,
|
|
908
|
+
type: CategoricalViewportContext,
|
|
909
|
+
deps: [],
|
|
910
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
911
|
+
});
|
|
912
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
913
|
+
minVersion: "22.0.0",
|
|
914
|
+
version: "22.2.2",
|
|
915
|
+
ngImport: i0,
|
|
916
|
+
type: CategoricalViewportContext,
|
|
917
|
+
autoProvided: false
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
921
|
+
minVersion: "12.0.0",
|
|
922
|
+
version: "22.2.2",
|
|
923
|
+
ngImport: i0,
|
|
924
|
+
type: CategoricalViewportContext,
|
|
925
|
+
decorators: [{
|
|
926
|
+
type: Service,
|
|
927
|
+
args: [{ autoProvided: false }]
|
|
928
|
+
}]
|
|
929
|
+
});
|
|
930
|
+
var ScatterViewportContext = class ScatterViewportContext {
|
|
931
|
+
innerWidth = signal(0, ...ngDevMode ? [{ debugName: "innerWidth" }] : /* istanbul ignore next */ []);
|
|
932
|
+
innerHeight = signal(0, ...ngDevMode ? [{ debugName: "innerHeight" }] : /* istanbul ignore next */ []);
|
|
933
|
+
fullXDomain = signal(null, ...ngDevMode ? [{ debugName: "fullXDomain" }] : /* istanbul ignore next */ []);
|
|
934
|
+
fullYDomain = signal(null, ...ngDevMode ? [{ debugName: "fullYDomain" }] : /* istanbul ignore next */ []);
|
|
935
|
+
zoomXDomain = signal(null, ...ngDevMode ? [{ debugName: "zoomXDomain" }] : /* istanbul ignore next */ []);
|
|
936
|
+
zoomYDomain = signal(null, ...ngDevMode ? [{ debugName: "zoomYDomain" }] : /* istanbul ignore next */ []);
|
|
937
|
+
xScale = signal(null, ...ngDevMode ? [{ debugName: "xScale" }] : /* istanbul ignore next */ []);
|
|
938
|
+
yScale = signal(null, ...ngDevMode ? [{ debugName: "yScale" }] : /* istanbul ignore next */ []);
|
|
939
|
+
hasZoom = computed(() => this.zoomXDomain() !== null || this.zoomYDomain() !== null, ...ngDevMode ? [{ debugName: "hasZoom" }] : /* istanbul ignore next */ []);
|
|
940
|
+
resetZoom() {
|
|
941
|
+
this.zoomXDomain.set(null);
|
|
942
|
+
this.zoomYDomain.set(null);
|
|
943
|
+
}
|
|
944
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
945
|
+
minVersion: "12.0.0",
|
|
946
|
+
version: "22.2.2",
|
|
947
|
+
ngImport: i0,
|
|
948
|
+
type: ScatterViewportContext,
|
|
949
|
+
deps: [],
|
|
950
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
951
|
+
});
|
|
952
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
953
|
+
minVersion: "22.0.0",
|
|
954
|
+
version: "22.2.2",
|
|
955
|
+
ngImport: i0,
|
|
956
|
+
type: ScatterViewportContext,
|
|
957
|
+
autoProvided: false
|
|
958
|
+
});
|
|
959
|
+
};
|
|
960
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
961
|
+
minVersion: "12.0.0",
|
|
962
|
+
version: "22.2.2",
|
|
963
|
+
ngImport: i0,
|
|
964
|
+
type: ScatterViewportContext,
|
|
965
|
+
decorators: [{
|
|
966
|
+
type: Service,
|
|
967
|
+
args: [{ autoProvided: false }]
|
|
968
|
+
}]
|
|
969
|
+
});
|
|
1041
970
|
function bandTicks(scale) {
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
971
|
+
const half = scale.bandwidth() / 2;
|
|
972
|
+
return scale.domain().map((value) => ({
|
|
973
|
+
value,
|
|
974
|
+
offset: (scale(value) ?? 0) + half,
|
|
975
|
+
label: value
|
|
976
|
+
}));
|
|
1048
977
|
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Produce ticks for a linear scale.
|
|
1051
|
-
*
|
|
1052
|
-
* @param scale The linear scale.
|
|
1053
|
-
* @param count Approximate number of ticks (hint, d3 may return fewer/more).
|
|
1054
|
-
* @param formatter Label formatter.
|
|
1055
|
-
*/
|
|
1056
978
|
function linearTicks(scale, count = 5, formatter = (v) => String(v)) {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
979
|
+
return scale.ticks(count).map((value) => ({
|
|
980
|
+
value,
|
|
981
|
+
offset: scale(value),
|
|
982
|
+
label: formatter(value)
|
|
983
|
+
}));
|
|
1062
984
|
}
|
|
1063
|
-
|
|
1064
|
-
/**
|
|
1065
|
-
* Read a numeric value from a datum, tolerating strings.
|
|
1066
|
-
*
|
|
1067
|
-
* Every layout in this library reads its numbers through here. Bar and line
|
|
1068
|
-
* each used to carry their own identical copy while the polar and scatter
|
|
1069
|
-
* layouts reached for a bare `Number(d[key] ?? 0)`, so the same dataset drew
|
|
1070
|
-
* correctly as a bar chart and silently lost marks as a pie: `Number('n/a')`
|
|
1071
|
-
* is `NaN`, and a `NaN` flows straight into the path data.
|
|
1072
|
-
*
|
|
1073
|
-
* Anything that is not a finite number or a parseable numeric string reads as
|
|
1074
|
-
* `0`. That is the behaviour bar and line already shipped, so it is the one the
|
|
1075
|
-
* rest of the family adopts.
|
|
1076
|
-
*/
|
|
1077
985
|
function readNumber(datum, key) {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
}
|
|
1086
|
-
return 0;
|
|
986
|
+
const raw = datum[key];
|
|
987
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
988
|
+
if (typeof raw === "string") {
|
|
989
|
+
const parsed = Number(raw);
|
|
990
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
991
|
+
}
|
|
992
|
+
return 0;
|
|
1087
993
|
}
|
|
1088
|
-
|
|
1089
994
|
function curveFor(curve) {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
case 'linear':
|
|
1096
|
-
default:
|
|
1097
|
-
return curveLinear;
|
|
1098
|
-
}
|
|
995
|
+
switch (curve) {
|
|
996
|
+
case "monotone": return curveMonotoneX;
|
|
997
|
+
case "step": return curveStep;
|
|
998
|
+
default: return curveLinear;
|
|
999
|
+
}
|
|
1099
1000
|
}
|
|
1100
|
-
/** Build category + value scales for point-based charts (line / area). */
|
|
1101
1001
|
function buildCartesianScales(input) {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
const valueScale = scaleLinear()
|
|
1113
|
-
.domain([domainMin, domainMax])
|
|
1114
|
-
.nice()
|
|
1115
|
-
.range(isVertical ? [innerHeight, 0] : [0, innerWidth]);
|
|
1116
|
-
return { categories, categoryScale, valueScale };
|
|
1002
|
+
const { data, xKey, seriesKeys, orientation, innerWidth, innerHeight } = input;
|
|
1003
|
+
const isVertical = orientation === "vertical";
|
|
1004
|
+
const categories = data.map((d) => String(d[xKey] ?? ""));
|
|
1005
|
+
const categoryScale = scalePoint().domain(categories).range(isVertical ? [0, innerWidth] : [0, innerHeight]).padding(0);
|
|
1006
|
+
const [domainMin, domainMax] = zeroBaselineDomain(min(data, (d) => min(seriesKeys, (k) => readNumber(d, k)) ?? 0) ?? 0, max(data, (d) => max(seriesKeys, (k) => readNumber(d, k)) ?? 0) ?? 0);
|
|
1007
|
+
return {
|
|
1008
|
+
categories,
|
|
1009
|
+
categoryScale,
|
|
1010
|
+
valueScale: scaleLinear().domain([domainMin, domainMax]).nice().range(isVertical ? [innerHeight, 0] : [0, innerWidth])
|
|
1011
|
+
};
|
|
1117
1012
|
}
|
|
1118
|
-
/** Compute line-chart geometry. */
|
|
1119
1013
|
function computeLineLayout(input) {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
valueScale,
|
|
1157
|
-
categories,
|
|
1158
|
-
};
|
|
1014
|
+
const { data, seriesKeys, orientation, curve } = input;
|
|
1015
|
+
const { categories, categoryScale, valueScale } = buildCartesianScales(input);
|
|
1016
|
+
const isVertical = orientation === "vertical";
|
|
1017
|
+
const allPoints = [];
|
|
1018
|
+
const series = [];
|
|
1019
|
+
for (const seriesKey of seriesKeys) {
|
|
1020
|
+
const points = data.map((d, datumIndex) => {
|
|
1021
|
+
const value = readNumber(d, seriesKey);
|
|
1022
|
+
const category = categories[datumIndex];
|
|
1023
|
+
const c = categoryScale(category) ?? 0;
|
|
1024
|
+
const v = valueScale(value);
|
|
1025
|
+
return {
|
|
1026
|
+
seriesKey,
|
|
1027
|
+
datumIndex,
|
|
1028
|
+
category,
|
|
1029
|
+
value,
|
|
1030
|
+
x: isVertical ? c : v,
|
|
1031
|
+
y: isVertical ? v : c
|
|
1032
|
+
};
|
|
1033
|
+
});
|
|
1034
|
+
allPoints.push(...points);
|
|
1035
|
+
const generator = line().x((p) => p.x).y((p) => p.y).curve(curveFor(curve));
|
|
1036
|
+
series.push({
|
|
1037
|
+
seriesKey,
|
|
1038
|
+
color: seriesColorVar(seriesKey),
|
|
1039
|
+
linePath: generator(points) ?? "",
|
|
1040
|
+
points
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
return {
|
|
1044
|
+
series,
|
|
1045
|
+
points: allPoints,
|
|
1046
|
+
categoryScale,
|
|
1047
|
+
valueScale,
|
|
1048
|
+
categories
|
|
1049
|
+
};
|
|
1159
1050
|
}
|
|
1160
|
-
/** Compute area-chart geometry (single or stacked). */
|
|
1161
1051
|
function computeAreaLayout(input) {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
}
|
|
1165
|
-
return computeSingleArea(input);
|
|
1052
|
+
if (input.stacked && input.seriesKeys.length > 0) return computeStackedArea(input);
|
|
1053
|
+
return computeSingleArea(input);
|
|
1166
1054
|
}
|
|
1167
1055
|
function computeSingleArea(input) {
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
linePath: lineGen(points) ?? '',
|
|
1209
|
-
areaPath: areaGen(points) ?? '',
|
|
1210
|
-
points,
|
|
1211
|
-
});
|
|
1212
|
-
}
|
|
1213
|
-
return {
|
|
1214
|
-
series,
|
|
1215
|
-
points: allPoints,
|
|
1216
|
-
categoryScale,
|
|
1217
|
-
valueScale,
|
|
1218
|
-
categories,
|
|
1219
|
-
stacked: false,
|
|
1220
|
-
};
|
|
1056
|
+
const { data, seriesKeys, orientation, curve } = input;
|
|
1057
|
+
const { categories, categoryScale, valueScale } = buildCartesianScales(input);
|
|
1058
|
+
const isVertical = orientation === "vertical";
|
|
1059
|
+
const baseline = isVertical ? valueScale(0) : valueScale(0);
|
|
1060
|
+
const allPoints = [];
|
|
1061
|
+
const series = [];
|
|
1062
|
+
for (const seriesKey of seriesKeys) {
|
|
1063
|
+
const points = data.map((d, datumIndex) => {
|
|
1064
|
+
const value = readNumber(d, seriesKey);
|
|
1065
|
+
const category = categories[datumIndex];
|
|
1066
|
+
const c = categoryScale(category) ?? 0;
|
|
1067
|
+
const v = valueScale(value);
|
|
1068
|
+
return {
|
|
1069
|
+
seriesKey,
|
|
1070
|
+
datumIndex,
|
|
1071
|
+
category,
|
|
1072
|
+
value,
|
|
1073
|
+
x: isVertical ? c : v,
|
|
1074
|
+
y: isVertical ? v : c
|
|
1075
|
+
};
|
|
1076
|
+
});
|
|
1077
|
+
allPoints.push(...points);
|
|
1078
|
+
const lineGen = line().x((p) => p.x).y((p) => p.y).curve(curveFor(curve));
|
|
1079
|
+
const areaGen = isVertical ? area().x((p) => p.x).y0(baseline).y1((p) => p.y).curve(curveFor(curve)) : area().y((p) => p.y).x0(baseline).x1((p) => p.x).curve(curveFor(curve));
|
|
1080
|
+
series.push({
|
|
1081
|
+
seriesKey,
|
|
1082
|
+
color: seriesColorVar(seriesKey),
|
|
1083
|
+
linePath: lineGen(points) ?? "",
|
|
1084
|
+
areaPath: areaGen(points) ?? "",
|
|
1085
|
+
points
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
return {
|
|
1089
|
+
series,
|
|
1090
|
+
points: allPoints,
|
|
1091
|
+
categoryScale,
|
|
1092
|
+
valueScale,
|
|
1093
|
+
categories,
|
|
1094
|
+
stacked: false
|
|
1095
|
+
};
|
|
1221
1096
|
}
|
|
1222
1097
|
function computeStackedArea(input) {
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
.x(([x]) => x)
|
|
1280
|
-
.y0(([, , y0]) => y0)
|
|
1281
|
-
.y1(([, y1]) => y1)
|
|
1282
|
-
.curve(curveFor(curve))
|
|
1283
|
-
: area()
|
|
1284
|
-
.y(([x]) => x)
|
|
1285
|
-
.x0(([, , x0]) => x0)
|
|
1286
|
-
.x1(([, x1]) => x1)
|
|
1287
|
-
.curve(curveFor(curve));
|
|
1288
|
-
const tuples = layer.map((p, i) => {
|
|
1289
|
-
const c = categoryScale(categories[i]) ?? 0;
|
|
1290
|
-
return [c, valueScale(p[1]), valueScale(p[0])];
|
|
1291
|
-
});
|
|
1292
|
-
return {
|
|
1293
|
-
seriesKey,
|
|
1294
|
-
color: seriesColorVar(seriesKey),
|
|
1295
|
-
linePath: lineGen(tuples) ?? '',
|
|
1296
|
-
areaPath: areaGen(tuples) ?? '',
|
|
1297
|
-
points,
|
|
1298
|
-
};
|
|
1299
|
-
});
|
|
1300
|
-
return {
|
|
1301
|
-
series,
|
|
1302
|
-
points: allPoints,
|
|
1303
|
-
categoryScale,
|
|
1304
|
-
valueScale,
|
|
1305
|
-
categories,
|
|
1306
|
-
stacked: true,
|
|
1307
|
-
};
|
|
1098
|
+
const { data, seriesKeys, orientation, innerWidth, innerHeight, xKey, curve, expanded } = input;
|
|
1099
|
+
const isVertical = orientation === "vertical";
|
|
1100
|
+
const categories = data.map((d) => String(d[xKey] ?? ""));
|
|
1101
|
+
const categoryScale = scalePoint().domain(categories).range(isVertical ? [0, innerWidth] : [0, innerHeight]).padding(0);
|
|
1102
|
+
const normalized = data.map((d) => {
|
|
1103
|
+
const out = {};
|
|
1104
|
+
for (const k of seriesKeys) out[k] = readNumber(d, k);
|
|
1105
|
+
return out;
|
|
1106
|
+
});
|
|
1107
|
+
const stackGenerator = stack().keys(seriesKeys);
|
|
1108
|
+
if (expanded) stackGenerator.offset(stackOffsetExpand);
|
|
1109
|
+
const stackSeries = stackGenerator(normalized);
|
|
1110
|
+
const [domainMin, domainMax] = zeroBaselineDomain(expanded ? 0 : min(stackSeries, (layer) => min(layer, (p) => Math.min(p[0], p[1]))) ?? 0, expanded ? 1 : max(stackSeries, (layer) => max(layer, (p) => Math.max(p[0], p[1]))) ?? 0);
|
|
1111
|
+
const valueScale = scaleLinear().domain([domainMin, domainMax]).range(isVertical ? [innerHeight, 0] : [0, innerWidth]);
|
|
1112
|
+
if (!expanded) valueScale.nice();
|
|
1113
|
+
const allPoints = [];
|
|
1114
|
+
return {
|
|
1115
|
+
series: stackSeries.map((layer) => {
|
|
1116
|
+
const seriesKey = layer.key;
|
|
1117
|
+
const points = layer.map((p, datumIndex) => {
|
|
1118
|
+
const category = categories[datumIndex];
|
|
1119
|
+
const c = categoryScale(category) ?? 0;
|
|
1120
|
+
const upper = valueScale(p[1]);
|
|
1121
|
+
return {
|
|
1122
|
+
seriesKey,
|
|
1123
|
+
datumIndex,
|
|
1124
|
+
category,
|
|
1125
|
+
value: p[1] - p[0],
|
|
1126
|
+
x: isVertical ? c : upper,
|
|
1127
|
+
y: isVertical ? upper : c
|
|
1128
|
+
};
|
|
1129
|
+
});
|
|
1130
|
+
allPoints.push(...points);
|
|
1131
|
+
const lineGen = line().x(([x]) => x).y(([, y]) => y).curve(curveFor(curve));
|
|
1132
|
+
const areaGen = isVertical ? area().x(([x]) => x).y0(([, , y0]) => y0).y1(([, y1]) => y1).curve(curveFor(curve)) : area().y(([x]) => x).x0(([, , x0]) => x0).x1(([, x1]) => x1).curve(curveFor(curve));
|
|
1133
|
+
const tuples = layer.map((p, i) => {
|
|
1134
|
+
return [
|
|
1135
|
+
categoryScale(categories[i]) ?? 0,
|
|
1136
|
+
valueScale(p[1]),
|
|
1137
|
+
valueScale(p[0])
|
|
1138
|
+
];
|
|
1139
|
+
});
|
|
1140
|
+
return {
|
|
1141
|
+
seriesKey,
|
|
1142
|
+
color: seriesColorVar(seriesKey),
|
|
1143
|
+
linePath: lineGen(tuples) ?? "",
|
|
1144
|
+
areaPath: areaGen(tuples) ?? "",
|
|
1145
|
+
points
|
|
1146
|
+
};
|
|
1147
|
+
}),
|
|
1148
|
+
points: allPoints,
|
|
1149
|
+
categoryScale,
|
|
1150
|
+
valueScale,
|
|
1151
|
+
categories,
|
|
1152
|
+
stacked: true
|
|
1153
|
+
};
|
|
1308
1154
|
}
|
|
1309
|
-
|
|
1310
|
-
/**
|
|
1311
|
-
* Publish a `scalePoint` from line/area layouts to the `CartesianContext`,
|
|
1312
|
-
* which expects a `scaleBand`. Line/area points sit on the range edges (the
|
|
1313
|
-
* point scale has zero padding, so the first point touches the y-axis and the
|
|
1314
|
-
* last touches the right edge). We extend the band range by half a step on
|
|
1315
|
-
* each side so band centers — used to position axis ticks — line up exactly
|
|
1316
|
-
* with those edge-touching points.
|
|
1317
|
-
*
|
|
1318
|
-
* This keeps axes/grid primitives agnostic to whether the underlying chart
|
|
1319
|
-
* uses `scaleBand` (bar) or `scalePoint` (line/area).
|
|
1320
|
-
*/
|
|
1321
1155
|
function pointToBandAdapter(pointScale, range) {
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1156
|
+
const half = pointScale.step() / 2;
|
|
1157
|
+
const extended = [range[0] - half, range[1] + half];
|
|
1158
|
+
return scaleBand().domain(pointScale.domain()).range(extended).padding(0);
|
|
1325
1159
|
}
|
|
1326
|
-
/** Recreate a linear scale with the same domain/range (handy for effects). */
|
|
1327
1160
|
function cloneLinear(scale) {
|
|
1328
|
-
|
|
1161
|
+
return scaleLinear().domain(scale.domain()).range(scale.range());
|
|
1329
1162
|
}
|
|
1330
1163
|
function provideCartesianFromLineLayout(ctx, layout, orientation, innerWidth, innerHeight) {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1164
|
+
const range = orientation === "vertical" ? [0, innerWidth] : [0, innerHeight];
|
|
1165
|
+
ctx.orientation.set(orientation);
|
|
1166
|
+
ctx.innerWidth.set(innerWidth);
|
|
1167
|
+
ctx.innerHeight.set(innerHeight);
|
|
1168
|
+
ctx.categoryScale.set(pointToBandAdapter(layout.categoryScale, range));
|
|
1169
|
+
ctx.valueScale.set(cloneLinear(layout.valueScale));
|
|
1170
|
+
ctx.categories.set(layout.categories);
|
|
1338
1171
|
}
|
|
1339
|
-
|
|
1340
|
-
/** 0.375rem @ 16px root — Tailwind's stock `rounded-md` value. */
|
|
1341
1172
|
const FALLBACK_RADIUS_PX = 6;
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
// Concrete px values parse directly.
|
|
1396
|
-
return numeric;
|
|
1397
|
-
}
|
|
1398
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeRadius, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
1399
|
-
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeRadius });
|
|
1400
|
-
}
|
|
1401
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeRadius, decorators: [{
|
|
1402
|
-
type: Service
|
|
1403
|
-
}], ctorParameters: () => [] });
|
|
1404
|
-
|
|
1405
|
-
/** 0.25rem @ 16px root — the `--spacing-base` value on the `normal` preset. */
|
|
1173
|
+
var ChartThemeRadius = class ChartThemeRadius {
|
|
1174
|
+
document = inject(DOCUMENT, { optional: true });
|
|
1175
|
+
basePx = signal(this.readBasePx(), ...ngDevMode ? [{ debugName: "basePx" }] : /* istanbul ignore next */ []);
|
|
1176
|
+
px = this.basePx.asReadonly();
|
|
1177
|
+
constructor() {
|
|
1178
|
+
const root = this.document?.documentElement;
|
|
1179
|
+
const view = this.document?.defaultView;
|
|
1180
|
+
if (!root || !view || typeof view.MutationObserver !== "function") return;
|
|
1181
|
+
const observer = new view.MutationObserver(() => this.basePx.set(this.readBasePx()));
|
|
1182
|
+
observer.observe(root, {
|
|
1183
|
+
attributes: true,
|
|
1184
|
+
attributeFilter: ["theme-radius"]
|
|
1185
|
+
});
|
|
1186
|
+
inject(DestroyRef).onDestroy(() => observer.disconnect());
|
|
1187
|
+
}
|
|
1188
|
+
readBasePx() {
|
|
1189
|
+
const root = this.document?.documentElement;
|
|
1190
|
+
const view = this.document?.defaultView;
|
|
1191
|
+
if (!root || !view) return FALLBACK_RADIUS_PX;
|
|
1192
|
+
const raw = view.getComputedStyle(root).getPropertyValue("--radius").trim();
|
|
1193
|
+
return this.toPx(raw, view, root) ?? FALLBACK_RADIUS_PX;
|
|
1194
|
+
}
|
|
1195
|
+
toPx(value, view, root) {
|
|
1196
|
+
if (!value) return null;
|
|
1197
|
+
if (value.includes("infinity")) return 9999;
|
|
1198
|
+
const numeric = Number.parseFloat(value);
|
|
1199
|
+
if (!Number.isFinite(numeric)) return null;
|
|
1200
|
+
if (value.endsWith("rem")) return numeric * (Number.parseFloat(view.getComputedStyle(root).fontSize) || 16);
|
|
1201
|
+
return numeric;
|
|
1202
|
+
}
|
|
1203
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1204
|
+
minVersion: "12.0.0",
|
|
1205
|
+
version: "22.2.2",
|
|
1206
|
+
ngImport: i0,
|
|
1207
|
+
type: ChartThemeRadius,
|
|
1208
|
+
deps: [],
|
|
1209
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1210
|
+
});
|
|
1211
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
1212
|
+
minVersion: "22.0.0",
|
|
1213
|
+
version: "22.2.2",
|
|
1214
|
+
ngImport: i0,
|
|
1215
|
+
type: ChartThemeRadius
|
|
1216
|
+
});
|
|
1217
|
+
};
|
|
1218
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1219
|
+
minVersion: "12.0.0",
|
|
1220
|
+
version: "22.2.2",
|
|
1221
|
+
ngImport: i0,
|
|
1222
|
+
type: ChartThemeRadius,
|
|
1223
|
+
decorators: [{ type: Service }],
|
|
1224
|
+
ctorParameters: () => []
|
|
1225
|
+
});
|
|
1406
1226
|
const FALLBACK_SPACING_PX = 4;
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
*
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
}
|
|
1464
|
-
const numeric = Number.parseFloat(value);
|
|
1465
|
-
if (!Number.isFinite(numeric)) {
|
|
1466
|
-
return null;
|
|
1467
|
-
}
|
|
1468
|
-
if (value.endsWith('rem')) {
|
|
1469
|
-
const rootFontSize = Number.parseFloat(view.getComputedStyle(root).fontSize) || 16;
|
|
1470
|
-
return numeric * rootFontSize;
|
|
1471
|
-
}
|
|
1472
|
-
// Concrete px values parse directly.
|
|
1473
|
-
return numeric;
|
|
1474
|
-
}
|
|
1475
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeSpace, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
1476
|
-
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeSpace });
|
|
1477
|
-
}
|
|
1478
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartThemeSpace, decorators: [{
|
|
1479
|
-
type: Service
|
|
1480
|
-
}], ctorParameters: () => [] });
|
|
1481
|
-
|
|
1482
|
-
/**
|
|
1483
|
-
* Generated bundle index. Do not edit.
|
|
1484
|
-
*/
|
|
1485
|
-
|
|
1486
|
-
export { CHART_DATA_ATTRIBUTE, CHART_THEMES, CartesianContext, CategoricalViewportContext, ChartContainer, ChartContext, ChartDataTable, ChartMarkFocus, ChartRovingFocus, ChartStyle, ChartThemeRadius, ChartThemeSpace, DEFAULT_CARTESIAN_MARGIN, DEFAULT_CARTESIAN_MARGIN_UNITS, DEFAULT_POLAR_MARGIN, DEFAULT_POLAR_MARGIN_UNITS, DEFAULT_RADAR_MARGIN, DEFAULT_RADAR_MARGIN_UNITS, ScatterViewportContext, activationClientPoint, bandTicks, buildCartesianScales, buildChartCss, cloneLinear, computeAreaLayout, computeLineLayout, effectiveIndexRange, elementClientCenter, escapeCssIdent, indexRangeSize, isSafeCssColorValue, linearTicks, nearestCategoryIndex, normalizeIndexRange, normalizeNumericDomain, panIndexRange, panNumericDomain, pointToBandAdapter, provideCartesianFromLineLayout, readNumber, resolveChartMargin, resolveChartStyle, resolveSeriesColor, seriesColorVar, setupCartesianChart, setupPolarChart, sliceByIndexRange, xScale, yScale, zeroBaselineDomain, zoomIndexRange, zoomNumericDomain };
|
|
1227
|
+
var ChartThemeSpace = class ChartThemeSpace {
|
|
1228
|
+
document = inject(DOCUMENT, { optional: true });
|
|
1229
|
+
unitPx = signal(this.readUnitPx(), ...ngDevMode ? [{ debugName: "unitPx" }] : /* istanbul ignore next */ []);
|
|
1230
|
+
px = this.unitPx.asReadonly();
|
|
1231
|
+
constructor() {
|
|
1232
|
+
const root = this.document?.documentElement;
|
|
1233
|
+
const view = this.document?.defaultView;
|
|
1234
|
+
if (!root || !view || typeof view.MutationObserver !== "function") return;
|
|
1235
|
+
const observer = new view.MutationObserver(() => this.unitPx.set(this.readUnitPx()));
|
|
1236
|
+
observer.observe(root, {
|
|
1237
|
+
attributes: true,
|
|
1238
|
+
attributeFilter: ["theme-space"]
|
|
1239
|
+
});
|
|
1240
|
+
inject(DestroyRef).onDestroy(() => observer.disconnect());
|
|
1241
|
+
}
|
|
1242
|
+
scale(units) {
|
|
1243
|
+
return units * this.unitPx();
|
|
1244
|
+
}
|
|
1245
|
+
readUnitPx() {
|
|
1246
|
+
const root = this.document?.documentElement;
|
|
1247
|
+
const view = this.document?.defaultView;
|
|
1248
|
+
if (!root || !view) return FALLBACK_SPACING_PX;
|
|
1249
|
+
const raw = view.getComputedStyle(root).getPropertyValue("--spacing-base").trim();
|
|
1250
|
+
return this.toPx(raw, view, root) ?? FALLBACK_SPACING_PX;
|
|
1251
|
+
}
|
|
1252
|
+
toPx(value, view, root) {
|
|
1253
|
+
if (!value) return null;
|
|
1254
|
+
const numeric = Number.parseFloat(value);
|
|
1255
|
+
if (!Number.isFinite(numeric)) return null;
|
|
1256
|
+
if (value.endsWith("rem")) return numeric * (Number.parseFloat(view.getComputedStyle(root).fontSize) || 16);
|
|
1257
|
+
return numeric;
|
|
1258
|
+
}
|
|
1259
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1260
|
+
minVersion: "12.0.0",
|
|
1261
|
+
version: "22.2.2",
|
|
1262
|
+
ngImport: i0,
|
|
1263
|
+
type: ChartThemeSpace,
|
|
1264
|
+
deps: [],
|
|
1265
|
+
target: i0.ɵɵFactoryTarget.Service
|
|
1266
|
+
});
|
|
1267
|
+
static ɵprov = i0.ɵɵngDeclareService({
|
|
1268
|
+
minVersion: "22.0.0",
|
|
1269
|
+
version: "22.2.2",
|
|
1270
|
+
ngImport: i0,
|
|
1271
|
+
type: ChartThemeSpace
|
|
1272
|
+
});
|
|
1273
|
+
};
|
|
1274
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1275
|
+
minVersion: "12.0.0",
|
|
1276
|
+
version: "22.2.2",
|
|
1277
|
+
ngImport: i0,
|
|
1278
|
+
type: ChartThemeSpace,
|
|
1279
|
+
decorators: [{ type: Service }],
|
|
1280
|
+
ctorParameters: () => []
|
|
1281
|
+
});
|
|
1282
|
+
export { CHART_DATA_ATTRIBUTE, CHART_THEMES, CartesianContext, CategoricalViewportContext, ChartContainer, ChartContext, ChartDataTable, ChartMarkFocus, ChartRovingFocus, ChartStyle, ChartThemeRadius, ChartThemeSpace, DEFAULT_CARTESIAN_MARGIN, DEFAULT_CARTESIAN_MARGIN_UNITS, DEFAULT_POLAR_MARGIN, DEFAULT_POLAR_MARGIN_UNITS, DEFAULT_RADAR_MARGIN, DEFAULT_RADAR_MARGIN_UNITS, ScatterViewportContext, activationClientPoint, bandTicks, buildCartesianScales, buildChartCss, cloneLinear, computeAreaLayout, computeLineLayout, effectiveIndexRange, elementClientCenter, escapeCssIdent, indexRangeSize, isSafeCssColorValue, linearTicks, nearestCategoryIndex, normalizeIndexRange, normalizeNumericDomain, panIndexRange, panNumericDomain, pointToBandAdapter, provideCartesianFromLineLayout, readNumber, resolveChartMargin, resolveChartStyle, resolveSeriesColor, seriesColorVar, setupCartesianChart, setupPolarChart, sliceByIndexRange, xScale, yScale, zeroBaselineDomain, zoomIndexRange, zoomNumericDomain };
|