@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.
Files changed (252) hide show
  1. package/README.md +8 -6
  2. package/SUPPORT.md +3 -3
  3. package/chart/README.md +1 -1
  4. package/component/README.md +2 -2
  5. package/component/calendar/README.md +3 -15
  6. package/component/drawer/README.md +1 -2
  7. package/fesm2022/ojiepermana-angular-chart-area.mjs +352 -137
  8. package/fesm2022/ojiepermana-angular-chart-bar.mjs +744 -524
  9. package/fesm2022/ojiepermana-angular-chart-core.mjs +1140 -1344
  10. package/fesm2022/ojiepermana-angular-chart-line.mjs +393 -147
  11. package/fesm2022/ojiepermana-angular-chart-pie.mjs +408 -179
  12. package/fesm2022/ojiepermana-angular-chart-primitives.mjs +1262 -920
  13. package/fesm2022/ojiepermana-angular-chart-radar.mjs +473 -205
  14. package/fesm2022/ojiepermana-angular-chart-radial.mjs +425 -182
  15. package/fesm2022/ojiepermana-angular-chart-scatter.mjs +386 -210
  16. package/fesm2022/ojiepermana-angular-chart.mjs +3 -19
  17. package/fesm2022/ojiepermana-angular-component-accordion.mjs +485 -243
  18. package/fesm2022/ojiepermana-angular-component-alert-dialog.mjs +963 -325
  19. package/fesm2022/ojiepermana-angular-component-alert.mjs +266 -103
  20. package/fesm2022/ojiepermana-angular-component-aspect-ratio.mjs +80 -35
  21. package/fesm2022/ojiepermana-angular-component-avatar.mjs +402 -135
  22. package/fesm2022/ojiepermana-angular-component-badge.mjs +109 -59
  23. package/fesm2022/ojiepermana-angular-component-breadcrumb.mjs +410 -142
  24. package/fesm2022/ojiepermana-angular-component-button-group.mjs +249 -96
  25. package/fesm2022/ojiepermana-angular-component-button.mjs +153 -75
  26. package/fesm2022/ojiepermana-angular-component-calendar.mjs +531 -418
  27. package/fesm2022/ojiepermana-angular-component-card.mjs +457 -171
  28. package/fesm2022/ojiepermana-angular-component-carousel.mjs +642 -272
  29. package/fesm2022/ojiepermana-angular-component-checkbox.mjs +312 -108
  30. package/fesm2022/ojiepermana-angular-component-collapsible.mjs +299 -115
  31. package/fesm2022/ojiepermana-angular-component-combobox.mjs +396 -183
  32. package/fesm2022/ojiepermana-angular-component-command.mjs +807 -347
  33. package/fesm2022/ojiepermana-angular-component-composer.mjs +807 -330
  34. package/fesm2022/ojiepermana-angular-component-context-menu.mjs +196 -161
  35. package/fesm2022/ojiepermana-angular-component-date-picker.mjs +650 -338
  36. package/fesm2022/ojiepermana-angular-component-dialog.mjs +710 -316
  37. package/fesm2022/ojiepermana-angular-component-drawer.mjs +1 -5
  38. package/fesm2022/ojiepermana-angular-component-dropdown-menu.mjs +1212 -646
  39. package/fesm2022/ojiepermana-angular-component-editor.mjs +987 -502
  40. package/fesm2022/ojiepermana-angular-component-empty.mjs +350 -137
  41. package/fesm2022/ojiepermana-angular-component-form.mjs +813 -434
  42. package/fesm2022/ojiepermana-angular-component-hover-card.mjs +486 -277
  43. package/fesm2022/ojiepermana-angular-component-icon.mjs +241 -140
  44. package/fesm2022/ojiepermana-angular-component-input-group.mjs +449 -176
  45. package/fesm2022/ojiepermana-angular-component-input-otp.mjs +891 -488
  46. package/fesm2022/ojiepermana-angular-component-input.mjs +86 -55
  47. package/fesm2022/ojiepermana-angular-component-item.mjs +713 -261
  48. package/fesm2022/ojiepermana-angular-component-kanban.mjs +714 -216
  49. package/fesm2022/ojiepermana-angular-component-kbd.mjs +124 -52
  50. package/fesm2022/ojiepermana-angular-component-label.mjs +82 -31
  51. package/fesm2022/ojiepermana-angular-component-menubar.mjs +479 -329
  52. package/fesm2022/ojiepermana-angular-component-native-select.mjs +167 -65
  53. package/fesm2022/ojiepermana-angular-component-navigation-menu.mjs +683 -380
  54. package/fesm2022/ojiepermana-angular-component-pagination.mjs +277 -94
  55. package/fesm2022/ojiepermana-angular-component-pillbox.mjs +1283 -607
  56. package/fesm2022/ojiepermana-angular-component-popover.mjs +291 -204
  57. package/fesm2022/ojiepermana-angular-component-progress.mjs +176 -53
  58. package/fesm2022/ojiepermana-angular-component-radio.mjs +449 -142
  59. package/fesm2022/ojiepermana-angular-component-resizable.mjs +659 -453
  60. package/fesm2022/ojiepermana-angular-component-scroll-area.mjs +117 -39
  61. package/fesm2022/ojiepermana-angular-component-segmented-control.mjs +351 -172
  62. package/fesm2022/ojiepermana-angular-component-select.mjs +475 -345
  63. package/fesm2022/ojiepermana-angular-component-separator.mjs +102 -35
  64. package/fesm2022/ojiepermana-angular-component-sheet.mjs +797 -347
  65. package/fesm2022/ojiepermana-angular-component-skeleton.mjs +62 -29
  66. package/fesm2022/ojiepermana-angular-component-slider.mjs +592 -376
  67. package/fesm2022/ojiepermana-angular-component-spinner.mjs +135 -38
  68. package/fesm2022/ojiepermana-angular-component-switch.mjs +315 -103
  69. package/fesm2022/ojiepermana-angular-component-table.mjs +440 -153
  70. package/fesm2022/ojiepermana-angular-component-tabs.mjs +590 -317
  71. package/fesm2022/ojiepermana-angular-component-textarea.mjs +85 -50
  72. package/fesm2022/ojiepermana-angular-component-timeline.mjs +609 -231
  73. package/fesm2022/ojiepermana-angular-component-toast.mjs +229 -243
  74. package/fesm2022/ojiepermana-angular-component-toggle-group.mjs +573 -288
  75. package/fesm2022/ojiepermana-angular-component-toggle.mjs +187 -78
  76. package/fesm2022/ojiepermana-angular-component-tooltip.mjs +798 -517
  77. package/fesm2022/ojiepermana-angular-component-utils-core.mjs +159 -292
  78. package/fesm2022/ojiepermana-angular-component-utils-overlay.mjs +46 -58
  79. package/fesm2022/ojiepermana-angular-component-utils-scale.mjs +76 -38
  80. package/fesm2022/ojiepermana-angular-component-utils.mjs +2 -8
  81. package/fesm2022/ojiepermana-angular-component.mjs +0 -10
  82. package/fesm2022/ojiepermana-angular-navigation-core.mjs +13 -23
  83. package/fesm2022/ojiepermana-angular-navigation-icon.mjs +35 -24
  84. package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-DYuysKVf.mjs +129 -0
  85. package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-COiTaw34.mjs +812 -0
  86. package/fesm2022/{ojiepermana-angular-navigation-navigation-entry-grid.component-COQ-60DS.mjs → ojiepermana-angular-navigation-navigation-entry-grid.component-YIz0IsIb.mjs} +392 -207
  87. package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-D2vwEwBY.mjs +650 -0
  88. package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-B5D7yXfb.mjs +662 -0
  89. package/fesm2022/ojiepermana-angular-navigation-navigation-item.component-CUb68MZH.mjs +1219 -0
  90. package/fesm2022/ojiepermana-angular-navigation-navigation-list.component-CrK16trj.mjs +327 -0
  91. package/fesm2022/ojiepermana-angular-navigation-service.mjs +544 -724
  92. package/fesm2022/ojiepermana-angular-navigation-types.mjs +139 -56
  93. package/fesm2022/ojiepermana-angular-navigation.mjs +3256 -4
  94. package/fesm2022/ojiepermana-angular-sdk.mjs +91 -201
  95. package/fesm2022/ojiepermana-angular-theme-component-settings.mjs +1125 -737
  96. package/fesm2022/ojiepermana-angular-theme-layout-services.mjs +245 -328
  97. package/fesm2022/ojiepermana-angular-theme-layout-types.mjs +35 -38
  98. package/fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs +1928 -553
  99. package/fesm2022/ojiepermana-angular-theme-layout.mjs +847 -496
  100. package/fesm2022/ojiepermana-angular-theme-page-core.mjs +288 -358
  101. package/fesm2022/ojiepermana-angular-theme-page-filter.mjs +362 -224
  102. package/fesm2022/ojiepermana-angular-theme-page-overview.mjs +88 -0
  103. package/fesm2022/ojiepermana-angular-theme-page-root.mjs +576 -254
  104. package/fesm2022/ojiepermana-angular-theme-page-side.mjs +317 -177
  105. package/fesm2022/ojiepermana-angular-theme-page-slots.mjs +256 -112
  106. package/fesm2022/ojiepermana-angular-theme-page.mjs +7 -12
  107. package/fesm2022/ojiepermana-angular-theme-shell-services.mjs +215 -326
  108. package/fesm2022/ojiepermana-angular-theme-shell-types.mjs +68 -129
  109. package/fesm2022/ojiepermana-angular-theme-shell.mjs +907 -378
  110. package/fesm2022/ojiepermana-angular-theme-styles.mjs +521 -720
  111. package/fesm2022/ojiepermana-angular-theme.mjs +0 -10
  112. package/fesm2022/ojiepermana-angular.mjs +5 -24
  113. package/navigation/README.md +69 -18
  114. package/package.json +16 -12
  115. package/sdk/README.md +1 -1
  116. package/sdk/src/writer/index.js +2 -2
  117. package/theme/README.md +1 -1
  118. package/theme/layout/README.md +2 -4
  119. package/theme/page/README.md +50 -0
  120. package/theme/styles/README.md +10 -10
  121. package/theme/styles/css/base/prefers-dark.css +1 -1
  122. package/theme/styles/css/base/status.css +1 -1
  123. package/theme/styles/css/color/amber.css +1 -1
  124. package/theme/styles/css/color/blue.css +1 -1
  125. package/theme/styles/css/color/cyan.css +1 -1
  126. package/theme/styles/css/color/emerald.css +1 -1
  127. package/theme/styles/css/color/fuchsia.css +1 -1
  128. package/theme/styles/css/color/green.css +1 -1
  129. package/theme/styles/css/color/indigo.css +1 -1
  130. package/theme/styles/css/color/lime.css +1 -1
  131. package/theme/styles/css/color/orange.css +1 -1
  132. package/theme/styles/css/color/pink.css +1 -1
  133. package/theme/styles/css/color/purple.css +1 -1
  134. package/theme/styles/css/color/red.css +1 -1
  135. package/theme/styles/css/color/rose.css +1 -1
  136. package/theme/styles/css/color/sky.css +1 -1
  137. package/theme/styles/css/color/teal.css +1 -1
  138. package/theme/styles/css/color/violet.css +1 -1
  139. package/theme/styles/css/color/yellow.css +1 -1
  140. package/theme/styles/css/neutral/gray.css +1 -1
  141. package/theme/styles/css/neutral/mauve.css +1 -1
  142. package/theme/styles/css/neutral/mist.css +1 -1
  143. package/theme/styles/css/neutral/neutral.css +1 -1
  144. package/theme/styles/css/neutral/olive.css +1 -1
  145. package/theme/styles/css/neutral/slate.css +1 -1
  146. package/theme/styles/css/neutral/stone.css +1 -1
  147. package/theme/styles/css/neutral/taupe.css +1 -1
  148. package/theme/styles/css/neutral/zinc.css +1 -1
  149. package/types/ojiepermana-angular-chart-area.d.ts +126 -63
  150. package/types/ojiepermana-angular-chart-bar.d.ts +244 -154
  151. package/types/ojiepermana-angular-chart-core.d.ts +409 -398
  152. package/types/ojiepermana-angular-chart-line.d.ts +141 -68
  153. package/types/ojiepermana-angular-chart-pie.d.ts +192 -121
  154. package/types/ojiepermana-angular-chart-primitives.d.ts +283 -214
  155. package/types/ojiepermana-angular-chart-radar.d.ts +189 -108
  156. package/types/ojiepermana-angular-chart-radial.d.ts +177 -106
  157. package/types/ojiepermana-angular-chart-scatter.d.ts +166 -110
  158. package/types/ojiepermana-angular-chart.d.ts +3 -2
  159. package/types/ojiepermana-angular-component-accordion.d.ts +135 -81
  160. package/types/ojiepermana-angular-component-alert-dialog.d.ts +271 -123
  161. package/types/ojiepermana-angular-component-alert.d.ts +69 -39
  162. package/types/ojiepermana-angular-component-aspect-ratio.d.ts +20 -12
  163. package/types/ojiepermana-angular-component-avatar.d.ts +103 -49
  164. package/types/ojiepermana-angular-component-badge.d.ts +36 -24
  165. package/types/ojiepermana-angular-component-breadcrumb.d.ts +79 -40
  166. package/types/ojiepermana-angular-component-button-group.d.ts +48 -24
  167. package/types/ojiepermana-angular-component-button.d.ts +44 -27
  168. package/types/ojiepermana-angular-component-calendar.d.ts +145 -107
  169. package/types/ojiepermana-angular-component-card.d.ts +112 -63
  170. package/types/ojiepermana-angular-component-carousel.d.ts +150 -81
  171. package/types/ojiepermana-angular-component-checkbox.d.ts +96 -38
  172. package/types/ojiepermana-angular-component-collapsible.d.ts +65 -39
  173. package/types/ojiepermana-angular-component-combobox.d.ts +100 -55
  174. package/types/ojiepermana-angular-component-command.d.ts +206 -121
  175. package/types/ojiepermana-angular-component-composer.d.ts +184 -84
  176. package/types/ojiepermana-angular-component-context-menu.d.ts +51 -41
  177. package/types/ojiepermana-angular-component-date-picker.d.ts +199 -109
  178. package/types/ojiepermana-angular-component-dialog.d.ts +200 -105
  179. package/types/ojiepermana-angular-component-drawer.d.ts +2 -1
  180. package/types/ojiepermana-angular-component-dropdown-menu.d.ts +324 -202
  181. package/types/ojiepermana-angular-component-editor.d.ts +215 -117
  182. package/types/ojiepermana-angular-component-empty.d.ts +80 -45
  183. package/types/ojiepermana-angular-component-form.d.ts +185 -121
  184. package/types/ojiepermana-angular-component-hover-card.d.ts +130 -72
  185. package/types/ojiepermana-angular-component-icon.d.ts +87 -57
  186. package/types/ojiepermana-angular-component-input-group.d.ts +93 -46
  187. package/types/ojiepermana-angular-component-input-otp.d.ts +243 -150
  188. package/types/ojiepermana-angular-component-input.d.ts +27 -17
  189. package/types/ojiepermana-angular-component-item.d.ts +160 -84
  190. package/types/ojiepermana-angular-component-kanban.d.ts +157 -62
  191. package/types/ojiepermana-angular-component-kbd.d.ts +24 -15
  192. package/types/ojiepermana-angular-component-label.d.ts +19 -11
  193. package/types/ojiepermana-angular-component-menubar.d.ts +120 -90
  194. package/types/ojiepermana-angular-component-native-select.d.ts +37 -24
  195. package/types/ojiepermana-angular-component-navigation-menu.d.ts +157 -98
  196. package/types/ojiepermana-angular-component-pagination.d.ts +78 -28
  197. package/types/ojiepermana-angular-component-pillbox.d.ts +361 -204
  198. package/types/ojiepermana-angular-component-popover.d.ts +94 -64
  199. package/types/ojiepermana-angular-component-progress.d.ts +45 -17
  200. package/types/ojiepermana-angular-component-radio.d.ts +129 -53
  201. package/types/ojiepermana-angular-component-resizable.d.ts +160 -112
  202. package/types/ojiepermana-angular-component-scroll-area.d.ts +33 -15
  203. package/types/ojiepermana-angular-component-segmented-control.d.ts +94 -50
  204. package/types/ojiepermana-angular-component-select.d.ts +94 -77
  205. package/types/ojiepermana-angular-component-separator.d.ts +26 -14
  206. package/types/ojiepermana-angular-component-sheet.d.ts +226 -116
  207. package/types/ojiepermana-angular-component-skeleton.d.ts +13 -10
  208. package/types/ojiepermana-angular-component-slider.d.ts +140 -75
  209. package/types/ojiepermana-angular-component-spinner.d.ts +31 -13
  210. package/types/ojiepermana-angular-component-switch.d.ts +97 -40
  211. package/types/ojiepermana-angular-component-table.d.ts +102 -50
  212. package/types/ojiepermana-angular-component-tabs.d.ts +174 -115
  213. package/types/ojiepermana-angular-component-textarea.d.ts +27 -17
  214. package/types/ojiepermana-angular-component-timeline.d.ts +141 -59
  215. package/types/ojiepermana-angular-component-toast.d.ts +51 -55
  216. package/types/ojiepermana-angular-component-toggle-group.d.ts +159 -88
  217. package/types/ojiepermana-angular-component-toggle.d.ts +47 -25
  218. package/types/ojiepermana-angular-component-tooltip.d.ts +222 -132
  219. package/types/ojiepermana-angular-component-utils-core.d.ts +81 -90
  220. package/types/ojiepermana-angular-component-utils-overlay.d.ts +7 -11
  221. package/types/ojiepermana-angular-component-utils-scale.d.ts +20 -12
  222. package/types/ojiepermana-angular-component-utils.d.ts +2 -2
  223. package/types/ojiepermana-angular-component.d.ts +1 -2
  224. package/types/ojiepermana-angular-navigation-core.d.ts +46 -50
  225. package/types/ojiepermana-angular-navigation-icon.d.ts +9 -12
  226. package/types/ojiepermana-angular-navigation-service.d.ts +112 -115
  227. package/types/ojiepermana-angular-navigation-types.d.ts +166 -125
  228. package/types/ojiepermana-angular-navigation.d.ts +708 -375
  229. package/types/ojiepermana-angular-sdk.d.ts +69 -71
  230. package/types/ojiepermana-angular-theme-component-settings.d.ts +120 -86
  231. package/types/ojiepermana-angular-theme-layout-services.d.ts +119 -124
  232. package/types/ojiepermana-angular-theme-layout-types.d.ts +27 -31
  233. package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +446 -187
  234. package/types/ojiepermana-angular-theme-layout.d.ts +201 -113
  235. package/types/ojiepermana-angular-theme-page-core.d.ts +136 -142
  236. package/types/ojiepermana-angular-theme-page-filter.d.ts +112 -62
  237. package/types/ojiepermana-angular-theme-page-overview.d.ts +28 -0
  238. package/types/ojiepermana-angular-theme-page-root.d.ts +172 -88
  239. package/types/ojiepermana-angular-theme-page-side.d.ts +89 -49
  240. package/types/ojiepermana-angular-theme-page-slots.d.ts +58 -37
  241. package/types/ojiepermana-angular-theme-page.d.ts +7 -5
  242. package/types/ojiepermana-angular-theme-shell-services.d.ts +119 -125
  243. package/types/ojiepermana-angular-theme-shell-types.d.ts +38 -41
  244. package/types/ojiepermana-angular-theme-shell.d.ts +139 -61
  245. package/types/ojiepermana-angular-theme-styles.d.ts +184 -196
  246. package/types/ojiepermana-angular-theme.d.ts +1 -2
  247. package/types/ojiepermana-angular.d.ts +5 -5
  248. package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-Be3IqzG4.mjs +0 -91
  249. package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-Bc7DWK3R.mjs +0 -522
  250. package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-DA8VPEn7.mjs +0 -404
  251. package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-U2TJTzlW.mjs +0 -466
  252. package/fesm2022/ojiepermana-angular-navigation-ojiepermana-angular-navigation-CIUhmytH.mjs +0 -2668
@@ -1,39 +1,65 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, input, computed, Component, viewChild, DestroyRef, signal, Directive, ElementRef, NgZone, PLATFORM_ID, afterNextRender, afterRenderEffect, contentChild, TemplateRef } from '@angular/core';
3
- import { CartesianContext, linearTicks, bandTicks, ChartContext, CategoricalViewportContext, ScatterViewportContext, nearestCategoryIndex, normalizeIndexRange, panIndexRange, panNumericDomain, indexRangeSize, normalizeNumericDomain, zoomNumericDomain, zoomIndexRange, seriesColorVar, effectiveIndexRange } from '@ojiepermana/angular/chart/core';
4
- import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
5
-
6
- /**
7
- * X axis for a cartesian chart. Reads scales from `CartesianContext`.
8
- *
9
- * Renders as `<svg:g>` — must be placed inside the owning chart's SVG.
10
- */
11
- class ChartAxisX {
12
- ctx = inject(CartesianContext);
13
- /** Approximate tick count for linear (value) scales. */
14
- tickCount = input(5, /* @ts-ignore */
15
- ...(ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []));
16
- /** Show 6-px tick marks between the axis line and the labels. */
17
- tickLine = input(true, /* @ts-ignore */
18
- ...(ngDevMode ? [{ debugName: "tickLine" }] : /* istanbul ignore next */ []));
19
- /** Formatter for numeric tick labels. */
20
- tickFormat = input((v) => String(v), /* @ts-ignore */
21
- ...(ngDevMode ? [{ debugName: "tickFormat" }] : /* istanbul ignore next */ []));
22
- innerWidth = this.ctx.innerWidth;
23
- transform = computed(() => `translate(0,${this.ctx.innerHeight()})`, /* @ts-ignore */
24
- ...(ngDevMode ? [{ debugName: "transform" }] : /* istanbul ignore next */ []));
25
- ticks = computed(() => {
26
- const horizontal = this.ctx.orientation() === 'horizontal';
27
- if (horizontal) {
28
- const scale = this.ctx.valueScale();
29
- return scale ? linearTicks(scale, this.tickCount(), this.tickFormat()) : [];
30
- }
31
- const scale = this.ctx.categoryScale();
32
- return scale ? bandTicks(scale) : [];
33
- }, /* @ts-ignore */
34
- ...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
35
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartAxisX, deps: [], target: i0.ɵɵFactoryTarget.Component });
36
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartAxisX, isStandalone: true, selector: "svg:g[ChartAxisX]", inputs: { tickCount: { classPropertyName: "tickCount", publicName: "tickCount", isSignal: true, isRequired: false, transformFunction: null }, tickLine: { classPropertyName: "tickLine", publicName: "tickLine", isSignal: true, isRequired: false, transformFunction: null }, tickFormat: { classPropertyName: "tickFormat", publicName: "tickFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.transform": "transform()" }, classAttribute: "chart-axis chart-axis-x text-muted-foreground" }, ngImport: i0, template: `
1
+ import * as i0 from "@angular/core";
2
+ import { Component, DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, TemplateRef, afterNextRender, afterRenderEffect, computed, contentChild, inject, input, signal, viewChild } from "@angular/core";
3
+ import { CartesianContext, CategoricalViewportContext, ChartContext, ScatterViewportContext, bandTicks, effectiveIndexRange, indexRangeSize, linearTicks, nearestCategoryIndex, normalizeIndexRange, normalizeNumericDomain, panIndexRange, panNumericDomain, seriesColorVar, zoomIndexRange, zoomNumericDomain } from "@ojiepermana/angular/chart/core";
4
+ import { DOCUMENT, NgComponentOutlet, NgTemplateOutlet, isPlatformBrowser } from "@angular/common";
5
+ var ChartAxisX = class ChartAxisX {
6
+ ctx = inject(CartesianContext);
7
+ tickCount = input(5, ...ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []);
8
+ tickLine = input(true, ...ngDevMode ? [{ debugName: "tickLine" }] : /* istanbul ignore next */ []);
9
+ tickFormat = input((v) => String(v), ...ngDevMode ? [{ debugName: "tickFormat" }] : /* istanbul ignore next */ []);
10
+ innerWidth = this.ctx.innerWidth;
11
+ transform = computed(() => `translate(0,${this.ctx.innerHeight()})`, ...ngDevMode ? [{ debugName: "transform" }] : /* istanbul ignore next */ []);
12
+ ticks = computed(() => {
13
+ if (this.ctx.orientation() === "horizontal") {
14
+ const scale = this.ctx.valueScale();
15
+ return scale ? linearTicks(scale, this.tickCount(), this.tickFormat()) : [];
16
+ }
17
+ const scale = this.ctx.categoryScale();
18
+ return scale ? bandTicks(scale) : [];
19
+ }, ...ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []);
20
+ static ɵfac = i0.ɵɵngDeclareFactory({
21
+ minVersion: "12.0.0",
22
+ version: "22.2.2",
23
+ ngImport: i0,
24
+ type: ChartAxisX,
25
+ deps: [],
26
+ target: i0.ɵɵFactoryTarget.Component
27
+ });
28
+ static ɵcmp = i0.ɵɵngDeclareComponent({
29
+ minVersion: "17.0.0",
30
+ version: "22.2.2",
31
+ type: ChartAxisX,
32
+ isStandalone: true,
33
+ selector: "svg:g[ChartAxisX]",
34
+ inputs: {
35
+ tickCount: {
36
+ classPropertyName: "tickCount",
37
+ publicName: "tickCount",
38
+ isSignal: true,
39
+ isRequired: false,
40
+ transformFunction: null
41
+ },
42
+ tickLine: {
43
+ classPropertyName: "tickLine",
44
+ publicName: "tickLine",
45
+ isSignal: true,
46
+ isRequired: false,
47
+ transformFunction: null
48
+ },
49
+ tickFormat: {
50
+ classPropertyName: "tickFormat",
51
+ publicName: "tickFormat",
52
+ isSignal: true,
53
+ isRequired: false,
54
+ transformFunction: null
55
+ }
56
+ },
57
+ host: {
58
+ properties: { "attr.transform": "transform()" },
59
+ classAttribute: "chart-axis chart-axis-x text-muted-foreground"
60
+ },
61
+ ngImport: i0,
62
+ template: `
37
63
  <svg:line class="stroke-border" [attr.x1]="0" [attr.x2]="innerWidth()" y1="0" y2="0" />
38
64
  @for (t of ticks(); track t.value) {
39
65
  <svg:g [attr.transform]="'translate(' + t.offset + ',0)'">
@@ -50,17 +76,24 @@ class ChartAxisX {
50
76
  </svg:text>
51
77
  </svg:g>
52
78
  }
53
- `, isInline: true });
54
- }
55
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartAxisX, decorators: [{
56
- type: Component,
57
- args: [{
58
- selector: 'svg:g[ChartAxisX]',
59
- host: {
60
- class: 'chart-axis chart-axis-x text-muted-foreground',
61
- '[attr.transform]': 'transform()',
62
- },
63
- template: `
79
+ `,
80
+ isInline: true
81
+ });
82
+ };
83
+ i0.ɵɵngDeclareClassMetadata({
84
+ minVersion: "12.0.0",
85
+ version: "22.2.2",
86
+ ngImport: i0,
87
+ type: ChartAxisX,
88
+ decorators: [{
89
+ type: Component,
90
+ args: [{
91
+ selector: "svg:g[ChartAxisX]",
92
+ host: {
93
+ class: "chart-axis chart-axis-x text-muted-foreground",
94
+ "[attr.transform]": "transform()"
95
+ },
96
+ template: `
64
97
  <svg:line class="stroke-border" [attr.x1]="0" [attr.x2]="innerWidth()" y1="0" y2="0" />
65
98
  @for (t of ticks(); track t.value) {
66
99
  <svg:g [attr.transform]="'translate(' + t.offset + ',0)'">
@@ -77,36 +110,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
77
110
  </svg:text>
78
111
  </svg:g>
79
112
  }
80
- `,
81
- }]
82
- }], propDecorators: { tickCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickCount", required: false }] }], tickLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickLine", required: false }] }], tickFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickFormat", required: false }] }] } });
83
-
84
- /**
85
- * Y axis for a cartesian chart. Reads scales from `CartesianContext`.
86
- *
87
- * Renders as `<svg:g>` — must be placed inside the owning chart's SVG.
88
- */
89
- class ChartAxisY {
90
- ctx = inject(CartesianContext);
91
- tickCount = input(5, /* @ts-ignore */
92
- ...(ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []));
93
- tickLine = input(true, /* @ts-ignore */
94
- ...(ngDevMode ? [{ debugName: "tickLine" }] : /* istanbul ignore next */ []));
95
- tickFormat = input((v) => String(v), /* @ts-ignore */
96
- ...(ngDevMode ? [{ debugName: "tickFormat" }] : /* istanbul ignore next */ []));
97
- innerHeight = this.ctx.innerHeight;
98
- ticks = computed(() => {
99
- const horizontal = this.ctx.orientation() === 'horizontal';
100
- if (horizontal) {
101
- const scale = this.ctx.categoryScale();
102
- return scale ? bandTicks(scale) : [];
103
- }
104
- const scale = this.ctx.valueScale();
105
- return scale ? linearTicks(scale, this.tickCount(), this.tickFormat()) : [];
106
- }, /* @ts-ignore */
107
- ...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartAxisY, deps: [], target: i0.ɵɵFactoryTarget.Component });
109
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartAxisY, isStandalone: true, selector: "svg:g[ChartAxisY]", inputs: { tickCount: { classPropertyName: "tickCount", publicName: "tickCount", isSignal: true, isRequired: false, transformFunction: null }, tickLine: { classPropertyName: "tickLine", publicName: "tickLine", isSignal: true, isRequired: false, transformFunction: null }, tickFormat: { classPropertyName: "tickFormat", publicName: "tickFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "chart-axis chart-axis-y text-muted-foreground" }, ngImport: i0, template: `
113
+ `
114
+ }]
115
+ }],
116
+ propDecorators: {
117
+ tickCount: [{
118
+ type: i0.Input,
119
+ args: [{
120
+ isSignal: true,
121
+ alias: "tickCount",
122
+ required: false
123
+ }]
124
+ }],
125
+ tickLine: [{
126
+ type: i0.Input,
127
+ args: [{
128
+ isSignal: true,
129
+ alias: "tickLine",
130
+ required: false
131
+ }]
132
+ }],
133
+ tickFormat: [{
134
+ type: i0.Input,
135
+ args: [{
136
+ isSignal: true,
137
+ alias: "tickFormat",
138
+ required: false
139
+ }]
140
+ }]
141
+ }
142
+ });
143
+ var ChartAxisY = class ChartAxisY {
144
+ ctx = inject(CartesianContext);
145
+ tickCount = input(5, ...ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []);
146
+ tickLine = input(true, ...ngDevMode ? [{ debugName: "tickLine" }] : /* istanbul ignore next */ []);
147
+ tickFormat = input((v) => String(v), ...ngDevMode ? [{ debugName: "tickFormat" }] : /* istanbul ignore next */ []);
148
+ innerHeight = this.ctx.innerHeight;
149
+ ticks = computed(() => {
150
+ if (this.ctx.orientation() === "horizontal") {
151
+ const scale = this.ctx.categoryScale();
152
+ return scale ? bandTicks(scale) : [];
153
+ }
154
+ const scale = this.ctx.valueScale();
155
+ return scale ? linearTicks(scale, this.tickCount(), this.tickFormat()) : [];
156
+ }, ...ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []);
157
+ static ɵfac = i0.ɵɵngDeclareFactory({
158
+ minVersion: "12.0.0",
159
+ version: "22.2.2",
160
+ ngImport: i0,
161
+ type: ChartAxisY,
162
+ deps: [],
163
+ target: i0.ɵɵFactoryTarget.Component
164
+ });
165
+ static ɵcmp = i0.ɵɵngDeclareComponent({
166
+ minVersion: "17.0.0",
167
+ version: "22.2.2",
168
+ type: ChartAxisY,
169
+ isStandalone: true,
170
+ selector: "svg:g[ChartAxisY]",
171
+ inputs: {
172
+ tickCount: {
173
+ classPropertyName: "tickCount",
174
+ publicName: "tickCount",
175
+ isSignal: true,
176
+ isRequired: false,
177
+ transformFunction: null
178
+ },
179
+ tickLine: {
180
+ classPropertyName: "tickLine",
181
+ publicName: "tickLine",
182
+ isSignal: true,
183
+ isRequired: false,
184
+ transformFunction: null
185
+ },
186
+ tickFormat: {
187
+ classPropertyName: "tickFormat",
188
+ publicName: "tickFormat",
189
+ isSignal: true,
190
+ isRequired: false,
191
+ transformFunction: null
192
+ }
193
+ },
194
+ host: { classAttribute: "chart-axis chart-axis-y text-muted-foreground" },
195
+ ngImport: i0,
196
+ template: `
110
197
  <svg:line class="stroke-border" x1="0" x2="0" [attr.y1]="0" [attr.y2]="innerHeight()" />
111
198
  @for (t of ticks(); track t.value) {
112
199
  <svg:g [attr.transform]="'translate(0,' + t.offset + ')'">
@@ -124,16 +211,21 @@ class ChartAxisY {
124
211
  </svg:text>
125
212
  </svg:g>
126
213
  }
127
- `, isInline: true });
128
- }
129
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartAxisY, decorators: [{
130
- type: Component,
131
- args: [{
132
- selector: 'svg:g[ChartAxisY]',
133
- host: {
134
- class: 'chart-axis chart-axis-y text-muted-foreground',
135
- },
136
- template: `
214
+ `,
215
+ isInline: true
216
+ });
217
+ };
218
+ i0.ɵɵngDeclareClassMetadata({
219
+ minVersion: "12.0.0",
220
+ version: "22.2.2",
221
+ ngImport: i0,
222
+ type: ChartAxisY,
223
+ decorators: [{
224
+ type: Component,
225
+ args: [{
226
+ selector: "svg:g[ChartAxisY]",
227
+ host: { class: "chart-axis chart-axis-y text-muted-foreground" },
228
+ template: `
137
229
  <svg:line class="stroke-border" x1="0" x2="0" [attr.y1]="0" [attr.y2]="innerHeight()" />
138
230
  @for (t of ticks(); track t.value) {
139
231
  <svg:g [attr.transform]="'translate(0,' + t.offset + ')'">
@@ -151,35 +243,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
151
243
  </svg:text>
152
244
  </svg:g>
153
245
  }
154
- `,
155
- }]
156
- }], propDecorators: { tickCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickCount", required: false }] }], tickLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickLine", required: false }] }], tickFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickFormat", required: false }] }] } });
157
-
158
- /**
159
- * Horizontal / vertical grid lines for the cartesian plotting area.
160
- *
161
- * Reads tick positions from `CartesianContext.valueScale`. Direction of the
162
- * grid lines follows `orientation`:
163
- * - vertical → horizontal grid lines (one per y-tick)
164
- * - horizontal → vertical grid lines (one per x-tick)
165
- */
166
- class ChartGrid {
167
- ctx = inject(CartesianContext);
168
- tickCount = input(5, /* @ts-ignore */
169
- ...(ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []));
170
- ticks = computed(() => {
171
- const scale = this.ctx.valueScale();
172
- return scale ? linearTicks(scale, this.tickCount()) : [];
173
- }, /* @ts-ignore */
174
- ...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
175
- line = (offset) => {
176
- if (this.ctx.orientation() === 'vertical') {
177
- return { x1: 0, x2: this.ctx.innerWidth(), y1: offset, y2: offset };
178
- }
179
- return { x1: offset, x2: offset, y1: 0, y2: this.ctx.innerHeight() };
180
- };
181
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartGrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
182
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartGrid, isStandalone: true, selector: "svg:g[ChartGrid]", inputs: { tickCount: { classPropertyName: "tickCount", publicName: "tickCount", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "chart-grid text-border" }, ngImport: i0, template: `
246
+ `
247
+ }]
248
+ }],
249
+ propDecorators: {
250
+ tickCount: [{
251
+ type: i0.Input,
252
+ args: [{
253
+ isSignal: true,
254
+ alias: "tickCount",
255
+ required: false
256
+ }]
257
+ }],
258
+ tickLine: [{
259
+ type: i0.Input,
260
+ args: [{
261
+ isSignal: true,
262
+ alias: "tickLine",
263
+ required: false
264
+ }]
265
+ }],
266
+ tickFormat: [{
267
+ type: i0.Input,
268
+ args: [{
269
+ isSignal: true,
270
+ alias: "tickFormat",
271
+ required: false
272
+ }]
273
+ }]
274
+ }
275
+ });
276
+ var ChartGrid = class ChartGrid {
277
+ ctx = inject(CartesianContext);
278
+ tickCount = input(5, ...ngDevMode ? [{ debugName: "tickCount" }] : /* istanbul ignore next */ []);
279
+ ticks = computed(() => {
280
+ const scale = this.ctx.valueScale();
281
+ return scale ? linearTicks(scale, this.tickCount()) : [];
282
+ }, ...ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []);
283
+ line = (offset) => {
284
+ if (this.ctx.orientation() === "vertical") return {
285
+ x1: 0,
286
+ x2: this.ctx.innerWidth(),
287
+ y1: offset,
288
+ y2: offset
289
+ };
290
+ return {
291
+ x1: offset,
292
+ x2: offset,
293
+ y1: 0,
294
+ y2: this.ctx.innerHeight()
295
+ };
296
+ };
297
+ static ɵfac = i0.ɵɵngDeclareFactory({
298
+ minVersion: "12.0.0",
299
+ version: "22.2.2",
300
+ ngImport: i0,
301
+ type: ChartGrid,
302
+ deps: [],
303
+ target: i0.ɵɵFactoryTarget.Component
304
+ });
305
+ static ɵcmp = i0.ɵɵngDeclareComponent({
306
+ minVersion: "17.0.0",
307
+ version: "22.2.2",
308
+ type: ChartGrid,
309
+ isStandalone: true,
310
+ selector: "svg:g[ChartGrid]",
311
+ inputs: { tickCount: {
312
+ classPropertyName: "tickCount",
313
+ publicName: "tickCount",
314
+ isSignal: true,
315
+ isRequired: false,
316
+ transformFunction: null
317
+ } },
318
+ host: { classAttribute: "chart-grid text-border" },
319
+ ngImport: i0,
320
+ template: `
183
321
  @for (t of ticks(); track t.value) {
184
322
  <svg:line
185
323
  class="stroke-border"
@@ -190,16 +328,21 @@ class ChartGrid {
190
328
  [attr.y2]="line(t.offset).y2"
191
329
  />
192
330
  }
193
- `, isInline: true });
194
- }
195
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartGrid, decorators: [{
196
- type: Component,
197
- args: [{
198
- selector: 'svg:g[ChartGrid]',
199
- host: {
200
- class: 'chart-grid text-border',
201
- },
202
- template: `
331
+ `,
332
+ isInline: true
333
+ });
334
+ };
335
+ i0.ɵɵngDeclareClassMetadata({
336
+ minVersion: "12.0.0",
337
+ version: "22.2.2",
338
+ ngImport: i0,
339
+ type: ChartGrid,
340
+ decorators: [{
341
+ type: Component,
342
+ args: [{
343
+ selector: "svg:g[ChartGrid]",
344
+ host: { class: "chart-grid text-border" },
345
+ template: `
203
346
  @for (t of ticks(); track t.value) {
204
347
  <svg:line
205
348
  class="stroke-border"
@@ -210,37 +353,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
210
353
  [attr.y2]="line(t.offset).y2"
211
354
  />
212
355
  }
213
- `,
214
- }]
215
- }], propDecorators: { tickCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickCount", required: false }] }] } });
216
-
217
- /**
218
- * Crosshair primitive — a line drawn through the currently active data point
219
- * perpendicular to the categorical axis. Reads `activePoint` from
220
- * `ChartContext` and the scales from `CartesianContext`.
221
- *
222
- * Place inside a cartesian chart's SVG inner group.
223
- */
224
- class ChartCrosshair {
225
- root = inject(ChartContext);
226
- cart = inject(CartesianContext);
227
- line = computed(() => {
228
- const active = this.root.activePoint();
229
- const scale = this.cart.categoryScale();
230
- const categories = this.cart.categories();
231
- if (!active || !scale || active.index < 0 || active.index >= categories.length) {
232
- return null;
233
- }
234
- const base = scale(categories[active.index]) ?? 0;
235
- const pos = base + scale.bandwidth() / 2;
236
- if (this.cart.orientation() === 'vertical') {
237
- return { x1: pos, x2: pos, y1: 0, y2: this.cart.innerHeight() };
238
- }
239
- return { x1: 0, x2: this.cart.innerWidth(), y1: pos, y2: pos };
240
- }, /* @ts-ignore */
241
- ...(ngDevMode ? [{ debugName: "line" }] : /* istanbul ignore next */ []));
242
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartCrosshair, deps: [], target: i0.ɵɵFactoryTarget.Component });
243
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartCrosshair, isStandalone: true, selector: "svg:g[ChartCrosshair]", host: { classAttribute: "chart-crosshair" }, ngImport: i0, template: `
356
+ `
357
+ }]
358
+ }],
359
+ propDecorators: { tickCount: [{
360
+ type: i0.Input,
361
+ args: [{
362
+ isSignal: true,
363
+ alias: "tickCount",
364
+ required: false
365
+ }]
366
+ }] }
367
+ });
368
+ var ChartCrosshair = class ChartCrosshair {
369
+ root = inject(ChartContext);
370
+ cart = inject(CartesianContext);
371
+ line = computed(() => {
372
+ const active = this.root.activePoint();
373
+ const scale = this.cart.categoryScale();
374
+ const categories = this.cart.categories();
375
+ if (!active || !scale || active.index < 0 || active.index >= categories.length) return null;
376
+ const pos = (scale(categories[active.index]) ?? 0) + scale.bandwidth() / 2;
377
+ if (this.cart.orientation() === "vertical") return {
378
+ x1: pos,
379
+ x2: pos,
380
+ y1: 0,
381
+ y2: this.cart.innerHeight()
382
+ };
383
+ return {
384
+ x1: 0,
385
+ x2: this.cart.innerWidth(),
386
+ y1: pos,
387
+ y2: pos
388
+ };
389
+ }, ...ngDevMode ? [{ debugName: "line" }] : /* istanbul ignore next */ []);
390
+ static ɵfac = i0.ɵɵngDeclareFactory({
391
+ minVersion: "12.0.0",
392
+ version: "22.2.2",
393
+ ngImport: i0,
394
+ type: ChartCrosshair,
395
+ deps: [],
396
+ target: i0.ɵɵFactoryTarget.Component
397
+ });
398
+ static ɵcmp = i0.ɵɵngDeclareComponent({
399
+ minVersion: "17.0.0",
400
+ version: "22.2.2",
401
+ type: ChartCrosshair,
402
+ isStandalone: true,
403
+ selector: "svg:g[ChartCrosshair]",
404
+ host: { classAttribute: "chart-crosshair" },
405
+ ngImport: i0,
406
+ template: `
244
407
  @if (line(); as l) {
245
408
  <svg:line
246
409
  class="stroke-border"
@@ -251,14 +414,21 @@ class ChartCrosshair {
251
414
  [attr.y2]="l.y2"
252
415
  />
253
416
  }
254
- `, isInline: true });
255
- }
256
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartCrosshair, decorators: [{
257
- type: Component,
258
- args: [{
259
- selector: 'svg:g[ChartCrosshair]',
260
- host: { class: 'chart-crosshair' },
261
- template: `
417
+ `,
418
+ isInline: true
419
+ });
420
+ };
421
+ i0.ɵɵngDeclareClassMetadata({
422
+ minVersion: "12.0.0",
423
+ version: "22.2.2",
424
+ ngImport: i0,
425
+ type: ChartCrosshair,
426
+ decorators: [{
427
+ type: Component,
428
+ args: [{
429
+ selector: "svg:g[ChartCrosshair]",
430
+ host: { class: "chart-crosshair" },
431
+ template: `
262
432
  @if (line(); as l) {
263
433
  <svg:line
264
434
  class="stroke-border"
@@ -269,352 +439,311 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
269
439
  [attr.y2]="l.y2"
270
440
  />
271
441
  }
272
- `,
273
- }]
274
- }] });
275
-
442
+ `
443
+ }]
444
+ }]
445
+ });
276
446
  function clamp(value, min, max) {
277
- return Math.min(max, Math.max(min, value));
447
+ return Math.min(max, Math.max(min, value));
278
448
  }
279
449
  function sameDomain(a, b) {
280
- return Math.abs(a[0] - b[0]) < 1e-9 && Math.abs(a[1] - b[1]) < 1e-9;
450
+ return Math.abs(a[0] - b[0]) < 1e-9 && Math.abs(a[1] - b[1]) < 1e-9;
281
451
  }
282
- class ChartBrush {
283
- hitbox = viewChild.required('hitbox', /* @ts-ignore */
284
- ...(ngDevMode ? [{ debugName: "hitbox" }] : /* istanbul ignore next */ []));
285
- cart = inject(CartesianContext, { optional: true });
286
- categorical = inject(CategoricalViewportContext, { optional: true });
287
- scatter = inject(ScatterViewportContext, { optional: true });
288
- document = inject(DOCUMENT);
289
- /**
290
- * Torn down the moment a drag ends. Permanent `window:` bindings marked the
291
- * view dirty for every pointer move anywhere on the page, brush or no brush.
292
- */
293
- detachDragListeners = null;
294
- constructor() {
295
- inject(DestroyRef).onDestroy(() => this.detachDragListeners?.());
296
- }
297
- mode = signal(null, /* @ts-ignore */
298
- ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
299
- activePointerId = signal(null, /* @ts-ignore */
300
- ...(ngDevMode ? [{ debugName: "activePointerId" }] : /* istanbul ignore next */ []));
301
- categoryStartIndex = signal(null, /* @ts-ignore */
302
- ...(ngDevMode ? [{ debugName: "categoryStartIndex" }] : /* istanbul ignore next */ []));
303
- categoryPanStart = signal(null, /* @ts-ignore */
304
- ...(ngDevMode ? [{ debugName: "categoryPanStart" }] : /* istanbul ignore next */ []));
305
- scatterBrush = signal(null, /* @ts-ignore */
306
- ...(ngDevMode ? [{ debugName: "scatterBrush" }] : /* istanbul ignore next */ []));
307
- scatterPan = signal(null, /* @ts-ignore */
308
- ...(ngDevMode ? [{ debugName: "scatterPan" }] : /* istanbul ignore next */ []));
309
- width = computed(() => this.scatter?.innerWidth() ?? this.cart?.innerWidth() ?? 0, /* @ts-ignore */
310
- ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
311
- height = computed(() => this.scatter?.innerHeight() ?? this.cart?.innerHeight() ?? 0, /* @ts-ignore */
312
- ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
313
- categoryPreview = computed(() => {
314
- const cart = this.cart;
315
- const viewport = this.categorical;
316
- const range = viewport?.brushRange();
317
- const scale = cart?.categoryScale();
318
- const categories = cart?.categories() ?? [];
319
- if (!cart || !viewport || !range || !scale || categories.length === 0) {
320
- return null;
321
- }
322
- const visibleStart = viewport.zoomRange()?.startIndex ?? 0;
323
- const startVisible = range.startIndex - visibleStart;
324
- const endVisible = range.endIndex - visibleStart;
325
- if (startVisible < 0 || endVisible >= categories.length) {
326
- return null;
327
- }
328
- const first = scale(categories[startVisible]) ?? 0;
329
- const last = (scale(categories[endVisible]) ?? 0) + scale.bandwidth();
330
- if (cart.orientation() === 'vertical') {
331
- return {
332
- x: Math.min(first, last),
333
- y: 0,
334
- width: Math.abs(last - first),
335
- height: cart.innerHeight(),
336
- };
337
- }
338
- return {
339
- x: 0,
340
- y: Math.min(first, last),
341
- width: cart.innerWidth(),
342
- height: Math.abs(last - first),
343
- };
344
- }, /* @ts-ignore */
345
- ...(ngDevMode ? [{ debugName: "categoryPreview" }] : /* istanbul ignore next */ []));
346
- scatterPreviewRect = computed(() => {
347
- const preview = this.scatterBrush();
348
- if (!preview) {
349
- return null;
350
- }
351
- return {
352
- x: Math.min(preview.start.x, preview.current.x),
353
- y: Math.min(preview.start.y, preview.current.y),
354
- width: Math.abs(preview.current.x - preview.start.x),
355
- height: Math.abs(preview.current.y - preview.start.y),
356
- };
357
- }, /* @ts-ignore */
358
- ...(ngDevMode ? [{ debugName: "scatterPreviewRect" }] : /* istanbul ignore next */ []));
359
- onPointerDown(event) {
360
- if (this.activePointerId() != null) {
361
- return;
362
- }
363
- const local = this.localPoint(event);
364
- if (!local) {
365
- return;
366
- }
367
- if (this.scatter) {
368
- if (!this.scatter.fullXDomain() || !this.scatter.fullYDomain()) {
369
- return;
370
- }
371
- event.preventDefault();
372
- this.beginDrag(event);
373
- this.onScatterPointerDown(event, local);
374
- return;
375
- }
376
- if (!this.cart || !this.categorical) {
377
- return;
378
- }
379
- const index = nearestCategoryIndex({
380
- categoryScale: this.cart.categoryScale,
381
- categories: this.cart.categories,
382
- orientation: this.cart.orientation,
383
- }, local.x, local.y);
384
- if (index < 0) {
385
- return;
386
- }
387
- event.preventDefault();
388
- this.beginDrag(event);
389
- const visibleStart = this.categorical.zoomRange()?.startIndex ?? 0;
390
- const absoluteIndex = visibleStart + index;
391
- if (event.pointerType === 'touch' && this.categorical.hasZoom()) {
392
- this.mode.set('category-pan');
393
- this.categoryPanStart.set({
394
- coord: this.pointerAxis(local),
395
- range: this.categorical.zoomRange(),
396
- });
397
- return;
398
- }
399
- this.mode.set('category-brush');
400
- this.categoryStartIndex.set(absoluteIndex);
401
- this.categorical.brushRange.set({ startIndex: absoluteIndex, endIndex: absoluteIndex });
402
- }
403
- onPointerMove(event) {
404
- if (this.activePointerId() !== event.pointerId) {
405
- return;
406
- }
407
- const local = this.localPoint(event);
408
- if (!local) {
409
- return;
410
- }
411
- if (this.mode() === 'category-brush' && this.cart && this.categorical) {
412
- const startIndex = this.categoryStartIndex();
413
- if (startIndex == null) {
414
- return;
415
- }
416
- const index = nearestCategoryIndex({
417
- categoryScale: this.cart.categoryScale,
418
- categories: this.cart.categories,
419
- orientation: this.cart.orientation,
420
- }, local.x, local.y);
421
- if (index < 0) {
422
- return;
423
- }
424
- const visibleStart = this.categorical.zoomRange()?.startIndex ?? 0;
425
- this.categorical.brushRange.set(normalizeIndexRange(startIndex, visibleStart + index, this.categorical.dataCount()));
426
- return;
427
- }
428
- if (this.mode() === 'category-pan' && this.cart && this.categorical) {
429
- const pan = this.categoryPanStart();
430
- if (!pan) {
431
- return;
432
- }
433
- const scale = this.cart.categoryScale();
434
- const step = scale?.step?.() ?? scale?.bandwidth() ?? 0;
435
- if (step <= 0) {
436
- return;
437
- }
438
- const deltaSteps = Math.round((pan.coord - this.pointerAxis(local)) / step);
439
- this.categorical.zoomRange.set(panIndexRange(pan.range, this.categorical.dataCount(), deltaSteps));
440
- return;
441
- }
442
- if (this.mode() === 'scatter-brush') {
443
- const preview = this.scatterBrush();
444
- if (!preview) {
445
- return;
446
- }
447
- this.scatterBrush.set({ start: preview.start, current: local });
448
- return;
449
- }
450
- if (this.mode() === 'scatter-pan' && this.scatter) {
451
- const pan = this.scatterPan();
452
- const xScale = this.scatter.xScale();
453
- const yScale = this.scatter.yScale();
454
- const fullX = this.scatter.fullXDomain();
455
- const fullY = this.scatter.fullYDomain();
456
- if (!pan || !xScale || !yScale || !fullX || !fullY) {
457
- return;
458
- }
459
- const deltaX = xScale.invert(pan.start.x) - xScale.invert(local.x);
460
- const deltaY = yScale.invert(pan.start.y) - yScale.invert(local.y);
461
- this.scatter.zoomXDomain.set(panNumericDomain(pan.xDomain, fullX, deltaX));
462
- this.scatter.zoomYDomain.set(panNumericDomain(pan.yDomain, fullY, deltaY));
463
- }
464
- }
465
- onPointerUp(event) {
466
- if (event && this.activePointerId() !== event.pointerId) {
467
- return;
468
- }
469
- if (this.mode() === 'category-brush' && this.categorical) {
470
- const range = this.categorical.brushRange();
471
- if (range && indexRangeSize(range, this.categorical.dataCount()) > 1) {
472
- this.categorical.zoomRange.set(range);
473
- }
474
- this.categorical.brushRange.set(null);
475
- }
476
- if (this.mode() === 'scatter-brush' && this.scatter) {
477
- const preview = this.scatterBrush();
478
- const xScale = this.scatter.xScale();
479
- const yScale = this.scatter.yScale();
480
- const fullX = this.scatter.fullXDomain();
481
- const fullY = this.scatter.fullYDomain();
482
- if (preview && xScale && yScale && fullX && fullY) {
483
- const width = Math.abs(preview.current.x - preview.start.x);
484
- const height = Math.abs(preview.current.y - preview.start.y);
485
- if (width >= 6 && height >= 6) {
486
- const nextX = normalizeNumericDomain(xScale.invert(preview.start.x), xScale.invert(preview.current.x));
487
- const nextY = normalizeNumericDomain(yScale.invert(preview.start.y), yScale.invert(preview.current.y));
488
- this.scatter.zoomXDomain.set(sameDomain(nextX, fullX) ? null : nextX);
489
- this.scatter.zoomYDomain.set(sameDomain(nextY, fullY) ? null : nextY);
490
- }
491
- }
492
- this.scatterBrush.set(null);
493
- }
494
- this.mode.set(null);
495
- this.categoryStartIndex.set(null);
496
- this.categoryPanStart.set(null);
497
- this.scatterPan.set(null);
498
- this.endDrag(event);
499
- }
500
- onPointerCancel(event) {
501
- if (this.activePointerId() !== event.pointerId) {
502
- return;
503
- }
504
- this.mode.set(null);
505
- this.categorical?.brushRange.set(null);
506
- this.scatterBrush.set(null);
507
- this.categoryStartIndex.set(null);
508
- this.categoryPanStart.set(null);
509
- this.scatterPan.set(null);
510
- this.endDrag(event);
511
- }
512
- onWheel(event) {
513
- const local = this.localPoint(event);
514
- if (!local) {
515
- return;
516
- }
517
- event.preventDefault();
518
- if (this.scatter) {
519
- const xScale = this.scatter.xScale();
520
- const yScale = this.scatter.yScale();
521
- const fullX = this.scatter.fullXDomain();
522
- const fullY = this.scatter.fullYDomain();
523
- if (!xScale || !yScale || !fullX || !fullY) {
524
- return;
525
- }
526
- const factor = event.deltaY < 0 ? 0.8 : 1.25;
527
- const currentX = this.scatter.zoomXDomain() ?? fullX;
528
- const currentY = this.scatter.zoomYDomain() ?? fullY;
529
- const nextX = zoomNumericDomain(currentX, fullX, xScale.invert(local.x), factor);
530
- const nextY = zoomNumericDomain(currentY, fullY, yScale.invert(local.y), factor);
531
- this.scatter.zoomXDomain.set(sameDomain(nextX, fullX) ? null : nextX);
532
- this.scatter.zoomYDomain.set(sameDomain(nextY, fullY) ? null : nextY);
533
- return;
534
- }
535
- if (!this.cart || !this.categorical) {
536
- return;
537
- }
538
- const visibleIndex = nearestCategoryIndex({
539
- categoryScale: this.cart.categoryScale,
540
- categories: this.cart.categories,
541
- orientation: this.cart.orientation,
542
- }, local.x, local.y);
543
- if (visibleIndex < 0) {
544
- return;
545
- }
546
- const anchor = (this.categorical.zoomRange()?.startIndex ?? 0) + visibleIndex;
547
- const factor = event.deltaY < 0 ? 0.75 : 1.25;
548
- this.categorical.zoomRange.set(zoomIndexRange(this.categorical.zoomRange(), this.categorical.dataCount(), anchor, factor));
549
- this.categorical.brushRange.set(null);
550
- }
551
- resetZoom() {
552
- this.categorical?.resetZoom();
553
- this.scatter?.resetZoom();
554
- this.scatterBrush.set(null);
555
- }
556
- beginDrag(event) {
557
- this.activePointerId.set(event.pointerId);
558
- this.hitbox().nativeElement.setPointerCapture(event.pointerId);
559
- const move = (next) => this.onPointerMove(next);
560
- const up = (next) => this.onPointerUp(next);
561
- const cancel = (next) => this.onPointerCancel(next);
562
- this.document.addEventListener('pointermove', move);
563
- this.document.addEventListener('pointerup', up);
564
- this.document.addEventListener('pointercancel', cancel);
565
- this.detachDragListeners = () => {
566
- this.document.removeEventListener('pointermove', move);
567
- this.document.removeEventListener('pointerup', up);
568
- this.document.removeEventListener('pointercancel', cancel);
569
- this.detachDragListeners = null;
570
- };
571
- }
572
- endDrag(event) {
573
- if (event && this.hitbox().nativeElement.hasPointerCapture(event.pointerId)) {
574
- this.hitbox().nativeElement.releasePointerCapture(event.pointerId);
575
- }
576
- this.detachDragListeners?.();
577
- this.activePointerId.set(null);
578
- }
579
- onScatterPointerDown(event, local) {
580
- const fullX = this.scatter?.fullXDomain();
581
- const fullY = this.scatter?.fullYDomain();
582
- if (!this.scatter || !fullX || !fullY) {
583
- return;
584
- }
585
- if (event.pointerType === 'touch' && this.scatter.hasZoom()) {
586
- this.mode.set('scatter-pan');
587
- this.scatterPan.set({
588
- start: local,
589
- xDomain: this.scatter.zoomXDomain() ?? fullX,
590
- yDomain: this.scatter.zoomYDomain() ?? fullY,
591
- });
592
- return;
593
- }
594
- this.mode.set('scatter-brush');
595
- this.scatterBrush.set({ start: local, current: local });
596
- }
597
- localPoint(event) {
598
- const hitbox = this.hitbox()?.nativeElement;
599
- const width = this.width();
600
- const height = this.height();
601
- if (!hitbox || width <= 0 || height <= 0) {
602
- return null;
603
- }
604
- const rect = hitbox.getBoundingClientRect();
605
- if (rect.width <= 0 || rect.height <= 0) {
606
- return null;
607
- }
608
- return {
609
- x: clamp(((event.clientX - rect.left) / rect.width) * width, 0, width),
610
- y: clamp(((event.clientY - rect.top) / rect.height) * height, 0, height),
611
- };
612
- }
613
- pointerAxis(local) {
614
- return this.cart?.orientation() === 'horizontal' ? local.y : local.x;
615
- }
616
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartBrush, deps: [], target: i0.ɵɵFactoryTarget.Component });
617
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartBrush, isStandalone: true, selector: "svg:g[ChartBrush]", host: { classAttribute: "chart-brush" }, viewQueries: [{ propertyName: "hitbox", first: true, predicate: ["hitbox"], descendants: true, isSignal: true }], ngImport: i0, template: `
452
+ var ChartBrush = class ChartBrush {
453
+ hitbox = viewChild.required("hitbox", ...ngDevMode ? [{ debugName: "hitbox" }] : /* istanbul ignore next */ []);
454
+ cart = inject(CartesianContext, { optional: true });
455
+ categorical = inject(CategoricalViewportContext, { optional: true });
456
+ scatter = inject(ScatterViewportContext, { optional: true });
457
+ document = inject(DOCUMENT);
458
+ detachDragListeners = null;
459
+ constructor() {
460
+ inject(DestroyRef).onDestroy(() => this.detachDragListeners?.());
461
+ }
462
+ mode = signal(null, ...ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []);
463
+ activePointerId = signal(null, ...ngDevMode ? [{ debugName: "activePointerId" }] : /* istanbul ignore next */ []);
464
+ categoryStartIndex = signal(null, ...ngDevMode ? [{ debugName: "categoryStartIndex" }] : /* istanbul ignore next */ []);
465
+ categoryPanStart = signal(null, ...ngDevMode ? [{ debugName: "categoryPanStart" }] : /* istanbul ignore next */ []);
466
+ scatterBrush = signal(null, ...ngDevMode ? [{ debugName: "scatterBrush" }] : /* istanbul ignore next */ []);
467
+ scatterPan = signal(null, ...ngDevMode ? [{ debugName: "scatterPan" }] : /* istanbul ignore next */ []);
468
+ width = computed(() => this.scatter?.innerWidth() ?? this.cart?.innerWidth() ?? 0, ...ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []);
469
+ height = computed(() => this.scatter?.innerHeight() ?? this.cart?.innerHeight() ?? 0, ...ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []);
470
+ categoryPreview = computed(() => {
471
+ const cart = this.cart;
472
+ const viewport = this.categorical;
473
+ const range = viewport?.brushRange();
474
+ const scale = cart?.categoryScale();
475
+ const categories = cart?.categories() ?? [];
476
+ if (!cart || !viewport || !range || !scale || categories.length === 0) return null;
477
+ const visibleStart = viewport.zoomRange()?.startIndex ?? 0;
478
+ const startVisible = range.startIndex - visibleStart;
479
+ const endVisible = range.endIndex - visibleStart;
480
+ if (startVisible < 0 || endVisible >= categories.length) return null;
481
+ const first = scale(categories[startVisible]) ?? 0;
482
+ const last = (scale(categories[endVisible]) ?? 0) + scale.bandwidth();
483
+ if (cart.orientation() === "vertical") return {
484
+ x: Math.min(first, last),
485
+ y: 0,
486
+ width: Math.abs(last - first),
487
+ height: cart.innerHeight()
488
+ };
489
+ return {
490
+ x: 0,
491
+ y: Math.min(first, last),
492
+ width: cart.innerWidth(),
493
+ height: Math.abs(last - first)
494
+ };
495
+ }, ...ngDevMode ? [{ debugName: "categoryPreview" }] : /* istanbul ignore next */ []);
496
+ scatterPreviewRect = computed(() => {
497
+ const preview = this.scatterBrush();
498
+ if (!preview) return null;
499
+ return {
500
+ x: Math.min(preview.start.x, preview.current.x),
501
+ y: Math.min(preview.start.y, preview.current.y),
502
+ width: Math.abs(preview.current.x - preview.start.x),
503
+ height: Math.abs(preview.current.y - preview.start.y)
504
+ };
505
+ }, ...ngDevMode ? [{ debugName: "scatterPreviewRect" }] : /* istanbul ignore next */ []);
506
+ onPointerDown(event) {
507
+ if (this.activePointerId() != null) return;
508
+ const local = this.localPoint(event);
509
+ if (!local) return;
510
+ if (this.scatter) {
511
+ if (!this.scatter.fullXDomain() || !this.scatter.fullYDomain()) return;
512
+ event.preventDefault();
513
+ this.beginDrag(event);
514
+ this.onScatterPointerDown(event, local);
515
+ return;
516
+ }
517
+ if (!this.cart || !this.categorical) return;
518
+ const index = nearestCategoryIndex({
519
+ categoryScale: this.cart.categoryScale,
520
+ categories: this.cart.categories,
521
+ orientation: this.cart.orientation
522
+ }, local.x, local.y);
523
+ if (index < 0) return;
524
+ event.preventDefault();
525
+ this.beginDrag(event);
526
+ const absoluteIndex = (this.categorical.zoomRange()?.startIndex ?? 0) + index;
527
+ if (event.pointerType === "touch" && this.categorical.hasZoom()) {
528
+ this.mode.set("category-pan");
529
+ this.categoryPanStart.set({
530
+ coord: this.pointerAxis(local),
531
+ range: this.categorical.zoomRange()
532
+ });
533
+ return;
534
+ }
535
+ this.mode.set("category-brush");
536
+ this.categoryStartIndex.set(absoluteIndex);
537
+ this.categorical.brushRange.set({
538
+ startIndex: absoluteIndex,
539
+ endIndex: absoluteIndex
540
+ });
541
+ }
542
+ onPointerMove(event) {
543
+ if (this.activePointerId() !== event.pointerId) return;
544
+ const local = this.localPoint(event);
545
+ if (!local) return;
546
+ if (this.mode() === "category-brush" && this.cart && this.categorical) {
547
+ const startIndex = this.categoryStartIndex();
548
+ if (startIndex == null) return;
549
+ const index = nearestCategoryIndex({
550
+ categoryScale: this.cart.categoryScale,
551
+ categories: this.cart.categories,
552
+ orientation: this.cart.orientation
553
+ }, local.x, local.y);
554
+ if (index < 0) return;
555
+ const visibleStart = this.categorical.zoomRange()?.startIndex ?? 0;
556
+ this.categorical.brushRange.set(normalizeIndexRange(startIndex, visibleStart + index, this.categorical.dataCount()));
557
+ return;
558
+ }
559
+ if (this.mode() === "category-pan" && this.cart && this.categorical) {
560
+ const pan = this.categoryPanStart();
561
+ if (!pan) return;
562
+ const scale = this.cart.categoryScale();
563
+ const step = scale?.step?.() ?? scale?.bandwidth() ?? 0;
564
+ if (step <= 0) return;
565
+ const deltaSteps = Math.round((pan.coord - this.pointerAxis(local)) / step);
566
+ this.categorical.zoomRange.set(panIndexRange(pan.range, this.categorical.dataCount(), deltaSteps));
567
+ return;
568
+ }
569
+ if (this.mode() === "scatter-brush") {
570
+ const preview = this.scatterBrush();
571
+ if (!preview) return;
572
+ this.scatterBrush.set({
573
+ start: preview.start,
574
+ current: local
575
+ });
576
+ return;
577
+ }
578
+ if (this.mode() === "scatter-pan" && this.scatter) {
579
+ const pan = this.scatterPan();
580
+ const xScale = this.scatter.xScale();
581
+ const yScale = this.scatter.yScale();
582
+ const fullX = this.scatter.fullXDomain();
583
+ const fullY = this.scatter.fullYDomain();
584
+ if (!pan || !xScale || !yScale || !fullX || !fullY) return;
585
+ const deltaX = xScale.invert(pan.start.x) - xScale.invert(local.x);
586
+ const deltaY = yScale.invert(pan.start.y) - yScale.invert(local.y);
587
+ this.scatter.zoomXDomain.set(panNumericDomain(pan.xDomain, fullX, deltaX));
588
+ this.scatter.zoomYDomain.set(panNumericDomain(pan.yDomain, fullY, deltaY));
589
+ }
590
+ }
591
+ onPointerUp(event) {
592
+ if (event && this.activePointerId() !== event.pointerId) return;
593
+ if (this.mode() === "category-brush" && this.categorical) {
594
+ const range = this.categorical.brushRange();
595
+ if (range && indexRangeSize(range, this.categorical.dataCount()) > 1) this.categorical.zoomRange.set(range);
596
+ this.categorical.brushRange.set(null);
597
+ }
598
+ if (this.mode() === "scatter-brush" && this.scatter) {
599
+ const preview = this.scatterBrush();
600
+ const xScale = this.scatter.xScale();
601
+ const yScale = this.scatter.yScale();
602
+ const fullX = this.scatter.fullXDomain();
603
+ const fullY = this.scatter.fullYDomain();
604
+ if (preview && xScale && yScale && fullX && fullY) {
605
+ const width = Math.abs(preview.current.x - preview.start.x);
606
+ const height = Math.abs(preview.current.y - preview.start.y);
607
+ if (width >= 6 && height >= 6) {
608
+ const nextX = normalizeNumericDomain(xScale.invert(preview.start.x), xScale.invert(preview.current.x));
609
+ const nextY = normalizeNumericDomain(yScale.invert(preview.start.y), yScale.invert(preview.current.y));
610
+ this.scatter.zoomXDomain.set(sameDomain(nextX, fullX) ? null : nextX);
611
+ this.scatter.zoomYDomain.set(sameDomain(nextY, fullY) ? null : nextY);
612
+ }
613
+ }
614
+ this.scatterBrush.set(null);
615
+ }
616
+ this.mode.set(null);
617
+ this.categoryStartIndex.set(null);
618
+ this.categoryPanStart.set(null);
619
+ this.scatterPan.set(null);
620
+ this.endDrag(event);
621
+ }
622
+ onPointerCancel(event) {
623
+ if (this.activePointerId() !== event.pointerId) return;
624
+ this.mode.set(null);
625
+ this.categorical?.brushRange.set(null);
626
+ this.scatterBrush.set(null);
627
+ this.categoryStartIndex.set(null);
628
+ this.categoryPanStart.set(null);
629
+ this.scatterPan.set(null);
630
+ this.endDrag(event);
631
+ }
632
+ onWheel(event) {
633
+ const local = this.localPoint(event);
634
+ if (!local) return;
635
+ event.preventDefault();
636
+ if (this.scatter) {
637
+ const xScale = this.scatter.xScale();
638
+ const yScale = this.scatter.yScale();
639
+ const fullX = this.scatter.fullXDomain();
640
+ const fullY = this.scatter.fullYDomain();
641
+ if (!xScale || !yScale || !fullX || !fullY) return;
642
+ const factor = event.deltaY < 0 ? .8 : 1.25;
643
+ const currentX = this.scatter.zoomXDomain() ?? fullX;
644
+ const currentY = this.scatter.zoomYDomain() ?? fullY;
645
+ const nextX = zoomNumericDomain(currentX, fullX, xScale.invert(local.x), factor);
646
+ const nextY = zoomNumericDomain(currentY, fullY, yScale.invert(local.y), factor);
647
+ this.scatter.zoomXDomain.set(sameDomain(nextX, fullX) ? null : nextX);
648
+ this.scatter.zoomYDomain.set(sameDomain(nextY, fullY) ? null : nextY);
649
+ return;
650
+ }
651
+ if (!this.cart || !this.categorical) return;
652
+ const visibleIndex = nearestCategoryIndex({
653
+ categoryScale: this.cart.categoryScale,
654
+ categories: this.cart.categories,
655
+ orientation: this.cart.orientation
656
+ }, local.x, local.y);
657
+ if (visibleIndex < 0) return;
658
+ const anchor = (this.categorical.zoomRange()?.startIndex ?? 0) + visibleIndex;
659
+ const factor = event.deltaY < 0 ? .75 : 1.25;
660
+ this.categorical.zoomRange.set(zoomIndexRange(this.categorical.zoomRange(), this.categorical.dataCount(), anchor, factor));
661
+ this.categorical.brushRange.set(null);
662
+ }
663
+ resetZoom() {
664
+ this.categorical?.resetZoom();
665
+ this.scatter?.resetZoom();
666
+ this.scatterBrush.set(null);
667
+ }
668
+ beginDrag(event) {
669
+ this.activePointerId.set(event.pointerId);
670
+ this.hitbox().nativeElement.setPointerCapture(event.pointerId);
671
+ const move = (next) => this.onPointerMove(next);
672
+ const up = (next) => this.onPointerUp(next);
673
+ const cancel = (next) => this.onPointerCancel(next);
674
+ this.document.addEventListener("pointermove", move);
675
+ this.document.addEventListener("pointerup", up);
676
+ this.document.addEventListener("pointercancel", cancel);
677
+ this.detachDragListeners = () => {
678
+ this.document.removeEventListener("pointermove", move);
679
+ this.document.removeEventListener("pointerup", up);
680
+ this.document.removeEventListener("pointercancel", cancel);
681
+ this.detachDragListeners = null;
682
+ };
683
+ }
684
+ endDrag(event) {
685
+ if (event && this.hitbox().nativeElement.hasPointerCapture(event.pointerId)) this.hitbox().nativeElement.releasePointerCapture(event.pointerId);
686
+ this.detachDragListeners?.();
687
+ this.activePointerId.set(null);
688
+ }
689
+ onScatterPointerDown(event, local) {
690
+ const fullX = this.scatter?.fullXDomain();
691
+ const fullY = this.scatter?.fullYDomain();
692
+ if (!this.scatter || !fullX || !fullY) return;
693
+ if (event.pointerType === "touch" && this.scatter.hasZoom()) {
694
+ this.mode.set("scatter-pan");
695
+ this.scatterPan.set({
696
+ start: local,
697
+ xDomain: this.scatter.zoomXDomain() ?? fullX,
698
+ yDomain: this.scatter.zoomYDomain() ?? fullY
699
+ });
700
+ return;
701
+ }
702
+ this.mode.set("scatter-brush");
703
+ this.scatterBrush.set({
704
+ start: local,
705
+ current: local
706
+ });
707
+ }
708
+ localPoint(event) {
709
+ const hitbox = this.hitbox()?.nativeElement;
710
+ const width = this.width();
711
+ const height = this.height();
712
+ if (!hitbox || width <= 0 || height <= 0) return null;
713
+ const rect = hitbox.getBoundingClientRect();
714
+ if (rect.width <= 0 || rect.height <= 0) return null;
715
+ return {
716
+ x: clamp((event.clientX - rect.left) / rect.width * width, 0, width),
717
+ y: clamp((event.clientY - rect.top) / rect.height * height, 0, height)
718
+ };
719
+ }
720
+ pointerAxis(local) {
721
+ return this.cart?.orientation() === "horizontal" ? local.y : local.x;
722
+ }
723
+ static ɵfac = i0.ɵɵngDeclareFactory({
724
+ minVersion: "12.0.0",
725
+ version: "22.2.2",
726
+ ngImport: i0,
727
+ type: ChartBrush,
728
+ deps: [],
729
+ target: i0.ɵɵFactoryTarget.Component
730
+ });
731
+ static ɵcmp = i0.ɵɵngDeclareComponent({
732
+ minVersion: "17.0.0",
733
+ version: "22.2.2",
734
+ type: ChartBrush,
735
+ isStandalone: true,
736
+ selector: "svg:g[ChartBrush]",
737
+ host: { classAttribute: "chart-brush" },
738
+ viewQueries: [{
739
+ propertyName: "hitbox",
740
+ first: true,
741
+ predicate: ["hitbox"],
742
+ descendants: true,
743
+ isSignal: true
744
+ }],
745
+ ngImport: i0,
746
+ template: `
618
747
  <svg:rect
619
748
  #hitbox
620
749
  class="fill-transparent touch-none"
@@ -648,14 +777,21 @@ class ChartBrush {
648
777
  stroke-dasharray="4 3"
649
778
  />
650
779
  }
651
- `, isInline: true });
652
- }
653
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartBrush, decorators: [{
654
- type: Component,
655
- args: [{
656
- selector: 'svg:g[ChartBrush]',
657
- host: { class: 'chart-brush' },
658
- template: `
780
+ `,
781
+ isInline: true
782
+ });
783
+ };
784
+ i0.ɵɵngDeclareClassMetadata({
785
+ minVersion: "12.0.0",
786
+ version: "22.2.2",
787
+ ngImport: i0,
788
+ type: ChartBrush,
789
+ decorators: [{
790
+ type: Component,
791
+ args: [{
792
+ selector: "svg:g[ChartBrush]",
793
+ host: { class: "chart-brush" },
794
+ template: `
659
795
  <svg:rect
660
796
  #hitbox
661
797
  class="fill-transparent touch-none"
@@ -689,268 +825,310 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
689
825
  stroke-dasharray="4 3"
690
826
  />
691
827
  }
692
- `,
693
- }]
694
- }], ctorParameters: () => [], propDecorators: { hitbox: [{ type: i0.ViewChild, args: ['hitbox', { isSignal: true }] }] } });
695
-
696
- /**
697
- * Attach to a chart's `<svg:svg>` to publish pointer-driven active-point
698
- * state into the surrounding `ChartContext`.
699
- *
700
- * Computes the local (x, y) of the pointer relative to the inner plotting
701
- * area, resolves the nearest category, and updates
702
- * `ChartContext.activePoint`. Clears it on `pointerleave`.
703
- */
704
- class ChartPointerTracker {
705
- root = inject(ChartContext);
706
- cart = inject(CartesianContext);
707
- viewport = inject(CategoricalViewportContext, { optional: true });
708
- onMove(event) {
709
- const target = event.currentTarget;
710
- if (!target)
711
- return;
712
- const rect = target.getBoundingClientRect();
713
- if (rect.width === 0 || rect.height === 0)
714
- return;
715
- const { width, height } = this.root.dimensions();
716
- // Map client coords → viewBox coords (SVG uses `0 0 width height`,
717
- // preserveAspectRatio="none" so axes scale independently).
718
- const scaleX = width / rect.width;
719
- const scaleY = height / rect.height;
720
- const viewX = (event.clientX - rect.left) * scaleX;
721
- const viewY = (event.clientY - rect.top) * scaleY;
722
- const margin = this.cart.margin();
723
- const localX = viewX - margin.left;
724
- const localY = viewY - margin.top;
725
- const index = nearestCategoryIndex({
726
- categoryScale: this.cart.categoryScale,
727
- categories: this.cart.categories,
728
- orientation: this.cart.orientation,
729
- }, localX, localY);
730
- if (index < 0) {
731
- this.root.activePoint.set(null);
732
- return;
733
- }
734
- this.root.activePoint.set({
735
- index,
736
- datumIndex: (this.viewport?.zoomRange()?.startIndex ?? 0) + index,
737
- clientX: event.clientX,
738
- clientY: event.clientY,
739
- });
740
- }
741
- onLeave() {
742
- this.root.activePoint.set(null);
743
- }
744
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartPointerTracker, deps: [], target: i0.ɵɵFactoryTarget.Directive });
745
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.6", type: ChartPointerTracker, isStandalone: true, selector: "svg:svg[ChartPointerTracker]", host: { listeners: { "pointermove": "onMove($event)", "pointerleave": "onLeave()" } }, ngImport: i0 });
746
- }
747
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartPointerTracker, decorators: [{
748
- type: Directive,
749
- args: [{
750
- selector: 'svg:svg[ChartPointerTracker]',
751
- host: {
752
- '(pointermove)': 'onMove($event)',
753
- '(pointerleave)': 'onLeave()',
754
- },
755
- }]
756
- }] });
757
-
758
- /** Locate the chart container DOM in order to position the tooltip. */
828
+ `
829
+ }]
830
+ }],
831
+ ctorParameters: () => [],
832
+ propDecorators: { hitbox: [{
833
+ type: i0.ViewChild,
834
+ args: ["hitbox", { isSignal: true }]
835
+ }] }
836
+ });
837
+ var ChartPointerTracker = class ChartPointerTracker {
838
+ root = inject(ChartContext);
839
+ cart = inject(CartesianContext);
840
+ viewport = inject(CategoricalViewportContext, { optional: true });
841
+ onMove(event) {
842
+ const target = event.currentTarget;
843
+ if (!target) return;
844
+ const rect = target.getBoundingClientRect();
845
+ if (rect.width === 0 || rect.height === 0) return;
846
+ const { width, height } = this.root.dimensions();
847
+ const scaleX = width / rect.width;
848
+ const scaleY = height / rect.height;
849
+ const viewX = (event.clientX - rect.left) * scaleX;
850
+ const viewY = (event.clientY - rect.top) * scaleY;
851
+ const margin = this.cart.margin();
852
+ const localX = viewX - margin.left;
853
+ const localY = viewY - margin.top;
854
+ const index = nearestCategoryIndex({
855
+ categoryScale: this.cart.categoryScale,
856
+ categories: this.cart.categories,
857
+ orientation: this.cart.orientation
858
+ }, localX, localY);
859
+ if (index < 0) {
860
+ this.root.activePoint.set(null);
861
+ return;
862
+ }
863
+ this.root.activePoint.set({
864
+ index,
865
+ datumIndex: (this.viewport?.zoomRange()?.startIndex ?? 0) + index,
866
+ clientX: event.clientX,
867
+ clientY: event.clientY
868
+ });
869
+ }
870
+ onLeave() {
871
+ this.root.activePoint.set(null);
872
+ }
873
+ static ɵfac = i0.ɵɵngDeclareFactory({
874
+ minVersion: "12.0.0",
875
+ version: "22.2.2",
876
+ ngImport: i0,
877
+ type: ChartPointerTracker,
878
+ deps: [],
879
+ target: i0.ɵɵFactoryTarget.Directive
880
+ });
881
+ static ɵdir = i0.ɵɵngDeclareDirective({
882
+ minVersion: "14.0.0",
883
+ version: "22.2.2",
884
+ type: ChartPointerTracker,
885
+ isStandalone: true,
886
+ selector: "svg:svg[ChartPointerTracker]",
887
+ host: { listeners: {
888
+ "pointermove": "onMove($event)",
889
+ "pointerleave": "onLeave()"
890
+ } },
891
+ ngImport: i0
892
+ });
893
+ };
894
+ i0.ɵɵngDeclareClassMetadata({
895
+ minVersion: "12.0.0",
896
+ version: "22.2.2",
897
+ ngImport: i0,
898
+ type: ChartPointerTracker,
899
+ decorators: [{
900
+ type: Directive,
901
+ args: [{
902
+ selector: "svg:svg[ChartPointerTracker]",
903
+ host: {
904
+ "(pointermove)": "onMove($event)",
905
+ "(pointerleave)": "onLeave()"
906
+ }
907
+ }]
908
+ }]
909
+ });
759
910
  function chartContainerElement(el) {
760
- // Climb to the nearest `[data-chart]` (the ChartContainer host).
761
- let node = el;
762
- while (node && !node.hasAttribute('data-chart')) {
763
- node = node.parentElement;
764
- }
765
- return node;
911
+ let node = el;
912
+ while (node && !node.hasAttribute("data-chart")) node = node.parentElement;
913
+ return node;
766
914
  }
767
- /** Card width assumed before the card has ever been laid out. */
768
915
  const FALLBACK_TOOLTIP_WIDTH = 128;
769
- /**
770
- * Tooltip overlay — renders the default tooltip card (or a user-supplied
771
- * template) anchored to the currently active data point.
772
- *
773
- * Shadcn-compatible knobs:
774
- * - `indicator="line"` / `"none"` / `"dashed"` — swap the row glyph
775
- * - `hideLabel` — drop the header row
776
- * - `label="Activities"` — override the header text
777
- * - `labelKey="activities"` — resolve the header from `config[labelKey].label`
778
- * - `labelFormatter` — transform the header (e.g. ISO date → long date)
779
- * - `formatter` — format per-row values (e.g. `"380 kcal"`)
780
- * - `valueKey` — for pie/radial/radar, read row value from a single field
781
- * - Icons are picked up automatically from `config[key].icon`.
782
- */
783
- class ChartTooltip {
784
- root = inject(ChartContext);
785
- host = inject((ElementRef));
786
- zone = inject(NgZone);
787
- platformId = inject(PLATFORM_ID);
788
- destroyRef = inject(DestroyRef);
789
- /**
790
- * The two measurements `position` needs, taken outside it.
791
- *
792
- * `position` used to call `getBoundingClientRect` and read `offsetWidth`
793
- * while the template evaluated it, which forced layout on every tick and left
794
- * the tooltip stale after a resize — a computed only re-runs for the signals
795
- * it reads, and a DOM box is not one.
796
- */
797
- containerBox = signal(null, { ...(ngDevMode ? { debugName: "containerBox" } : /* istanbul ignore next */ {}), equal: (a, b) => a?.left === b?.left && a?.top === b?.top && a?.width === b?.width });
798
- tooltipBox = signal({ width: FALLBACK_TOOLTIP_WIDTH, height: 0 }, { ...(ngDevMode ? { debugName: "tooltipBox" } : /* istanbul ignore next */ {}), equal: (a, b) => a.width === b.width && a.height === b.height });
799
- constructor() {
800
- if (!isPlatformBrowser(this.platformId)) {
801
- return;
802
- }
803
- afterNextRender(() => this.observeContainer());
804
- afterRenderEffect(() => {
805
- // Reading the payload ties the measurement to the card's content, so a
806
- // wider row re-measures without the computed ever touching the DOM.
807
- this.payload();
808
- this.measure();
809
- });
810
- }
811
- /** Data key on each datum whose value is the category label (x-axis). */
812
- xKey = input(null, /* @ts-ignore */
813
- ...(ngDevMode ? [{ debugName: "xKey" }] : /* istanbul ignore next */ []));
814
- /** Data source (optional — if omitted tooltip reads from chart data via activePoint.datumIndex). */
815
- data = input(null, /* @ts-ignore */
816
- ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
817
- /**
818
- * Optional key for per-datum value lookup (pie / radial / radar datasets
819
- * store values on a single field like `visitors` instead of one field per
820
- * series). When set and `activePoint.seriesKey` is active, the tooltip row
821
- * reads `datum[valueKey]` for its value.
822
- */
823
- valueKey = input(null, /* @ts-ignore */
824
- ...(ngDevMode ? [{ debugName: "valueKey" }] : /* istanbul ignore next */ []));
825
- /** Indicator variant next to each row. Default `'dot'`. */
826
- indicator = input('dot', /* @ts-ignore */
827
- ...(ngDevMode ? [{ debugName: "indicator" }] : /* istanbul ignore next */ []));
828
- /** Hide the header label entirely. */
829
- hideLabel = input(false, /* @ts-ignore */
830
- ...(ngDevMode ? [{ debugName: "hideLabel" }] : /* istanbul ignore next */ []));
831
- /** Override the header label with a fixed string. Takes precedence over `labelKey`. */
832
- label = input(null, /* @ts-ignore */
833
- ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
834
- /**
835
- * Resolve the header label from `config[labelKey].label`. Useful when the
836
- * header should come from a config entry rather than the datum itself
837
- * (shadcn's "Custom label" variant).
838
- */
839
- labelKey = input(null, /* @ts-ignore */
840
- ...(ngDevMode ? [{ debugName: "labelKey" }] : /* istanbul ignore next */ []));
841
- /** Transform the final header string (e.g. ISO date → long date). */
842
- labelFormatter = input(null, /* @ts-ignore */
843
- ...(ngDevMode ? [{ debugName: "labelFormatter" }] : /* istanbul ignore next */ []));
844
- /** Format each row's value (return string — HTML is not interpreted). */
845
- formatter = input(null, /* @ts-ignore */
846
- ...(ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []));
847
- customTpl = contentChild((TemplateRef), /* @ts-ignore */
848
- ...(ngDevMode ? [{ debugName: "customTpl" }] : /* istanbul ignore next */ []));
849
- visible = computed(() => this.root.activePoint() !== null, /* @ts-ignore */
850
- ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
851
- payload = computed(() => {
852
- const active = this.root.activePoint();
853
- const rows = this.data();
854
- if (!active || !rows)
855
- return null;
856
- const dataIndex = active.datumIndex != null && active.datumIndex < rows.length
857
- ? active.datumIndex
858
- : active.index;
859
- if (dataIndex < 0 || dataIndex >= rows.length)
860
- return null;
861
- const cfg = this.root.config();
862
- const visibleKeys = this.root.visibleSeriesKeys();
863
- const datum = rows[dataIndex];
864
- const xKey = this.xKey();
865
- const category = xKey && xKey in datum ? String(datum[xKey]) : String(active.index);
866
- // When the active point targets a single series (pie/radial/radar hover),
867
- // collapse the tooltip to just that row.
868
- const activeSeriesKey = active.seriesKey && visibleKeys.includes(active.seriesKey) ? active.seriesKey : null;
869
- const keys = activeSeriesKey ? [activeSeriesKey] : visibleKeys;
870
- const valueKey = this.valueKey();
871
- const tooltipRows = keys.map((k) => {
872
- // For single-slice hover on pie/radial/radar the value lives on a
873
- // shared `valueKey` field, not on a per-series column.
874
- const rawValue = valueKey != null && activeSeriesKey === k ? datum[valueKey] : datum[k];
875
- return {
876
- seriesKey: k,
877
- label: cfg[k]?.label ?? k,
878
- value: rawValue,
879
- color: seriesColorVar(k),
880
- icon: cfg[k]?.icon,
881
- };
882
- });
883
- return { category, datum, rows: tooltipRows };
884
- }, /* @ts-ignore */
885
- ...(ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []));
886
- /** Resolve the header string honoring `label`, `labelKey`, then `labelFormatter`. */
887
- headerText(p) {
888
- if (this.hideLabel())
889
- return null;
890
- const override = this.label();
891
- const labelKey = this.labelKey();
892
- const cfg = this.root.config();
893
- const fromKey = labelKey ? (cfg[labelKey]?.label ?? labelKey) : null;
894
- const raw = override ?? fromKey ?? p.category;
895
- const fmt = this.labelFormatter();
896
- return fmt ? fmt(raw, p) : raw;
897
- }
898
- /** Apply per-row value formatter (or stringify). */
899
- formatRow(row, p) {
900
- const fmt = this.formatter();
901
- if (fmt)
902
- return fmt(row.value, row, p);
903
- return row.value == null ? '' : String(row.value);
904
- }
905
- position = computed(() => {
906
- const active = this.root.activePoint();
907
- const box = this.containerBox();
908
- if (!active || active.clientX == null || active.clientY == null || !box) {
909
- return { x: 0, y: 0 };
910
- }
911
- // Map client coords → offset within the chart container (the element
912
- // marked with `data-chart`, which is our positioning ancestor).
913
- const { width: tooltipWidth, height: tooltipHeight } = this.tooltipBox();
914
- const padding = 8;
915
- const minX = padding + tooltipWidth / 2;
916
- const maxX = Math.max(minX, box.width - padding - tooltipWidth / 2);
917
- const x = Math.min(maxX, Math.max(minX, active.clientX - box.left));
918
- // Y is the tooltip's bottom edge because the card is translated upward.
919
- const minY = padding + tooltipHeight;
920
- const y = Math.max(minY, active.clientY - box.top - padding);
921
- return { x, y };
922
- }, /* @ts-ignore */
923
- ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
924
- observeContainer() {
925
- const container = chartContainerElement(this.host.nativeElement);
926
- if (!container) {
927
- return;
928
- }
929
- this.measureContainer(container);
930
- if (typeof ResizeObserver === 'undefined') {
931
- return;
932
- }
933
- const observer = new ResizeObserver(() => this.zone.run(() => this.measureContainer(container)));
934
- observer.observe(container);
935
- this.destroyRef.onDestroy(() => observer.disconnect());
936
- }
937
- measure() {
938
- const container = chartContainerElement(this.host.nativeElement);
939
- if (container) {
940
- this.measureContainer(container);
941
- }
942
- const card = this.host.nativeElement.querySelector('[role="tooltip"]');
943
- this.tooltipBox.set({
944
- width: card?.offsetWidth || FALLBACK_TOOLTIP_WIDTH,
945
- height: card?.offsetHeight ?? 0,
946
- });
947
- }
948
- measureContainer(container) {
949
- const rect = container.getBoundingClientRect();
950
- this.containerBox.set({ left: rect.left, top: rect.top, width: rect.width });
951
- }
952
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartTooltip, deps: [], target: i0.ɵɵFactoryTarget.Component });
953
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartTooltip, isStandalone: true, selector: "ChartTooltip", inputs: { xKey: { classPropertyName: "xKey", publicName: "xKey", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, valueKey: { classPropertyName: "valueKey", publicName: "valueKey", isSignal: true, isRequired: false, transformFunction: null }, indicator: { classPropertyName: "indicator", publicName: "indicator", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, labelFormatter: { classPropertyName: "labelFormatter", publicName: "labelFormatter", isSignal: true, isRequired: false, transformFunction: null }, formatter: { classPropertyName: "formatter", publicName: "formatter", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-hidden": "!visible()" }, classAttribute: "pointer-events-none absolute inset-0 z-10" }, queries: [{ propertyName: "customTpl", first: true, predicate: (TemplateRef), descendants: true, isSignal: true }], ngImport: i0, template: `
916
+ var ChartTooltip = class ChartTooltip {
917
+ root = inject(ChartContext);
918
+ host = inject(ElementRef);
919
+ zone = inject(NgZone);
920
+ platformId = inject(PLATFORM_ID);
921
+ destroyRef = inject(DestroyRef);
922
+ containerBox = signal(null, {
923
+ ...ngDevMode ? { debugName: "containerBox" } : /* istanbul ignore next */ {},
924
+ equal: (a, b) => a?.left === b?.left && a?.top === b?.top && a?.width === b?.width
925
+ });
926
+ tooltipBox = signal({
927
+ width: FALLBACK_TOOLTIP_WIDTH,
928
+ height: 0
929
+ }, {
930
+ ...ngDevMode ? { debugName: "tooltipBox" } : /* istanbul ignore next */ {},
931
+ equal: (a, b) => a.width === b.width && a.height === b.height
932
+ });
933
+ constructor() {
934
+ if (!isPlatformBrowser(this.platformId)) return;
935
+ afterNextRender(() => this.observeContainer());
936
+ afterRenderEffect(() => {
937
+ this.payload();
938
+ this.measure();
939
+ });
940
+ }
941
+ xKey = input(null, ...ngDevMode ? [{ debugName: "xKey" }] : /* istanbul ignore next */ []);
942
+ data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
943
+ valueKey = input(null, ...ngDevMode ? [{ debugName: "valueKey" }] : /* istanbul ignore next */ []);
944
+ indicator = input("dot", ...ngDevMode ? [{ debugName: "indicator" }] : /* istanbul ignore next */ []);
945
+ hideLabel = input(false, ...ngDevMode ? [{ debugName: "hideLabel" }] : /* istanbul ignore next */ []);
946
+ label = input(null, ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
947
+ labelKey = input(null, ...ngDevMode ? [{ debugName: "labelKey" }] : /* istanbul ignore next */ []);
948
+ labelFormatter = input(null, ...ngDevMode ? [{ debugName: "labelFormatter" }] : /* istanbul ignore next */ []);
949
+ formatter = input(null, ...ngDevMode ? [{ debugName: "formatter" }] : /* istanbul ignore next */ []);
950
+ customTpl = contentChild(TemplateRef, ...ngDevMode ? [{ debugName: "customTpl" }] : /* istanbul ignore next */ []);
951
+ visible = computed(() => this.root.activePoint() !== null, ...ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []);
952
+ payload = computed(() => {
953
+ const active = this.root.activePoint();
954
+ const rows = this.data();
955
+ if (!active || !rows) return null;
956
+ const dataIndex = active.datumIndex != null && active.datumIndex < rows.length ? active.datumIndex : active.index;
957
+ if (dataIndex < 0 || dataIndex >= rows.length) return null;
958
+ const cfg = this.root.config();
959
+ const visibleKeys = this.root.visibleSeriesKeys();
960
+ const datum = rows[dataIndex];
961
+ const xKey = this.xKey();
962
+ const category = xKey && xKey in datum ? String(datum[xKey]) : String(active.index);
963
+ const activeSeriesKey = active.seriesKey && visibleKeys.includes(active.seriesKey) ? active.seriesKey : null;
964
+ const keys = activeSeriesKey ? [activeSeriesKey] : visibleKeys;
965
+ const valueKey = this.valueKey();
966
+ return {
967
+ category,
968
+ datum,
969
+ rows: keys.map((k) => {
970
+ const rawValue = valueKey != null && activeSeriesKey === k ? datum[valueKey] : datum[k];
971
+ return {
972
+ seriesKey: k,
973
+ label: cfg[k]?.label ?? k,
974
+ value: rawValue,
975
+ color: seriesColorVar(k),
976
+ icon: cfg[k]?.icon
977
+ };
978
+ })
979
+ };
980
+ }, ...ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []);
981
+ headerText(p) {
982
+ if (this.hideLabel()) return null;
983
+ const override = this.label();
984
+ const labelKey = this.labelKey();
985
+ const cfg = this.root.config();
986
+ const fromKey = labelKey ? cfg[labelKey]?.label ?? labelKey : null;
987
+ const raw = override ?? fromKey ?? p.category;
988
+ const fmt = this.labelFormatter();
989
+ return fmt ? fmt(raw, p) : raw;
990
+ }
991
+ formatRow(row, p) {
992
+ const fmt = this.formatter();
993
+ if (fmt) return fmt(row.value, row, p);
994
+ return row.value == null ? "" : String(row.value);
995
+ }
996
+ position = computed(() => {
997
+ const active = this.root.activePoint();
998
+ const box = this.containerBox();
999
+ if (!active || active.clientX == null || active.clientY == null || !box) return {
1000
+ x: 0,
1001
+ y: 0
1002
+ };
1003
+ const { width: tooltipWidth, height: tooltipHeight } = this.tooltipBox();
1004
+ const padding = 8;
1005
+ const minX = padding + tooltipWidth / 2;
1006
+ const maxX = Math.max(minX, box.width - padding - tooltipWidth / 2);
1007
+ const x = Math.min(maxX, Math.max(minX, active.clientX - box.left));
1008
+ const minY = padding + tooltipHeight;
1009
+ return {
1010
+ x,
1011
+ y: Math.max(minY, active.clientY - box.top - padding)
1012
+ };
1013
+ }, ...ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []);
1014
+ observeContainer() {
1015
+ const container = chartContainerElement(this.host.nativeElement);
1016
+ if (!container) return;
1017
+ this.measureContainer(container);
1018
+ if (typeof ResizeObserver === "undefined") return;
1019
+ const observer = new ResizeObserver(() => this.zone.run(() => this.measureContainer(container)));
1020
+ observer.observe(container);
1021
+ this.destroyRef.onDestroy(() => observer.disconnect());
1022
+ }
1023
+ measure() {
1024
+ const container = chartContainerElement(this.host.nativeElement);
1025
+ if (container) this.measureContainer(container);
1026
+ const card = this.host.nativeElement.querySelector("[role=\"tooltip\"]");
1027
+ this.tooltipBox.set({
1028
+ width: card?.offsetWidth || FALLBACK_TOOLTIP_WIDTH,
1029
+ height: card?.offsetHeight ?? 0
1030
+ });
1031
+ }
1032
+ measureContainer(container) {
1033
+ const rect = container.getBoundingClientRect();
1034
+ this.containerBox.set({
1035
+ left: rect.left,
1036
+ top: rect.top,
1037
+ width: rect.width
1038
+ });
1039
+ }
1040
+ static ɵfac = i0.ɵɵngDeclareFactory({
1041
+ minVersion: "12.0.0",
1042
+ version: "22.2.2",
1043
+ ngImport: i0,
1044
+ type: ChartTooltip,
1045
+ deps: [],
1046
+ target: i0.ɵɵFactoryTarget.Component
1047
+ });
1048
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1049
+ minVersion: "17.0.0",
1050
+ version: "22.2.2",
1051
+ type: ChartTooltip,
1052
+ isStandalone: true,
1053
+ selector: "ChartTooltip",
1054
+ inputs: {
1055
+ xKey: {
1056
+ classPropertyName: "xKey",
1057
+ publicName: "xKey",
1058
+ isSignal: true,
1059
+ isRequired: false,
1060
+ transformFunction: null
1061
+ },
1062
+ data: {
1063
+ classPropertyName: "data",
1064
+ publicName: "data",
1065
+ isSignal: true,
1066
+ isRequired: false,
1067
+ transformFunction: null
1068
+ },
1069
+ valueKey: {
1070
+ classPropertyName: "valueKey",
1071
+ publicName: "valueKey",
1072
+ isSignal: true,
1073
+ isRequired: false,
1074
+ transformFunction: null
1075
+ },
1076
+ indicator: {
1077
+ classPropertyName: "indicator",
1078
+ publicName: "indicator",
1079
+ isSignal: true,
1080
+ isRequired: false,
1081
+ transformFunction: null
1082
+ },
1083
+ hideLabel: {
1084
+ classPropertyName: "hideLabel",
1085
+ publicName: "hideLabel",
1086
+ isSignal: true,
1087
+ isRequired: false,
1088
+ transformFunction: null
1089
+ },
1090
+ label: {
1091
+ classPropertyName: "label",
1092
+ publicName: "label",
1093
+ isSignal: true,
1094
+ isRequired: false,
1095
+ transformFunction: null
1096
+ },
1097
+ labelKey: {
1098
+ classPropertyName: "labelKey",
1099
+ publicName: "labelKey",
1100
+ isSignal: true,
1101
+ isRequired: false,
1102
+ transformFunction: null
1103
+ },
1104
+ labelFormatter: {
1105
+ classPropertyName: "labelFormatter",
1106
+ publicName: "labelFormatter",
1107
+ isSignal: true,
1108
+ isRequired: false,
1109
+ transformFunction: null
1110
+ },
1111
+ formatter: {
1112
+ classPropertyName: "formatter",
1113
+ publicName: "formatter",
1114
+ isSignal: true,
1115
+ isRequired: false,
1116
+ transformFunction: null
1117
+ }
1118
+ },
1119
+ host: {
1120
+ properties: { "attr.aria-hidden": "!visible()" },
1121
+ classAttribute: "pointer-events-none absolute inset-0 z-10"
1122
+ },
1123
+ queries: [{
1124
+ propertyName: "customTpl",
1125
+ first: true,
1126
+ predicate: TemplateRef,
1127
+ descendants: true,
1128
+ isSignal: true
1129
+ }],
1130
+ ngImport: i0,
1131
+ template: `
954
1132
  @if (payload(); as p) {
955
1133
  <div
956
1134
  role="tooltip"
@@ -1012,18 +1190,48 @@ class ChartTooltip {
1012
1190
  {{ p.category }}
1013
1191
  }
1014
1192
  </div>
1015
- `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }] });
1016
- }
1017
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartTooltip, decorators: [{
1018
- type: Component,
1019
- args: [{
1020
- selector: 'ChartTooltip',
1021
- imports: [NgTemplateOutlet, NgComponentOutlet],
1022
- host: {
1023
- class: 'pointer-events-none absolute inset-0 z-10',
1024
- '[attr.aria-hidden]': '!visible()',
1025
- },
1026
- template: `
1193
+ `,
1194
+ isInline: true,
1195
+ dependencies: [{
1196
+ kind: "directive",
1197
+ type: NgTemplateOutlet,
1198
+ selector: "[ngTemplateOutlet]",
1199
+ inputs: [
1200
+ "ngTemplateOutletContext",
1201
+ "ngTemplateOutlet",
1202
+ "ngTemplateOutletInjector"
1203
+ ]
1204
+ }, {
1205
+ kind: "directive",
1206
+ type: NgComponentOutlet,
1207
+ selector: "[ngComponentOutlet]",
1208
+ inputs: [
1209
+ "ngComponentOutlet",
1210
+ "ngComponentOutletInputs",
1211
+ "ngComponentOutletInjector",
1212
+ "ngComponentOutletEnvironmentInjector",
1213
+ "ngComponentOutletContent",
1214
+ "ngComponentOutletNgModule"
1215
+ ],
1216
+ exportAs: ["ngComponentOutlet"]
1217
+ }]
1218
+ });
1219
+ };
1220
+ i0.ɵɵngDeclareClassMetadata({
1221
+ minVersion: "12.0.0",
1222
+ version: "22.2.2",
1223
+ ngImport: i0,
1224
+ type: ChartTooltip,
1225
+ decorators: [{
1226
+ type: Component,
1227
+ args: [{
1228
+ selector: "ChartTooltip",
1229
+ imports: [NgTemplateOutlet, NgComponentOutlet],
1230
+ host: {
1231
+ class: "pointer-events-none absolute inset-0 z-10",
1232
+ "[attr.aria-hidden]": "!visible()"
1233
+ },
1234
+ template: `
1027
1235
  @if (payload(); as p) {
1028
1236
  <div
1029
1237
  role="tooltip"
@@ -1085,40 +1293,121 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1085
1293
  {{ p.category }}
1086
1294
  }
1087
1295
  </div>
1088
- `,
1089
- }]
1090
- }], ctorParameters: () => [], propDecorators: { xKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "xKey", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], valueKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueKey", required: false }] }], indicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicator", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKey", required: false }] }], labelFormatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelFormatter", required: false }] }], formatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatter", required: false }] }], customTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
1091
-
1092
- /**
1093
- * Legend — renders a list of series swatches. Clicking an item toggles
1094
- * visibility via `ChartContext.toggleSeries`.
1095
- *
1096
- * Place as a child of `<Chart>`:
1097
- * ```html
1098
- * <Chart [config]="cfg">
1099
- * <ChartBar ... />
1100
- * <ChartLegend />
1101
- * </Chart>
1102
- * ```
1103
- */
1104
- class ChartLegend {
1105
- root = inject(ChartContext);
1106
- items = computed(() => {
1107
- const cfg = this.root.config();
1108
- const hidden = this.root.hiddenSeries();
1109
- return this.root.seriesKeys().map((key) => ({
1110
- seriesKey: key,
1111
- label: cfg[key]?.label ?? key,
1112
- color: seriesColorVar(key),
1113
- hidden: hidden.has(key),
1114
- }));
1115
- }, /* @ts-ignore */
1116
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1117
- toggle(key) {
1118
- this.root.toggleSeries(key);
1119
- }
1120
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
1121
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartLegend, isStandalone: true, selector: "ChartLegend", host: { classAttribute: "block pt-3" }, ngImport: i0, template: `
1296
+ `
1297
+ }]
1298
+ }],
1299
+ ctorParameters: () => [],
1300
+ propDecorators: {
1301
+ xKey: [{
1302
+ type: i0.Input,
1303
+ args: [{
1304
+ isSignal: true,
1305
+ alias: "xKey",
1306
+ required: false
1307
+ }]
1308
+ }],
1309
+ data: [{
1310
+ type: i0.Input,
1311
+ args: [{
1312
+ isSignal: true,
1313
+ alias: "data",
1314
+ required: false
1315
+ }]
1316
+ }],
1317
+ valueKey: [{
1318
+ type: i0.Input,
1319
+ args: [{
1320
+ isSignal: true,
1321
+ alias: "valueKey",
1322
+ required: false
1323
+ }]
1324
+ }],
1325
+ indicator: [{
1326
+ type: i0.Input,
1327
+ args: [{
1328
+ isSignal: true,
1329
+ alias: "indicator",
1330
+ required: false
1331
+ }]
1332
+ }],
1333
+ hideLabel: [{
1334
+ type: i0.Input,
1335
+ args: [{
1336
+ isSignal: true,
1337
+ alias: "hideLabel",
1338
+ required: false
1339
+ }]
1340
+ }],
1341
+ label: [{
1342
+ type: i0.Input,
1343
+ args: [{
1344
+ isSignal: true,
1345
+ alias: "label",
1346
+ required: false
1347
+ }]
1348
+ }],
1349
+ labelKey: [{
1350
+ type: i0.Input,
1351
+ args: [{
1352
+ isSignal: true,
1353
+ alias: "labelKey",
1354
+ required: false
1355
+ }]
1356
+ }],
1357
+ labelFormatter: [{
1358
+ type: i0.Input,
1359
+ args: [{
1360
+ isSignal: true,
1361
+ alias: "labelFormatter",
1362
+ required: false
1363
+ }]
1364
+ }],
1365
+ formatter: [{
1366
+ type: i0.Input,
1367
+ args: [{
1368
+ isSignal: true,
1369
+ alias: "formatter",
1370
+ required: false
1371
+ }]
1372
+ }],
1373
+ customTpl: [{
1374
+ type: i0.ContentChild,
1375
+ args: [i0.forwardRef(() => TemplateRef), { isSignal: true }]
1376
+ }]
1377
+ }
1378
+ });
1379
+ var ChartLegend = class ChartLegend {
1380
+ root = inject(ChartContext);
1381
+ items = computed(() => {
1382
+ const cfg = this.root.config();
1383
+ const hidden = this.root.hiddenSeries();
1384
+ return this.root.seriesKeys().map((key) => ({
1385
+ seriesKey: key,
1386
+ label: cfg[key]?.label ?? key,
1387
+ color: seriesColorVar(key),
1388
+ hidden: hidden.has(key)
1389
+ }));
1390
+ }, ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
1391
+ toggle(key) {
1392
+ this.root.toggleSeries(key);
1393
+ }
1394
+ static ɵfac = i0.ɵɵngDeclareFactory({
1395
+ minVersion: "12.0.0",
1396
+ version: "22.2.2",
1397
+ ngImport: i0,
1398
+ type: ChartLegend,
1399
+ deps: [],
1400
+ target: i0.ɵɵFactoryTarget.Component
1401
+ });
1402
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1403
+ minVersion: "17.0.0",
1404
+ version: "22.2.2",
1405
+ type: ChartLegend,
1406
+ isStandalone: true,
1407
+ selector: "ChartLegend",
1408
+ host: { classAttribute: "block pt-3" },
1409
+ ngImport: i0,
1410
+ template: `
1122
1411
  <ul
1123
1412
  class="flex flex-wrap items-center justify-center gap-3 text-xs"
1124
1413
  aria-label="Toggle chart series visibility"
@@ -1142,14 +1431,21 @@ class ChartLegend {
1142
1431
  </li>
1143
1432
  }
1144
1433
  </ul>
1145
- `, isInline: true });
1146
- }
1147
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartLegend, decorators: [{
1148
- type: Component,
1149
- args: [{
1150
- selector: 'ChartLegend',
1151
- host: { class: 'block pt-3' },
1152
- template: `
1434
+ `,
1435
+ isInline: true
1436
+ });
1437
+ };
1438
+ i0.ɵɵngDeclareClassMetadata({
1439
+ minVersion: "12.0.0",
1440
+ version: "22.2.2",
1441
+ ngImport: i0,
1442
+ type: ChartLegend,
1443
+ decorators: [{
1444
+ type: Component,
1445
+ args: [{
1446
+ selector: "ChartLegend",
1447
+ host: { class: "block pt-3" },
1448
+ template: `
1153
1449
  <ul
1154
1450
  class="flex flex-wrap items-center justify-center gap-3 text-xs"
1155
1451
  aria-label="Toggle chart series visibility"
@@ -1173,51 +1469,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1173
1469
  </li>
1174
1470
  }
1175
1471
  </ul>
1176
- `,
1177
- }]
1178
- }] });
1179
-
1472
+ `
1473
+ }]
1474
+ }]
1475
+ });
1180
1476
  function formatNumber(value) {
1181
- return Math.abs(value) >= 10 ? value.toFixed(0) : value.toFixed(1);
1477
+ return Math.abs(value) >= 10 ? value.toFixed(0) : value.toFixed(1);
1182
1478
  }
1183
- class ChartZoomControls {
1184
- categorical = inject(CategoricalViewportContext, { optional: true });
1185
- scatter = inject(ScatterViewportContext, { optional: true });
1186
- status = computed(() => {
1187
- if (this.categorical?.hasZoom()) {
1188
- const count = this.categorical.dataCount();
1189
- // The chart renders the renormalized window, so the status has to quote
1190
- // the same one; the raw range can still name rows the data no longer has.
1191
- const range = effectiveIndexRange(this.categorical.zoomRange(), count);
1192
- if (!range) {
1193
- return null;
1194
- }
1195
- return `Showing ${range.startIndex + 1}-${range.endIndex + 1} of ${count}`;
1196
- }
1197
- if (this.scatter?.hasZoom()) {
1198
- const xDomain = this.scatter.zoomXDomain() ?? this.scatter.fullXDomain();
1199
- const yDomain = this.scatter.zoomYDomain() ?? this.scatter.fullYDomain();
1200
- if (!xDomain || !yDomain) {
1201
- return null;
1202
- }
1203
- return `X ${formatNumber(xDomain[0])}-${formatNumber(xDomain[1])} · Y ${formatNumber(yDomain[0])}-${formatNumber(yDomain[1])}`;
1204
- }
1205
- return null;
1206
- }, /* @ts-ignore */
1207
- ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
1208
- hint = computed(() => {
1209
- if (this.scatter) {
1210
- return 'Drag to brush a region. Use the wheel to zoom and one-finger touch drag to pan while zoomed.';
1211
- }
1212
- return 'Drag to select a category range. Use the wheel to zoom and one-finger touch drag to pan while zoomed.';
1213
- }, /* @ts-ignore */
1214
- ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
1215
- resetZoom() {
1216
- this.categorical?.resetZoom();
1217
- this.scatter?.resetZoom();
1218
- }
1219
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartZoomControls, deps: [], target: i0.ɵɵFactoryTarget.Component });
1220
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartZoomControls, isStandalone: true, selector: "ChartZoomControls", host: { classAttribute: "mt-3 flex flex-wrap items-center justify-between gap-3 text-xs text-muted-foreground" }, ngImport: i0, template: `
1479
+ var ChartZoomControls = class ChartZoomControls {
1480
+ categorical = inject(CategoricalViewportContext, { optional: true });
1481
+ scatter = inject(ScatterViewportContext, { optional: true });
1482
+ status = computed(() => {
1483
+ if (this.categorical?.hasZoom()) {
1484
+ const count = this.categorical.dataCount();
1485
+ const range = effectiveIndexRange(this.categorical.zoomRange(), count);
1486
+ if (!range) return null;
1487
+ return `Showing ${range.startIndex + 1}-${range.endIndex + 1} of ${count}`;
1488
+ }
1489
+ if (this.scatter?.hasZoom()) {
1490
+ const xDomain = this.scatter.zoomXDomain() ?? this.scatter.fullXDomain();
1491
+ const yDomain = this.scatter.zoomYDomain() ?? this.scatter.fullYDomain();
1492
+ if (!xDomain || !yDomain) return null;
1493
+ return `X ${formatNumber(xDomain[0])}-${formatNumber(xDomain[1])} · Y ${formatNumber(yDomain[0])}-${formatNumber(yDomain[1])}`;
1494
+ }
1495
+ return null;
1496
+ }, ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
1497
+ hint = computed(() => {
1498
+ if (this.scatter) return "Drag to brush a region. Use the wheel to zoom and one-finger touch drag to pan while zoomed.";
1499
+ return "Drag to select a category range. Use the wheel to zoom and one-finger touch drag to pan while zoomed.";
1500
+ }, ...ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []);
1501
+ resetZoom() {
1502
+ this.categorical?.resetZoom();
1503
+ this.scatter?.resetZoom();
1504
+ }
1505
+ static ɵfac = i0.ɵɵngDeclareFactory({
1506
+ minVersion: "12.0.0",
1507
+ version: "22.2.2",
1508
+ ngImport: i0,
1509
+ type: ChartZoomControls,
1510
+ deps: [],
1511
+ target: i0.ɵɵFactoryTarget.Component
1512
+ });
1513
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1514
+ minVersion: "17.0.0",
1515
+ version: "22.2.2",
1516
+ type: ChartZoomControls,
1517
+ isStandalone: true,
1518
+ selector: "ChartZoomControls",
1519
+ host: { classAttribute: "mt-3 flex flex-wrap items-center justify-between gap-3 text-xs text-muted-foreground" },
1520
+ ngImport: i0,
1521
+ template: `
1221
1522
  <p>{{ hint() }}</p>
1222
1523
 
1223
1524
  @if (status(); as currentStatus) {
@@ -1236,16 +1537,21 @@ class ChartZoomControls {
1236
1537
  </button>
1237
1538
  </div>
1238
1539
  }
1239
- `, isInline: true });
1240
- }
1241
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartZoomControls, decorators: [{
1242
- type: Component,
1243
- args: [{
1244
- selector: 'ChartZoomControls',
1245
- host: {
1246
- class: 'mt-3 flex flex-wrap items-center justify-between gap-3 text-xs text-muted-foreground',
1247
- },
1248
- template: `
1540
+ `,
1541
+ isInline: true
1542
+ });
1543
+ };
1544
+ i0.ɵɵngDeclareClassMetadata({
1545
+ minVersion: "12.0.0",
1546
+ version: "22.2.2",
1547
+ ngImport: i0,
1548
+ type: ChartZoomControls,
1549
+ decorators: [{
1550
+ type: Component,
1551
+ args: [{
1552
+ selector: "ChartZoomControls",
1553
+ host: { class: "mt-3 flex flex-wrap items-center justify-between gap-3 text-xs text-muted-foreground" },
1554
+ template: `
1249
1555
  <p>{{ hint() }}</p>
1250
1556
 
1251
1557
  @if (status(); as currentStatus) {
@@ -1264,42 +1570,78 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1264
1570
  </button>
1265
1571
  </div>
1266
1572
  }
1267
- `,
1268
- }]
1269
- }] });
1270
-
1271
- class PieCenter {
1272
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: PieCenter, deps: [], target: i0.ɵɵFactoryTarget.Component });
1273
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: PieCenter, isStandalone: true, selector: "ChartPieCenter", host: { classAttribute: "flex max-w-40 flex-col items-center justify-center text-center" }, ngImport: i0, template: `<ng-content />`, isInline: true });
1274
- }
1275
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: PieCenter, decorators: [{
1276
- type: Component,
1277
- args: [{
1278
- selector: 'ChartPieCenter',
1279
- host: {
1280
- class: 'flex max-w-40 flex-col items-center justify-center text-center',
1281
- },
1282
- template: `<ng-content />`,
1283
- }]
1284
- }] });
1285
-
1286
- class RadialCenter {
1287
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RadialCenter, deps: [], target: i0.ɵɵFactoryTarget.Component });
1288
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: RadialCenter, isStandalone: true, selector: "ChartRadialCenter", host: { classAttribute: "flex max-w-40 flex-col items-center justify-center text-center" }, ngImport: i0, template: `<ng-content />`, isInline: true });
1289
- }
1290
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: RadialCenter, decorators: [{
1291
- type: Component,
1292
- args: [{
1293
- selector: 'ChartRadialCenter',
1294
- host: {
1295
- class: 'flex max-w-40 flex-col items-center justify-center text-center',
1296
- },
1297
- template: `<ng-content />`,
1298
- }]
1299
- }] });
1300
-
1301
- /**
1302
- * Generated bundle index. Do not edit.
1303
- */
1304
-
1305
- export { ChartAxisX, ChartAxisY, ChartBrush, ChartCrosshair, ChartGrid, ChartLegend, ChartPointerTracker, ChartTooltip, ChartZoomControls, PieCenter, RadialCenter };
1573
+ `
1574
+ }]
1575
+ }]
1576
+ });
1577
+ var PieCenter = class PieCenter {
1578
+ static ɵfac = i0.ɵɵngDeclareFactory({
1579
+ minVersion: "12.0.0",
1580
+ version: "22.2.2",
1581
+ ngImport: i0,
1582
+ type: PieCenter,
1583
+ deps: [],
1584
+ target: i0.ɵɵFactoryTarget.Component
1585
+ });
1586
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1587
+ minVersion: "14.0.0",
1588
+ version: "22.2.2",
1589
+ type: PieCenter,
1590
+ isStandalone: true,
1591
+ selector: "ChartPieCenter",
1592
+ host: { classAttribute: "flex max-w-40 flex-col items-center justify-center text-center" },
1593
+ ngImport: i0,
1594
+ template: `<ng-content />`,
1595
+ isInline: true
1596
+ });
1597
+ };
1598
+ i0.ɵɵngDeclareClassMetadata({
1599
+ minVersion: "12.0.0",
1600
+ version: "22.2.2",
1601
+ ngImport: i0,
1602
+ type: PieCenter,
1603
+ decorators: [{
1604
+ type: Component,
1605
+ args: [{
1606
+ selector: "ChartPieCenter",
1607
+ host: { class: "flex max-w-40 flex-col items-center justify-center text-center" },
1608
+ template: `<ng-content />`
1609
+ }]
1610
+ }]
1611
+ });
1612
+ var RadialCenter = class RadialCenter {
1613
+ static ɵfac = i0.ɵɵngDeclareFactory({
1614
+ minVersion: "12.0.0",
1615
+ version: "22.2.2",
1616
+ ngImport: i0,
1617
+ type: RadialCenter,
1618
+ deps: [],
1619
+ target: i0.ɵɵFactoryTarget.Component
1620
+ });
1621
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1622
+ minVersion: "14.0.0",
1623
+ version: "22.2.2",
1624
+ type: RadialCenter,
1625
+ isStandalone: true,
1626
+ selector: "ChartRadialCenter",
1627
+ host: { classAttribute: "flex max-w-40 flex-col items-center justify-center text-center" },
1628
+ ngImport: i0,
1629
+ template: `<ng-content />`,
1630
+ isInline: true
1631
+ });
1632
+ };
1633
+ i0.ɵɵngDeclareClassMetadata({
1634
+ minVersion: "12.0.0",
1635
+ version: "22.2.2",
1636
+ ngImport: i0,
1637
+ type: RadialCenter,
1638
+ decorators: [{
1639
+ type: Component,
1640
+ args: [{
1641
+ selector: "ChartRadialCenter",
1642
+ host: { class: "flex max-w-40 flex-col items-center justify-center text-center" },
1643
+ template: `<ng-content />`
1644
+ }]
1645
+ }]
1646
+ });
1647
+ export { ChartAxisX, ChartAxisY, ChartBrush, ChartCrosshair, ChartGrid, ChartLegend, ChartPointerTracker, ChartTooltip, ChartZoomControls, PieCenter, RadialCenter };