@star-ng/ui 0.0.0-placeholder.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -3
  3. package/fesm2022/star-ng-ui-accordion.mjs +376 -0
  4. package/fesm2022/star-ng-ui-accordion.mjs.map +1 -0
  5. package/fesm2022/star-ng-ui-autocomplete.mjs +782 -0
  6. package/fesm2022/star-ng-ui-autocomplete.mjs.map +1 -0
  7. package/fesm2022/star-ng-ui-avatar.mjs +154 -0
  8. package/fesm2022/star-ng-ui-avatar.mjs.map +1 -0
  9. package/fesm2022/star-ng-ui-badge.mjs +153 -0
  10. package/fesm2022/star-ng-ui-badge.mjs.map +1 -0
  11. package/fesm2022/star-ng-ui-breadcrumb.mjs +199 -0
  12. package/fesm2022/star-ng-ui-breadcrumb.mjs.map +1 -0
  13. package/fesm2022/star-ng-ui-button.mjs +282 -0
  14. package/fesm2022/star-ng-ui-button.mjs.map +1 -0
  15. package/fesm2022/star-ng-ui-card.mjs +112 -0
  16. package/fesm2022/star-ng-ui-card.mjs.map +1 -0
  17. package/fesm2022/star-ng-ui-chart.mjs +1904 -0
  18. package/fesm2022/star-ng-ui-chart.mjs.map +1 -0
  19. package/fesm2022/star-ng-ui-checkbox.mjs +345 -0
  20. package/fesm2022/star-ng-ui-checkbox.mjs.map +1 -0
  21. package/fesm2022/star-ng-ui-core.mjs +392 -0
  22. package/fesm2022/star-ng-ui-core.mjs.map +1 -0
  23. package/fesm2022/star-ng-ui-data-display.mjs +1556 -0
  24. package/fesm2022/star-ng-ui-data-display.mjs.map +1 -0
  25. package/fesm2022/star-ng-ui-date-picker.mjs +2786 -0
  26. package/fesm2022/star-ng-ui-date-picker.mjs.map +1 -0
  27. package/fesm2022/star-ng-ui-dialog.mjs +948 -0
  28. package/fesm2022/star-ng-ui-dialog.mjs.map +1 -0
  29. package/fesm2022/star-ng-ui-drawer.mjs +158 -0
  30. package/fesm2022/star-ng-ui-drawer.mjs.map +1 -0
  31. package/fesm2022/star-ng-ui-editor.mjs +416 -0
  32. package/fesm2022/star-ng-ui-editor.mjs.map +1 -0
  33. package/fesm2022/star-ng-ui-field.mjs +378 -0
  34. package/fesm2022/star-ng-ui-field.mjs.map +1 -0
  35. package/fesm2022/star-ng-ui-file-upload.mjs +762 -0
  36. package/fesm2022/star-ng-ui-file-upload.mjs.map +1 -0
  37. package/fesm2022/star-ng-ui-i18n-de.mjs +179 -0
  38. package/fesm2022/star-ng-ui-i18n-de.mjs.map +1 -0
  39. package/fesm2022/star-ng-ui-i18n-es.mjs +179 -0
  40. package/fesm2022/star-ng-ui-i18n-es.mjs.map +1 -0
  41. package/fesm2022/star-ng-ui-input-group.mjs +188 -0
  42. package/fesm2022/star-ng-ui-input-group.mjs.map +1 -0
  43. package/fesm2022/star-ng-ui-input-mask.mjs +434 -0
  44. package/fesm2022/star-ng-ui-input-mask.mjs.map +1 -0
  45. package/fesm2022/star-ng-ui-input-number.mjs +691 -0
  46. package/fesm2022/star-ng-ui-input-number.mjs.map +1 -0
  47. package/fesm2022/star-ng-ui-input-otp.mjs +343 -0
  48. package/fesm2022/star-ng-ui-input-otp.mjs.map +1 -0
  49. package/fesm2022/star-ng-ui-input-tags.mjs +616 -0
  50. package/fesm2022/star-ng-ui-input-tags.mjs.map +1 -0
  51. package/fesm2022/star-ng-ui-knob.mjs +514 -0
  52. package/fesm2022/star-ng-ui-knob.mjs.map +1 -0
  53. package/fesm2022/star-ng-ui-layout.mjs +608 -0
  54. package/fesm2022/star-ng-ui-layout.mjs.map +1 -0
  55. package/fesm2022/star-ng-ui-listbox.mjs +978 -0
  56. package/fesm2022/star-ng-ui-listbox.mjs.map +1 -0
  57. package/fesm2022/star-ng-ui-media.mjs +833 -0
  58. package/fesm2022/star-ng-ui-media.mjs.map +1 -0
  59. package/fesm2022/star-ng-ui-menu.mjs +1840 -0
  60. package/fesm2022/star-ng-ui-menu.mjs.map +1 -0
  61. package/fesm2022/star-ng-ui-message.mjs +191 -0
  62. package/fesm2022/star-ng-ui-message.mjs.map +1 -0
  63. package/fesm2022/star-ng-ui-paginator.mjs +387 -0
  64. package/fesm2022/star-ng-ui-paginator.mjs.map +1 -0
  65. package/fesm2022/star-ng-ui-panel.mjs +324 -0
  66. package/fesm2022/star-ng-ui-panel.mjs.map +1 -0
  67. package/fesm2022/star-ng-ui-password.mjs +517 -0
  68. package/fesm2022/star-ng-ui-password.mjs.map +1 -0
  69. package/fesm2022/star-ng-ui-popover.mjs +241 -0
  70. package/fesm2022/star-ng-ui-popover.mjs.map +1 -0
  71. package/fesm2022/star-ng-ui-progress-bar.mjs +183 -0
  72. package/fesm2022/star-ng-ui-progress-bar.mjs.map +1 -0
  73. package/fesm2022/star-ng-ui-radio.mjs +411 -0
  74. package/fesm2022/star-ng-ui-radio.mjs.map +1 -0
  75. package/fesm2022/star-ng-ui-rating.mjs +211 -0
  76. package/fesm2022/star-ng-ui-rating.mjs.map +1 -0
  77. package/fesm2022/star-ng-ui-select-button.mjs +613 -0
  78. package/fesm2022/star-ng-ui-select-button.mjs.map +1 -0
  79. package/fesm2022/star-ng-ui-select.mjs +2523 -0
  80. package/fesm2022/star-ng-ui-select.mjs.map +1 -0
  81. package/fesm2022/star-ng-ui-skeleton.mjs +160 -0
  82. package/fesm2022/star-ng-ui-skeleton.mjs.map +1 -0
  83. package/fesm2022/star-ng-ui-slider.mjs +552 -0
  84. package/fesm2022/star-ng-ui-slider.mjs.map +1 -0
  85. package/fesm2022/star-ng-ui-spinner.mjs +148 -0
  86. package/fesm2022/star-ng-ui-spinner.mjs.map +1 -0
  87. package/fesm2022/star-ng-ui-stepper.mjs +360 -0
  88. package/fesm2022/star-ng-ui-stepper.mjs.map +1 -0
  89. package/fesm2022/star-ng-ui-table.mjs +3477 -0
  90. package/fesm2022/star-ng-ui-table.mjs.map +1 -0
  91. package/fesm2022/star-ng-ui-tabs.mjs +464 -0
  92. package/fesm2022/star-ng-ui-tabs.mjs.map +1 -0
  93. package/fesm2022/star-ng-ui-tag.mjs +129 -0
  94. package/fesm2022/star-ng-ui-tag.mjs.map +1 -0
  95. package/fesm2022/star-ng-ui-theme-switch.mjs +105 -0
  96. package/fesm2022/star-ng-ui-theme-switch.mjs.map +1 -0
  97. package/fesm2022/star-ng-ui-theme.mjs +98 -0
  98. package/fesm2022/star-ng-ui-theme.mjs.map +1 -0
  99. package/fesm2022/star-ng-ui-toast.mjs +298 -0
  100. package/fesm2022/star-ng-ui-toast.mjs.map +1 -0
  101. package/fesm2022/star-ng-ui-toggle-switch.mjs +316 -0
  102. package/fesm2022/star-ng-ui-toggle-switch.mjs.map +1 -0
  103. package/fesm2022/star-ng-ui-tooltip.mjs +297 -0
  104. package/fesm2022/star-ng-ui-tooltip.mjs.map +1 -0
  105. package/fesm2022/star-ng-ui-transloco.mjs +40 -0
  106. package/fesm2022/star-ng-ui-transloco.mjs.map +1 -0
  107. package/fesm2022/star-ng-ui-tree.mjs +1446 -0
  108. package/fesm2022/star-ng-ui-tree.mjs.map +1 -0
  109. package/fesm2022/star-ng-ui-utility.mjs +2134 -0
  110. package/fesm2022/star-ng-ui-utility.mjs.map +1 -0
  111. package/fesm2022/star-ng-ui.mjs +51 -0
  112. package/package.json +281 -5
  113. package/styles/_base.scss +70 -0
  114. package/styles/_shared.scss +2 -0
  115. package/styles/_tokens.scss +190 -0
  116. package/styles/controls/_accordion.scss +75 -0
  117. package/styles/controls/_autocomplete.scss +44 -0
  118. package/styles/controls/_avatar.scss +39 -0
  119. package/styles/controls/_breadcrumb.scss +45 -0
  120. package/styles/controls/_button.scss +137 -0
  121. package/styles/controls/_card.scss +38 -0
  122. package/styles/controls/_chart.scss +214 -0
  123. package/styles/controls/_chip.scss +51 -0
  124. package/styles/controls/_choice.scss +153 -0
  125. package/styles/controls/_data-display.scss +118 -0
  126. package/styles/controls/_date-picker.scss +300 -0
  127. package/styles/controls/_dialog.scss +123 -0
  128. package/styles/controls/_drawer.scss +118 -0
  129. package/styles/controls/_editor.scss +74 -0
  130. package/styles/controls/_field.scss +92 -0
  131. package/styles/controls/_file-upload.scss +136 -0
  132. package/styles/controls/_input-group.scss +104 -0
  133. package/styles/controls/_input-mask.scss +46 -0
  134. package/styles/controls/_input-number.scss +125 -0
  135. package/styles/controls/_knob.scss +76 -0
  136. package/styles/controls/_layout.scss +182 -0
  137. package/styles/controls/_listbox.scss +38 -0
  138. package/styles/controls/_media.scss +222 -0
  139. package/styles/controls/_menu.scss +254 -0
  140. package/styles/controls/_message.scss +48 -0
  141. package/styles/controls/_org-chart.scss +128 -0
  142. package/styles/controls/_paginator.scss +59 -0
  143. package/styles/controls/_panel.scss +83 -0
  144. package/styles/controls/_popover.scss +40 -0
  145. package/styles/controls/_progress-bar.scss +74 -0
  146. package/styles/controls/_select-button.scss +61 -0
  147. package/styles/controls/_select.scss +216 -0
  148. package/styles/controls/_skeleton.scss +43 -0
  149. package/styles/controls/_slider.scss +163 -0
  150. package/styles/controls/_spinner.scss +34 -0
  151. package/styles/controls/_stepper.scss +109 -0
  152. package/styles/controls/_table.scss +523 -0
  153. package/styles/controls/_tabs.scss +93 -0
  154. package/styles/controls/_tag.scss +84 -0
  155. package/styles/controls/_toast.scss +141 -0
  156. package/styles/controls/_tooltip.scss +14 -0
  157. package/styles/controls/_tree.scss +113 -0
  158. package/styles/controls/_utility.scss +654 -0
  159. package/styles/star-ng.css +5803 -0
  160. package/styles/star-ng.min.css +1 -0
  161. package/styles/star-ng.scss +50 -0
  162. package/theme/star-theme-first-paint.js +1 -0
  163. package/types/star-ng-ui-accordion.d.ts +82 -0
  164. package/types/star-ng-ui-autocomplete.d.ts +171 -0
  165. package/types/star-ng-ui-avatar.d.ts +43 -0
  166. package/types/star-ng-ui-badge.d.ts +46 -0
  167. package/types/star-ng-ui-breadcrumb.d.ts +39 -0
  168. package/types/star-ng-ui-button.d.ts +79 -0
  169. package/types/star-ng-ui-card.d.ts +29 -0
  170. package/types/star-ng-ui-chart.d.ts +337 -0
  171. package/types/star-ng-ui-checkbox.d.ts +92 -0
  172. package/types/star-ng-ui-core.d.ts +310 -0
  173. package/types/star-ng-ui-data-display.d.ts +339 -0
  174. package/types/star-ng-ui-date-picker.d.ts +701 -0
  175. package/types/star-ng-ui-dialog.d.ts +254 -0
  176. package/types/star-ng-ui-drawer.d.ts +29 -0
  177. package/types/star-ng-ui-editor.d.ts +96 -0
  178. package/types/star-ng-ui-field.d.ts +146 -0
  179. package/types/star-ng-ui-file-upload.d.ts +192 -0
  180. package/types/star-ng-ui-i18n-de.d.ts +7 -0
  181. package/types/star-ng-ui-i18n-es.d.ts +7 -0
  182. package/types/star-ng-ui-input-group.d.ts +58 -0
  183. package/types/star-ng-ui-input-mask.d.ts +126 -0
  184. package/types/star-ng-ui-input-number.d.ts +193 -0
  185. package/types/star-ng-ui-input-otp.d.ts +86 -0
  186. package/types/star-ng-ui-input-tags.d.ts +159 -0
  187. package/types/star-ng-ui-knob.d.ts +121 -0
  188. package/types/star-ng-ui-layout.d.ts +154 -0
  189. package/types/star-ng-ui-listbox.d.ts +197 -0
  190. package/types/star-ng-ui-media.d.ts +161 -0
  191. package/types/star-ng-ui-menu.d.ts +332 -0
  192. package/types/star-ng-ui-message.d.ts +52 -0
  193. package/types/star-ng-ui-paginator.d.ts +85 -0
  194. package/types/star-ng-ui-panel.d.ts +65 -0
  195. package/types/star-ng-ui-password.d.ts +129 -0
  196. package/types/star-ng-ui-popover.d.ts +57 -0
  197. package/types/star-ng-ui-progress-bar.d.ts +49 -0
  198. package/types/star-ng-ui-radio.d.ts +116 -0
  199. package/types/star-ng-ui-rating.d.ts +52 -0
  200. package/types/star-ng-ui-select-button.d.ts +169 -0
  201. package/types/star-ng-ui-select.d.ts +540 -0
  202. package/types/star-ng-ui-skeleton.d.ts +47 -0
  203. package/types/star-ng-ui-slider.d.ts +145 -0
  204. package/types/star-ng-ui-spinner.d.ts +29 -0
  205. package/types/star-ng-ui-stepper.d.ts +89 -0
  206. package/types/star-ng-ui-table.d.ts +829 -0
  207. package/types/star-ng-ui-tabs.d.ts +109 -0
  208. package/types/star-ng-ui-tag.d.ts +35 -0
  209. package/types/star-ng-ui-theme-switch.d.ts +36 -0
  210. package/types/star-ng-ui-theme.d.ts +95 -0
  211. package/types/star-ng-ui-toast.d.ts +84 -0
  212. package/types/star-ng-ui-toggle-switch.d.ts +81 -0
  213. package/types/star-ng-ui-tooltip.d.ts +66 -0
  214. package/types/star-ng-ui-transloco.d.ts +14 -0
  215. package/types/star-ng-ui-tree.d.ts +310 -0
  216. package/types/star-ng-ui-utility.d.ts +533 -0
  217. package/types/star-ng-ui.d.ts +51 -0
@@ -0,0 +1,1904 @@
1
+ import { _IdGenerator } from "@angular/cdk/a11y";
2
+ import * as i0 from "@angular/core";
3
+ import { ChangeDetectionStrategy, Component, booleanAttribute, computed, inject, input, linkedSignal, signal } from "@angular/core";
4
+ import { STAR_UI_TEXT } from "@star-ng/ui/core";
5
+ const LIMIT = 1e300;
6
+ const TWO_PI = Math.PI * 2;
7
+ function toFinite(value, fallback = 0) {
8
+ if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
9
+ return Math.max(-1e300, Math.min(LIMIT, value));
10
+ }
11
+ function clean(value, step) {
12
+ const decimals = Math.min(100, Math.max(0, 2 - Math.floor(Math.log10(Math.abs(step) || 1))));
13
+ const rounded = +value.toFixed(decimals);
14
+ return rounded === 0 ? 0 : rounded;
15
+ }
16
+ function niceScale(min, max, options = {}) {
17
+ let lo = toFinite(min);
18
+ let hi = toFinite(max);
19
+ if (lo > hi) [lo, hi] = [hi, lo];
20
+ if (options.includeZero) {
21
+ lo = Math.min(lo, 0);
22
+ hi = Math.max(hi, 0);
23
+ }
24
+ if (lo === hi) {
25
+ if (lo === 0) hi = 1;
26
+ else {
27
+ const pad = Math.abs(lo) * .1;
28
+ lo -= pad;
29
+ hi += pad;
30
+ }
31
+ }
32
+ const intervals = Math.max(1, Math.round(options.intervals ?? 4));
33
+ const rough = (hi - lo) / intervals;
34
+ if (!(rough > 0) || !Number.isFinite(rough)) return fallbackScale(lo, hi);
35
+ const power = 10 ** Math.floor(Math.log10(rough));
36
+ const step = [
37
+ 1,
38
+ 2,
39
+ 2.5,
40
+ 5,
41
+ 10
42
+ ].map((m) => m * power).find((s) => s >= rough * (1 - 1e-12));
43
+ const first = Math.floor(lo / step + 1e-9) * step;
44
+ const last = Math.ceil(hi / step - 1e-9) * step;
45
+ const count = Math.round((last - first) / step);
46
+ if (!Number.isFinite(count) || count < 1 || count > 24) return fallbackScale(lo, hi);
47
+ const ticks = Array.from({ length: count + 1 }, (_, i) => clean(first + i * step, step));
48
+ return {
49
+ min: ticks[0],
50
+ max: ticks[count],
51
+ step,
52
+ ticks
53
+ };
54
+ }
55
+ function fallbackScale(lo, hi) {
56
+ return {
57
+ min: lo,
58
+ max: hi,
59
+ step: hi - lo,
60
+ ticks: lo === hi ? [lo] : [lo, hi]
61
+ };
62
+ }
63
+ function scalePosition(value, scale, from, to) {
64
+ const span = scale.max - scale.min;
65
+ if (!(span > 0)) return from;
66
+ return from + (toFinite(value) - scale.min) / span * (to - from);
67
+ }
68
+ function tickDecimals(ticks) {
69
+ for (let digits = 0; digits <= 10; digits++) {
70
+ const factor = 10 ** digits;
71
+ if (ticks.every((t) => Math.abs(t * factor - Math.round(t * factor)) < 1e-6)) return digits;
72
+ }
73
+ return 10;
74
+ }
75
+ function stackColumns(series, categories, percent = false) {
76
+ return Array.from({ length: Math.max(0, categories) }, (_, i) => {
77
+ const values = series.map((s) => toFinite(s[i]));
78
+ const absolute = values.reduce((sum, v) => sum + Math.abs(v), 0);
79
+ const factor = percent ? absolute > 0 ? 100 / absolute : 0 : 1;
80
+ let up = 0;
81
+ let down = 0;
82
+ const segments = values.map((value, s) => {
83
+ const size = value * factor;
84
+ if (value >= 0) {
85
+ const start = up;
86
+ up += size;
87
+ return {
88
+ series: s,
89
+ value,
90
+ start,
91
+ end: up
92
+ };
93
+ }
94
+ const start = down;
95
+ down += size;
96
+ return {
97
+ series: s,
98
+ value,
99
+ start,
100
+ end: down
101
+ };
102
+ });
103
+ const positive = values.filter((v) => v > 0).reduce((a, b) => a + b, 0);
104
+ const negative = values.filter((v) => v < 0).reduce((a, b) => a + b, 0);
105
+ return {
106
+ segments,
107
+ positive,
108
+ negative,
109
+ total: positive + negative
110
+ };
111
+ });
112
+ }
113
+ function stackExtent(columns) {
114
+ let min = 0;
115
+ let max = 0;
116
+ for (const column of columns) for (const segment of column.segments) {
117
+ min = Math.min(min, segment.start, segment.end);
118
+ max = Math.max(max, segment.start, segment.end);
119
+ }
120
+ return {
121
+ min,
122
+ max
123
+ };
124
+ }
125
+ function n(value) {
126
+ return +value.toFixed(2);
127
+ }
128
+ function polarPoint(radius, angle, cx = 0, cy = 0) {
129
+ return {
130
+ x: cx + radius * Math.cos(angle),
131
+ y: cy + radius * Math.sin(angle)
132
+ };
133
+ }
134
+ function axisAngles(count, start = -Math.PI / 2) {
135
+ const total = Math.max(0, Math.floor(count));
136
+ return Array.from({ length: total }, (_, i) => start + i * TWO_PI / total);
137
+ }
138
+ function polygonPath(points) {
139
+ if (!points.length) return "";
140
+ return points.map((p, i) => `${i ? "L" : "M"}${n(p.x)},${n(p.y)}`).join("") + "Z";
141
+ }
142
+ function circlePath(radius) {
143
+ const r = n(Math.max(0, radius));
144
+ return r ? `M${-r},0A${r},${r} 0 1 1 ${r},0A${r},${r} 0 1 1 ${-r},0Z` : "";
145
+ }
146
+ function ringPath(angles, radius) {
147
+ if (!(radius > 0)) return "";
148
+ return angles.length >= 3 ? polygonPath(angles.map((a) => polarPoint(radius, a))) : circlePath(radius);
149
+ }
150
+ function sectorPath(inner, outer, a0, a1) {
151
+ const sweep = a1 - a0;
152
+ const ro = Math.max(0, outer);
153
+ const ri = Math.max(0, Math.min(inner, ro));
154
+ if (!(ro > 0) || !(sweep > 0) || ro === ri) return "";
155
+ if (sweep >= TWO_PI - 1e-6) {
156
+ const disc = `M0,${-n(ro)}A${n(ro)},${n(ro)} 0 1 1 -0.01,${-n(ro)}Z`;
157
+ return ri > 0 ? `${disc}M0,${-n(ri)}A${n(ri)},${n(ri)} 0 1 0 0.01,${-n(ri)}Z` : disc;
158
+ }
159
+ const large = sweep > Math.PI ? 1 : 0;
160
+ const p = (r, a) => {
161
+ const { x, y } = polarPoint(r, a);
162
+ return `${n(x)},${n(y)}`;
163
+ };
164
+ return ri > 0 ? `M${p(ro, a0)}A${n(ro)},${n(ro)} 0 ${large} 1 ${p(ro, a1)}L${p(ri, a1)}A${n(ri)},${n(ri)} 0 ${large} 0 ${p(ri, a0)}Z` : `M0,0L${p(ro, a0)}A${n(ro)},${n(ro)} 0 ${large} 1 ${p(ro, a1)}Z`;
165
+ }
166
+ function linearRadius(value, scale, radius) {
167
+ const span = scale.max - scale.min;
168
+ if (!(span > 0)) return 0;
169
+ return Math.max(0, Math.min(radius, (toFinite(value) - scale.min) / span * radius));
170
+ }
171
+ function areaRadius(value, max, radius) {
172
+ const v = Math.max(0, toFinite(value));
173
+ if (!(max > 0) || v === 0) return 0;
174
+ return radius * Math.sqrt(Math.min(1, v / max));
175
+ }
176
+ function polarSectors(values, max, radius) {
177
+ const angles = axisAngles(values.length);
178
+ const half = values.length ? Math.PI / values.length : 0;
179
+ return values.map((raw, index) => {
180
+ const value = Math.max(0, toFinite(raw));
181
+ const mid = angles[index];
182
+ return {
183
+ index,
184
+ value,
185
+ radius: areaRadius(value, max, radius),
186
+ start: mid - half,
187
+ end: mid + half,
188
+ mid
189
+ };
190
+ });
191
+ }
192
+ function truncateLabel(label, max) {
193
+ const chars = Array.from(String(label ?? ""));
194
+ const limit = Math.floor(max);
195
+ if (chars.length <= limit) return chars.join("");
196
+ if (limit < 1) return "";
197
+ return chars.slice(0, limit - 1).join("").trimEnd() + "…";
198
+ }
199
+ function labelAnchor(angle) {
200
+ const cos = Math.cos(angle);
201
+ return cos > .3 ? "start" : cos < -.3 ? "end" : "middle";
202
+ }
203
+ function labelOffset(angle) {
204
+ const sin = Math.sin(angle);
205
+ return sin < -.3 ? "0" : sin > .3 ? "0.9em" : "0.35em";
206
+ }
207
+ function cleanPoints(points) {
208
+ const result = [];
209
+ points.forEach((point, index) => {
210
+ if (!point) return;
211
+ const { x, y } = point;
212
+ if (typeof x === "number" && Number.isFinite(x) && typeof y === "number" && Number.isFinite(y)) result.push({
213
+ x: toFinite(x),
214
+ y: toFinite(y),
215
+ index
216
+ });
217
+ });
218
+ return result;
219
+ }
220
+ function scatterScales(points) {
221
+ if (!points.length) return {
222
+ x: niceScale(0, 1),
223
+ y: niceScale(0, 1)
224
+ };
225
+ const xs = points.map((p) => p.x);
226
+ const ys = points.map((p) => p.y);
227
+ return {
228
+ x: niceScale(Math.min(...xs), Math.max(...xs)),
229
+ y: niceScale(Math.min(...ys), Math.max(...ys))
230
+ };
231
+ }
232
+ function markerPath(index, cx, cy, radius) {
233
+ const r = Math.max(0, radius);
234
+ const at = (dx, dy) => ({
235
+ x: cx + dx * r,
236
+ y: cy + dy * r
237
+ });
238
+ switch ((Math.floor(index) % 8 + 8) % 8) {
239
+ case 0: return `M${n(cx - r)},${n(cy)}A${n(r)},${n(r)} 0 1 0 ${n(cx + r)},${n(cy)}A${n(r)},${n(r)} 0 1 0 ${n(cx - r)},${n(cy)}Z`;
240
+ case 1: return polygonPath([
241
+ at(-.88, -.88),
242
+ at(.88, -.88),
243
+ at(.88, .88),
244
+ at(-.88, .88)
245
+ ]);
246
+ case 2: return polygonPath([
247
+ at(0, -1.25),
248
+ at(1.25, 0),
249
+ at(0, 1.25),
250
+ at(-1.25, 0)
251
+ ]);
252
+ case 3: return polygonPath([
253
+ at(0, -1.2),
254
+ at(1.1, .85),
255
+ at(-1.1, .85)
256
+ ]);
257
+ case 4: return polygonPath([
258
+ at(0, 1.2),
259
+ at(1.1, -.85),
260
+ at(-1.1, -.85)
261
+ ]);
262
+ case 5: return polygonPath(plus(at, 0));
263
+ case 6: return polygonPath(plus(at, Math.PI / 4));
264
+ default: return polygonPath(axisAngles(5).map((a) => polarPoint(1.15 * r, a, cx, cy)));
265
+ }
266
+ }
267
+ function plus(at, turn) {
268
+ const a = 1.2;
269
+ const b = .4;
270
+ const outline = [
271
+ [-.4, -1.2],
272
+ [b, -1.2],
273
+ [b, -.4],
274
+ [a, -.4],
275
+ [a, b],
276
+ [b, b],
277
+ [b, a],
278
+ [-.4, a],
279
+ [-.4, b],
280
+ [-1.2, b],
281
+ [-1.2, -.4],
282
+ [-.4, -.4]
283
+ ];
284
+ const cos = Math.cos(turn);
285
+ const sin = Math.sin(turn);
286
+ return outline.map(([x, y]) => at(x * cos - y * sin, x * sin + y * cos));
287
+ }
288
+ const STAR_CHART_SLOTS = 8;
289
+ const DOUGHNUT_SLOTS = 4;
290
+ const W = 640;
291
+ const H = 280;
292
+ const PAD = {
293
+ top: 16,
294
+ right: 16,
295
+ bottom: 36,
296
+ left: 48
297
+ };
298
+ const SCATTER_PAD = {
299
+ top: 24,
300
+ right: 20,
301
+ bottom: 44,
302
+ left: 56
303
+ };
304
+ const RADIAL_W = 520;
305
+ const RADIAL_H = 300;
306
+ const RADIAL = 105;
307
+ const RADIAL_LABEL_CHARS = 18;
308
+ const MARKER_RADIUS = 5;
309
+ function valueOf(element) {
310
+ return element !== null && typeof element === "object" ? element.y : element;
311
+ }
312
+ function extentOf(values) {
313
+ let min = 1e400;
314
+ let max = -1e400;
315
+ for (const raw of values) {
316
+ const v = toFinite(raw, NaN);
317
+ if (v < min) min = v;
318
+ if (v > max) max = v;
319
+ }
320
+ return min <= max ? {
321
+ min,
322
+ max
323
+ } : {
324
+ min: 0,
325
+ max: 0
326
+ };
327
+ }
328
+ var StarChart = class StarChart {
329
+ text = inject(STAR_UI_TEXT);
330
+ W = W;
331
+ H = H;
332
+ RW = RADIAL_W;
333
+ RH = RADIAL_H;
334
+ PAD = PAD;
335
+ SP = SCATTER_PAD;
336
+ ids = inject(_IdGenerator);
337
+ titleId = this.ids.getId("star-chart-");
338
+ descriptionId = this.ids.getId("star-chart-description-");
339
+ type = input("bar", ...ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []);
340
+ percent = input(false, {
341
+ ...ngDevMode ? { debugName: "percent" } : /* istanbul ignore next */ {},
342
+ transform: booleanAttribute
343
+ });
344
+ round = computed(() => this.type() === "doughnut" || this.type() === "pie", ...ngDevMode ? [{ debugName: "round" }] : /* istanbul ignore next */ []);
345
+ kind = computed(() => {
346
+ switch (this.type()) {
347
+ case "doughnut":
348
+ case "pie": return "round";
349
+ case "radar": return "radar";
350
+ case "polar-area": return "polar";
351
+ case "scatter": return "scatter";
352
+ default: return "axis";
353
+ }
354
+ }, ...ngDevMode ? [{ debugName: "kind" }] : /* istanbul ignore next */ []);
355
+ title = input.required(...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
356
+ labels = input([], ...ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []);
357
+ series = input([], ...ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []);
358
+ categoryLabel = input(null, ...ngDevMode ? [{ debugName: "categoryLabel" }] : /* istanbul ignore next */ []);
359
+ valueLabel = input(null, ...ngDevMode ? [{ debugName: "valueLabel" }] : /* istanbul ignore next */ []);
360
+ locale = input(void 0, ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
361
+ table = input(false, {
362
+ ...ngDevMode ? { debugName: "table" } : /* istanbul ignore next */ {},
363
+ transform: booleanAttribute
364
+ });
365
+ showTable = linkedSignal(() => this.table(), ...ngDevMode ? [{ debugName: "showTable" }] : /* istanbul ignore next */ []);
366
+ hover = signal(null, ...ngDevMode ? [{ debugName: "hover" }] : /* istanbul ignore next */ []);
367
+ numberFormat = computed(() => new Intl.NumberFormat(this.locale(), { maximumFractionDigits: 1 }), ...ngDevMode ? [{ debugName: "numberFormat" }] : /* istanbul ignore next */ []);
368
+ preciseFormat = computed(() => new Intl.NumberFormat(this.locale(), { maximumFractionDigits: 3 }), ...ngDevMode ? [{ debugName: "preciseFormat" }] : /* istanbul ignore next */ []);
369
+ format(value) {
370
+ return this.numberFormat().format(value);
371
+ }
372
+ precise(value) {
373
+ return this.preciseFormat().format(value);
374
+ }
375
+ tickFormatter(ticks, suffix = "") {
376
+ const digits = tickDecimals(ticks);
377
+ const formatter = new Intl.NumberFormat(this.locale(), { maximumFractionDigits: digits });
378
+ return (value) => formatter.format(value) + suffix;
379
+ }
380
+ color(index) {
381
+ return `var(--star-chart-${index % 8 + 1})`;
382
+ }
383
+ numeric = computed(() => this.series().map((s) => ({
384
+ label: s.label,
385
+ data: s.data.map(valueOf)
386
+ })), ...ngDevMode ? [{ debugName: "numeric" }] : /* istanbul ignore next */ []);
387
+ drawn = computed(() => this.numeric().slice(0, 8), ...ngDevMode ? [{ debugName: "drawn" }] : /* istanbul ignore next */ []);
388
+ cell(series, index) {
389
+ return this.format(toFinite(series?.data[index]));
390
+ }
391
+ firstHeader = computed(() => this.round() ? this.text.chartCategory : this.kind() === "scatter" ? this.text.chartSeries : this.categoryLabel() ?? this.text.chartCategory, ...ngDevMode ? [{ debugName: "firstHeader" }] : /* istanbul ignore next */ []);
392
+ xName = computed(() => this.categoryLabel() ?? this.text.chartX, ...ngDevMode ? [{ debugName: "xName" }] : /* istanbul ignore next */ []);
393
+ yName = computed(() => this.valueLabel() ?? this.text.chartY, ...ngDevMode ? [{ debugName: "yName" }] : /* istanbul ignore next */ []);
394
+ valueName = computed(() => this.valueLabel() ?? this.series()[0]?.label ?? this.text.chartValue, ...ngDevMode ? [{ debugName: "valueName" }] : /* istanbul ignore next */ []);
395
+ legend = computed(() => {
396
+ if (this.round()) return this.slices().map((s) => ({
397
+ label: s.label,
398
+ color: s.color,
399
+ shape: ""
400
+ }));
401
+ if (this.kind() === "polar") return [];
402
+ const marked = this.kind() === "radar" || this.kind() === "scatter";
403
+ return this.drawn().map((s, i) => ({
404
+ label: s.label,
405
+ color: this.color(i),
406
+ shape: marked ? markerPath(i, 0, 0, MARKER_RADIUS) : ""
407
+ }));
408
+ }, ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
409
+ description = computed(() => {
410
+ const kind = this.kind();
411
+ const kinds = {
412
+ bar: this.text.chartTypeBar,
413
+ "stacked-bar": this.text.chartTypeStackedBar,
414
+ line: this.text.chartTypeLine,
415
+ area: this.text.chartTypeArea,
416
+ doughnut: this.text.chartTypeDoughnut,
417
+ pie: this.text.chartTypePie,
418
+ radar: this.text.chartTypeRadar,
419
+ "polar-area": this.text.chartTypePolarArea,
420
+ scatter: this.text.chartTypeScatter
421
+ };
422
+ let seriesCount = this.drawn().length;
423
+ let items = this.labels().length;
424
+ let values;
425
+ if (kind === "scatter") {
426
+ const points = this.scatterRows();
427
+ items = points.length;
428
+ values = points.map((p) => p.y);
429
+ } else if (kind === "round" || kind === "polar") {
430
+ seriesCount = Math.min(1, seriesCount);
431
+ values = this.numeric()[0]?.data ?? [];
432
+ } else values = this.drawn().flatMap((s) => s.data);
433
+ const { min, max } = extentOf(values);
434
+ return this.text.chartDescription(kinds[this.type()], seriesCount, items, this.format(min), this.format(max));
435
+ }, ...ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []);
436
+ stack = computed(() => stackColumns(this.drawn().map((s) => s.data), this.labels().length, this.percent()), ...ngDevMode ? [{ debugName: "stack" }] : /* istanbul ignore next */ []);
437
+ yScale = computed(() => {
438
+ if (this.type() === "stacked-bar") {
439
+ const { min, max } = stackExtent(this.stack());
440
+ return niceScale(min, max, { includeZero: true });
441
+ }
442
+ return niceScale(0, extentOf(this.numeric().flatMap((s) => s.data)).max, { includeZero: true });
443
+ }, ...ngDevMode ? [{ debugName: "yScale" }] : /* istanbul ignore next */ []);
444
+ ticks = computed(() => this.yScale().ticks, ...ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []);
445
+ yTick = computed(() => this.tickFormatter(this.ticks(), this.type() === "stacked-bar" && this.percent() ? "%" : ""), ...ngDevMode ? [{ debugName: "yTick" }] : /* istanbul ignore next */ []);
446
+ band = computed(() => (W - PAD.left - PAD.right) / Math.max(1, this.labels().length), ...ngDevMode ? [{ debugName: "band" }] : /* istanbul ignore next */ []);
447
+ axisLabels = computed(() => {
448
+ const max = Math.max(3, Math.floor(this.band() / 6.5));
449
+ return this.labels().map((label) => ({
450
+ text: truncateLabel(label, max),
451
+ full: label
452
+ }));
453
+ }, ...ngDevMode ? [{ debugName: "axisLabels" }] : /* istanbul ignore next */ []);
454
+ x(index) {
455
+ return PAD.left + this.band() * (index + .5);
456
+ }
457
+ y(value) {
458
+ const { min, max } = this.yScale();
459
+ return PAD.top + (1 - (value - min) / (max - min || 1)) * (H - PAD.top - PAD.bottom);
460
+ }
461
+ bars = computed(() => {
462
+ const series = this.drawn();
463
+ const groupWidth = Math.min(this.band() * .7, 28 * series.length + 2 * (series.length - 1));
464
+ const barWidth = (groupWidth - 2 * (series.length - 1)) / Math.max(1, series.length);
465
+ const base = this.y(0);
466
+ return this.labels().flatMap((_, i) => series.map((s, si) => {
467
+ const left = this.x(i) - groupWidth / 2 + si * (barWidth + 2);
468
+ const top = this.y(toFinite(s.data[i]));
469
+ const r = Math.min(4, barWidth / 2, Math.max(0, base - top));
470
+ const path = `M${left},${base}V${top + r}Q${left},${top} ${left + r},${top}H${left + barWidth - r}Q${left + barWidth},${top} ${left + barWidth},${top + r}V${base}Z`;
471
+ return {
472
+ key: `${i}-${si}`,
473
+ index: i,
474
+ path,
475
+ color: this.color(si)
476
+ };
477
+ }));
478
+ }, ...ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []);
479
+ segments = computed(() => {
480
+ const width = Math.min(this.band() * .6, 64);
481
+ return this.stack().flatMap((column, i) => column.segments.filter((segment) => segment.start !== segment.end).map((segment) => {
482
+ const a = this.y(segment.start);
483
+ const b = this.y(segment.end);
484
+ return {
485
+ key: `${i}-${segment.series}`,
486
+ index: i,
487
+ x: this.x(i) - width / 2,
488
+ y: Math.min(a, b),
489
+ width,
490
+ height: Math.abs(a - b),
491
+ color: this.color(segment.series)
492
+ };
493
+ }));
494
+ }, ...ngDevMode ? [{ debugName: "segments" }] : /* istanbul ignore next */ []);
495
+ share(segment) {
496
+ return segment ? Math.round(Math.abs(segment.end - segment.start) * 10) / 10 : 0;
497
+ }
498
+ lines = computed(() => this.drawn().map((s, si) => ({
499
+ label: s.label,
500
+ data: s.data,
501
+ color: this.color(si),
502
+ path: s.data.map((v, i) => `${i ? "L" : "M"}${this.x(i)},${this.y(v)}`).join(""),
503
+ area: s.data.length ? s.data.map((v, i) => `${i ? "L" : "M"}${this.x(i)},${this.y(v)}`).join("") + `L${this.x(s.data.length - 1)},${this.y(0)}L${this.x(0)},${this.y(0)}Z` : ""
504
+ })), ...ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []);
505
+ total = computed(() => (this.numeric()[0]?.data ?? []).reduce((a, b) => a + b, 0), ...ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []);
506
+ slices = computed(() => {
507
+ const data = this.numeric()[0]?.data ?? [];
508
+ let items = this.labels().map((label, i) => ({
509
+ label,
510
+ value: data[i] ?? 0
511
+ }));
512
+ if (items.length > DOUGHNUT_SLOTS) {
513
+ const sorted = [...items].sort((a, b) => b.value - a.value);
514
+ const rest = sorted.slice(3).reduce((sum, item) => sum + item.value, 0);
515
+ items = [...sorted.slice(0, 3), {
516
+ label: this.text.chartOther,
517
+ value: rest
518
+ }];
519
+ }
520
+ const total = items.reduce((sum, item) => sum + item.value, 0) || 1;
521
+ const outer = 110;
522
+ const inner = this.type() === "pie" ? 0 : 70;
523
+ let angle = -Math.PI / 2;
524
+ return items.map((item, i) => {
525
+ const sweep = item.value / total * Math.PI * 2;
526
+ const gap = items.length > 1 ? .02 : 0;
527
+ const a0 = angle + gap / 2;
528
+ const a1 = angle + sweep - gap / 2;
529
+ angle += sweep;
530
+ const large = a1 - a0 > Math.PI ? 1 : 0;
531
+ const p = (r, a) => `${(r * Math.cos(a)).toFixed(2)},${(r * Math.sin(a)).toFixed(2)}`;
532
+ const full = sweep >= Math.PI * 2 - .001;
533
+ const ring = full ? `M0,-${outer}A${outer},${outer} 0 1 1 -0.01,-${outer}ZM0,-${inner}A${inner},${inner} 0 1 0 0.01,-${inner}Z` : `M${p(outer, a0)}A${outer},${outer} 0 ${large} 1 ${p(outer, a1)}L${p(inner, a1)}A${inner},${inner} 0 ${large} 0 ${p(inner, a0)}Z`;
534
+ const wedge = full ? `M0,-${outer}A${outer},${outer} 0 1 1 -0.01,-${outer}Z` : `M0,0L${p(outer, a0)}A${outer},${outer} 0 ${large} 1 ${p(outer, a1)}Z`;
535
+ const path = inner ? ring : wedge;
536
+ return {
537
+ label: item.label,
538
+ value: item.value,
539
+ percent: Math.round(item.value / total * 1e3) / 10,
540
+ color: this.color(i),
541
+ path
542
+ };
543
+ });
544
+ }, ...ngDevMode ? [{ debugName: "slices" }] : /* istanbul ignore next */ []);
545
+ axisLabel(label, angle) {
546
+ const point = polarPoint(117, angle);
547
+ return {
548
+ x: point.x,
549
+ y: point.y,
550
+ anchor: labelAnchor(angle),
551
+ dy: labelOffset(angle),
552
+ text: truncateLabel(label, RADIAL_LABEL_CHARS),
553
+ full: label
554
+ };
555
+ }
556
+ radar = computed(() => {
557
+ const count = this.labels().length;
558
+ const angles = axisAngles(count);
559
+ const half = count ? Math.PI / count : 0;
560
+ const { min, max } = extentOf(this.drawn().flatMap((s) => s.data.slice(0, count)));
561
+ const scale = niceScale(min, max, { includeZero: true });
562
+ const tick = this.tickFormatter(scale.ticks);
563
+ return {
564
+ scale,
565
+ rings: scale.ticks.filter((t) => t > scale.min).map((t) => {
566
+ const radius = linearRadius(t, scale, RADIAL);
567
+ return {
568
+ value: t,
569
+ radius,
570
+ path: ringPath(angles, radius),
571
+ text: tick(t)
572
+ };
573
+ }),
574
+ spokes: angles.map((a) => polarPoint(RADIAL, a)),
575
+ labels: this.labels().map((label, i) => this.axisLabel(label, angles[i])),
576
+ hits: angles.map((a) => sectorPath(0, 117, a - half, a + half)),
577
+ polygons: this.drawn().map((s, si) => {
578
+ const points = angles.map((a, i) => polarPoint(linearRadius(toFinite(s.data[i]), scale, RADIAL), a));
579
+ return {
580
+ label: s.label,
581
+ color: this.color(si),
582
+ path: polygonPath(points),
583
+ vertices: points.map((p, index) => ({
584
+ index,
585
+ shape: markerPath(si, p.x, p.y, 4)
586
+ }))
587
+ };
588
+ })
589
+ };
590
+ }, ...ngDevMode ? [{ debugName: "radar" }] : /* istanbul ignore next */ []);
591
+ polar = computed(() => {
592
+ const count = this.labels().length;
593
+ const data = this.labels().map((_, i) => Math.max(0, toFinite(this.numeric()[0]?.data[i])));
594
+ const scale = niceScale(0, extentOf(data).max, { includeZero: true });
595
+ const tick = this.tickFormatter(scale.ticks);
596
+ const ringAngle = -Math.PI / 2 + (count ? Math.PI / count : 0);
597
+ return {
598
+ scale,
599
+ rings: scale.ticks.filter((t) => t > 0).map((t) => {
600
+ const radius = areaRadius(t, scale.max, RADIAL);
601
+ const at = polarPoint(radius, ringAngle);
602
+ return {
603
+ value: t,
604
+ radius,
605
+ text: tick(t),
606
+ x: at.x + 3,
607
+ y: at.y - 2
608
+ };
609
+ }),
610
+ sectors: polarSectors(data, scale.max, RADIAL).map((s) => ({
611
+ ...s,
612
+ path: sectorPath(0, s.radius, s.start, s.end),
613
+ hit: sectorPath(0, RADIAL, s.start, s.end),
614
+ label: this.axisLabel(this.labels()[s.index], s.mid)
615
+ }))
616
+ };
617
+ }, ...ngDevMode ? [{ debugName: "polar" }] : /* istanbul ignore next */ []);
618
+ scatterData = computed(() => this.series().map((s) => {
619
+ const points = s.data.map((element, i) => typeof element === "number" ? {
620
+ x: i,
621
+ y: element
622
+ } : element);
623
+ return {
624
+ label: s.label,
625
+ points: cleanPoints(points)
626
+ };
627
+ }), ...ngDevMode ? [{ debugName: "scatterData" }] : /* istanbul ignore next */ []);
628
+ scatterRows = computed(() => this.scatterData().flatMap((s) => s.points.map((p) => ({
629
+ series: s.label,
630
+ x: p.x,
631
+ y: p.y
632
+ }))), ...ngDevMode ? [{ debugName: "scatterRows" }] : /* istanbul ignore next */ []);
633
+ scatter = computed(() => {
634
+ const drawn = this.scatterData().slice(0, 8);
635
+ const scales = scatterScales(drawn.flatMap((s) => s.points));
636
+ const left = SCATTER_PAD.left;
637
+ const right = W - SCATTER_PAD.right;
638
+ const top = SCATTER_PAD.top;
639
+ const bottom = H - SCATTER_PAD.bottom;
640
+ const xText = this.tickFormatter(scales.x.ticks);
641
+ const yText = this.tickFormatter(scales.y.ticks);
642
+ let index = 0;
643
+ return {
644
+ xTicks: scales.x.ticks.map((value) => ({
645
+ value,
646
+ position: scalePosition(value, scales.x, left, right),
647
+ text: xText(value)
648
+ })),
649
+ yTicks: scales.y.ticks.map((value) => ({
650
+ value,
651
+ position: scalePosition(value, scales.y, bottom, top),
652
+ text: yText(value)
653
+ })),
654
+ points: drawn.flatMap((s, si) => s.points.map((p) => {
655
+ const px = scalePosition(p.x, scales.x, left, right);
656
+ const py = scalePosition(p.y, scales.y, bottom, top);
657
+ return {
658
+ index: index++,
659
+ seriesLabel: s.label,
660
+ color: this.color(si),
661
+ x: p.x,
662
+ y: p.y,
663
+ px,
664
+ py,
665
+ shape: markerPath(si, px, py, MARKER_RADIUS),
666
+ legendShape: markerPath(si, 0, 0, MARKER_RADIUS)
667
+ };
668
+ }))
669
+ };
670
+ }, ...ngDevMode ? [{ debugName: "scatter" }] : /* istanbul ignore next */ []);
671
+ static ɵfac = i0.ɵɵngDeclareFactory({
672
+ minVersion: "12.0.0",
673
+ version: "22.2.6",
674
+ ngImport: i0,
675
+ type: StarChart,
676
+ deps: [],
677
+ target: i0.ɵɵFactoryTarget.Component
678
+ });
679
+ static ɵcmp = i0.ɵɵngDeclareComponent({
680
+ minVersion: "17.0.0",
681
+ version: "22.2.6",
682
+ type: StarChart,
683
+ isStandalone: true,
684
+ selector: "star-chart",
685
+ inputs: {
686
+ type: {
687
+ classPropertyName: "type",
688
+ publicName: "type",
689
+ isSignal: true,
690
+ isRequired: false,
691
+ transformFunction: null
692
+ },
693
+ percent: {
694
+ classPropertyName: "percent",
695
+ publicName: "percent",
696
+ isSignal: true,
697
+ isRequired: false,
698
+ transformFunction: null
699
+ },
700
+ title: {
701
+ classPropertyName: "title",
702
+ publicName: "title",
703
+ isSignal: true,
704
+ isRequired: true,
705
+ transformFunction: null
706
+ },
707
+ labels: {
708
+ classPropertyName: "labels",
709
+ publicName: "labels",
710
+ isSignal: true,
711
+ isRequired: false,
712
+ transformFunction: null
713
+ },
714
+ series: {
715
+ classPropertyName: "series",
716
+ publicName: "series",
717
+ isSignal: true,
718
+ isRequired: false,
719
+ transformFunction: null
720
+ },
721
+ categoryLabel: {
722
+ classPropertyName: "categoryLabel",
723
+ publicName: "categoryLabel",
724
+ isSignal: true,
725
+ isRequired: false,
726
+ transformFunction: null
727
+ },
728
+ valueLabel: {
729
+ classPropertyName: "valueLabel",
730
+ publicName: "valueLabel",
731
+ isSignal: true,
732
+ isRequired: false,
733
+ transformFunction: null
734
+ },
735
+ locale: {
736
+ classPropertyName: "locale",
737
+ publicName: "locale",
738
+ isSignal: true,
739
+ isRequired: false,
740
+ transformFunction: null
741
+ },
742
+ table: {
743
+ classPropertyName: "table",
744
+ publicName: "table",
745
+ isSignal: true,
746
+ isRequired: false,
747
+ transformFunction: null
748
+ }
749
+ },
750
+ host: { classAttribute: "star-chart" },
751
+ ngImport: i0,
752
+ template: `
753
+ <figure
754
+ class="star-chart__figure"
755
+ [attr.aria-labelledby]="titleId"
756
+ [attr.aria-describedby]="descriptionId"
757
+ >
758
+ <figcaption class="star-chart__head">
759
+ <span class="star-chart__title" [id]="titleId">{{ title() }}</span>
760
+ <button
761
+ type="button"
762
+ class="star-btn star-btn--ghost star-btn--sm"
763
+ [attr.aria-pressed]="showTable()"
764
+ (click)="showTable.set(!showTable())"
765
+ >
766
+ <i
767
+ class="ph-bold"
768
+ [class.ph-table]="!showTable()"
769
+ [class.ph-chart-bar]="showTable()"
770
+ aria-hidden="true"
771
+ ></i>
772
+ {{ showTable() ? text.chartView : text.tableView }}
773
+ </button>
774
+ </figcaption>
775
+ <p class="star-sr-only" [id]="descriptionId">{{ description() }}</p>
776
+
777
+ @if (legend().length > 1 && !showTable()) {
778
+ <ul class="star-chart__legend" aria-hidden="true">
779
+ @for (item of legend(); track item.label) {
780
+ <li>
781
+ @if (item.shape) {
782
+ <svg class="star-chart__swatch-shape" viewBox="-6 -6 12 12">
783
+ <path
784
+ class="star-chart__mark star-chart__marker"
785
+ [attr.d]="item.shape"
786
+ [style.--mark]="item.color"
787
+ />
788
+ </svg>
789
+ } @else {
790
+ <span class="star-chart__swatch" [style.background]="item.color"></span>
791
+ }
792
+ {{ item.label }}
793
+ </li>
794
+ }
795
+ </ul>
796
+ }
797
+
798
+ <div
799
+ class="star-chart__plot"
800
+ [hidden]="showTable()"
801
+ aria-hidden="true"
802
+ (mouseleave)="hover.set(null)"
803
+ >
804
+ @switch (kind()) {
805
+ @case ('round') {
806
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
807
+ <g [attr.transform]="'translate(' + W / 2 + ',' + H / 2 + ')'">
808
+ @for (slice of slices(); track slice.label; let i = $index) {
809
+ <path
810
+ class="star-chart__slice"
811
+ [attr.d]="slice.path"
812
+ [style.fill]="slice.color"
813
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== i"
814
+ (mouseenter)="hover.set(i)"
815
+ />
816
+ }
817
+ @if (type() === 'doughnut') {
818
+ <text class="star-chart__total" y="-2" text-anchor="middle">
819
+ {{ format(total()) }}
820
+ </text>
821
+ <text class="star-chart__total-label" y="18" text-anchor="middle">
822
+ {{ text.chartTotal }}
823
+ </text>
824
+ }
825
+ </g>
826
+ </svg>
827
+ @if (hover() !== null) {
828
+ @let slice = slices()[hover()!];
829
+ @if (slice) {
830
+ <div class="star-chart__tip" [style.left.%]="50" [style.top.%]="8">
831
+ <span class="star-chart__swatch" [style.background]="slice.color"></span>
832
+ {{ slice.label }}: <strong>{{ format(slice.value) }}</strong> ({{
833
+ slice.percent
834
+ }}%)
835
+ </div>
836
+ }
837
+ }
838
+ }
839
+ @case ('radar') {
840
+ @let plot = radar();
841
+ <svg [attr.viewBox]="'0 0 ' + RW + ' ' + RH" class="star-chart__svg">
842
+ <g [attr.transform]="'translate(' + RW / 2 + ',' + RH / 2 + ')'">
843
+ @for (ring of plot.rings; track ring.value) {
844
+ <path class="star-chart__ring" [attr.d]="ring.path" />
845
+ }
846
+ @for (spoke of plot.spokes; track $index) {
847
+ <line
848
+ class="star-chart__grid"
849
+ x1="0"
850
+ y1="0"
851
+ [attr.x2]="spoke.x"
852
+ [attr.y2]="spoke.y"
853
+ />
854
+ }
855
+ @if (hover() !== null && plot.spokes[hover()!]) {
856
+ <line
857
+ class="star-chart__crosshair"
858
+ x1="0"
859
+ y1="0"
860
+ [attr.x2]="plot.spokes[hover()!].x"
861
+ [attr.y2]="plot.spokes[hover()!].y"
862
+ />
863
+ }
864
+ @for (polygon of plot.polygons; track polygon.label) {
865
+ <path
866
+ class="star-chart__mark star-chart__polygon"
867
+ [attr.d]="polygon.path"
868
+ [style.--mark]="polygon.color"
869
+ />
870
+ }
871
+ @for (polygon of plot.polygons; track polygon.label) {
872
+ @for (vertex of polygon.vertices; track vertex.index) {
873
+ <path
874
+ class="star-chart__mark star-chart__vertex"
875
+ [attr.d]="vertex.shape"
876
+ [style.--mark]="polygon.color"
877
+ />
878
+ }
879
+ }
880
+ @for (ring of plot.rings; track ring.value) {
881
+ <text
882
+ class="star-chart__ring-label"
883
+ [attr.x]="4"
884
+ [attr.y]="-ring.radius + 11"
885
+ text-anchor="start"
886
+ >
887
+ {{ ring.text }}
888
+ </text>
889
+ }
890
+ @for (label of plot.labels; track $index) {
891
+ <text
892
+ class="star-chart__axis"
893
+ [attr.x]="label.x"
894
+ [attr.y]="label.y"
895
+ [attr.dy]="label.dy"
896
+ [attr.text-anchor]="label.anchor"
897
+ >
898
+ {{ label.text }}
899
+ @if (label.text !== label.full) {
900
+ <title>{{ label.full }}</title>
901
+ }
902
+ </text>
903
+ }
904
+ @for (hit of plot.hits; track $index; let i = $index) {
905
+ <path class="star-chart__hit" [attr.d]="hit" (mouseenter)="hover.set(i)" />
906
+ }
907
+ </g>
908
+ </svg>
909
+ @if (hover() !== null && labels()[hover()!] !== undefined) {
910
+ <div class="star-chart__tip star-chart__tip--corner">
911
+ <span class="star-chart__tip-title">{{ labels()[hover()!] }}</span>
912
+ @for (s of drawn(); track s.label; let si = $index) {
913
+ <span class="star-chart__tip-row">
914
+ <span class="star-chart__swatch" [style.background]="color(si)"></span>
915
+ {{ s.label }}: <strong>{{ cell(s, hover()!) }}</strong>
916
+ </span>
917
+ }
918
+ </div>
919
+ }
920
+ }
921
+ @case ('polar') {
922
+ @let plot = polar();
923
+ <svg [attr.viewBox]="'0 0 ' + RW + ' ' + RH" class="star-chart__svg">
924
+ <g [attr.transform]="'translate(' + RW / 2 + ',' + RH / 2 + ')'">
925
+ @for (ring of plot.rings; track ring.value) {
926
+ <circle class="star-chart__ring" [attr.r]="ring.radius" />
927
+ }
928
+ @for (sector of plot.sectors; track sector.index) {
929
+ @if (sector.path) {
930
+ <path
931
+ class="star-chart__mark star-chart__sector"
932
+ [attr.d]="sector.path"
933
+ [style.--mark]="color(0)"
934
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== sector.index"
935
+ />
936
+ }
937
+ }
938
+ @for (ring of plot.rings; track ring.value) {
939
+ <text
940
+ class="star-chart__ring-label"
941
+ [attr.x]="ring.x"
942
+ [attr.y]="ring.y"
943
+ text-anchor="start"
944
+ >
945
+ {{ ring.text }}
946
+ </text>
947
+ }
948
+ @for (sector of plot.sectors; track sector.index) {
949
+ <text
950
+ class="star-chart__axis"
951
+ [attr.x]="sector.label.x"
952
+ [attr.y]="sector.label.y"
953
+ [attr.dy]="sector.label.dy"
954
+ [attr.text-anchor]="sector.label.anchor"
955
+ >
956
+ {{ sector.label.text }}
957
+ @if (sector.label.text !== sector.label.full) {
958
+ <title>{{ sector.label.full }}</title>
959
+ }
960
+ </text>
961
+ }
962
+ @for (sector of plot.sectors; track sector.index) {
963
+ <path
964
+ class="star-chart__hit"
965
+ [attr.d]="sector.hit"
966
+ (mouseenter)="hover.set(sector.index)"
967
+ />
968
+ }
969
+ </g>
970
+ </svg>
971
+ @if (hover() !== null) {
972
+ @let sector = plot.sectors[hover()!];
973
+ @if (sector) {
974
+ <div class="star-chart__tip star-chart__tip--corner">
975
+ <span class="star-chart__tip-title">{{ sector.label.full }}</span>
976
+ <span class="star-chart__tip-row">
977
+ <span class="star-chart__swatch" [style.background]="color(0)"></span>
978
+ {{ valueName() }}: <strong>{{ format(sector.value) }}</strong>
979
+ </span>
980
+ </div>
981
+ }
982
+ }
983
+ }
984
+ @case ('scatter') {
985
+ @let plot = scatter();
986
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
987
+ @for (tick of plot.yTicks; track tick.value) {
988
+ <line
989
+ class="star-chart__grid"
990
+ [attr.x1]="SP.left"
991
+ [attr.x2]="W - SP.right"
992
+ [attr.y1]="tick.position"
993
+ [attr.y2]="tick.position"
994
+ />
995
+ <text
996
+ class="star-chart__axis"
997
+ [attr.x]="SP.left - 8"
998
+ [attr.y]="tick.position + 4"
999
+ text-anchor="end"
1000
+ >
1001
+ {{ tick.text }}
1002
+ </text>
1003
+ }
1004
+ @for (tick of plot.xTicks; track tick.value) {
1005
+ <line
1006
+ class="star-chart__grid"
1007
+ [attr.x1]="tick.position"
1008
+ [attr.x2]="tick.position"
1009
+ [attr.y1]="SP.top"
1010
+ [attr.y2]="H - SP.bottom"
1011
+ />
1012
+ <text
1013
+ class="star-chart__axis"
1014
+ [attr.x]="tick.position"
1015
+ [attr.y]="H - SP.bottom + 16"
1016
+ text-anchor="middle"
1017
+ >
1018
+ {{ tick.text }}
1019
+ </text>
1020
+ }
1021
+ @if (categoryLabel()) {
1022
+ <text
1023
+ class="star-chart__axis-title"
1024
+ [attr.x]="W - SP.right"
1025
+ [attr.y]="H - 4"
1026
+ text-anchor="end"
1027
+ >
1028
+ {{ categoryLabel() }}
1029
+ </text>
1030
+ }
1031
+ @if (valueLabel()) {
1032
+ <text class="star-chart__axis-title" x="4" y="12" text-anchor="start">
1033
+ {{ valueLabel() }}
1034
+ </text>
1035
+ }
1036
+ @for (point of plot.points; track point.index) {
1037
+ <path
1038
+ class="star-chart__mark star-chart__point"
1039
+ [attr.d]="point.shape"
1040
+ [style.--mark]="point.color"
1041
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== point.index"
1042
+ />
1043
+ }
1044
+ @for (point of plot.points; track point.index) {
1045
+ <circle
1046
+ class="star-chart__hit"
1047
+ r="10"
1048
+ [attr.cx]="point.px"
1049
+ [attr.cy]="point.py"
1050
+ (mouseenter)="hover.set(point.index)"
1051
+ />
1052
+ }
1053
+ </svg>
1054
+ @if (hover() !== null) {
1055
+ @let point = plot.points[hover()!];
1056
+ @if (point) {
1057
+ <div
1058
+ class="star-chart__tip star-chart__tip--point"
1059
+ [style.left.%]="(point.px / W) * 100"
1060
+ [style.top.%]="(point.py / H) * 100"
1061
+ [style.translate]="
1062
+ point.px / W > 0.7 ? '-100% 0' : point.px / W < 0.3 ? '0 0' : null
1063
+ "
1064
+ >
1065
+ <span class="star-chart__tip-title">{{ point.seriesLabel }}</span>
1066
+ <span class="star-chart__tip-row">
1067
+ <svg class="star-chart__swatch-shape" viewBox="-6 -6 12 12">
1068
+ <path
1069
+ class="star-chart__mark star-chart__marker"
1070
+ [attr.d]="point.legendShape"
1071
+ [style.--mark]="point.color"
1072
+ />
1073
+ </svg>
1074
+ {{ xName() }}: <strong>{{ precise(point.x) }}</strong>
1075
+ </span>
1076
+ <span class="star-chart__tip-row star-chart__tip-indent">
1077
+ {{ yName() }}: <strong>{{ precise(point.y) }}</strong>
1078
+ </span>
1079
+ </div>
1080
+ }
1081
+ }
1082
+ }
1083
+ @default {
1084
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
1085
+ @for (tick of ticks(); track tick) {
1086
+ <line
1087
+ class="star-chart__grid"
1088
+ [attr.x1]="PAD.left"
1089
+ [attr.x2]="W - PAD.right"
1090
+ [attr.y1]="y(tick)"
1091
+ [attr.y2]="y(tick)"
1092
+ />
1093
+ <text
1094
+ class="star-chart__axis"
1095
+ [attr.x]="PAD.left - 8"
1096
+ [attr.y]="y(tick) + 4"
1097
+ text-anchor="end"
1098
+ >
1099
+ {{ yTick()(tick) }}
1100
+ </text>
1101
+ }
1102
+ @if (yScale().min < 0) {
1103
+ <line
1104
+ class="star-chart__baseline"
1105
+ [attr.x1]="PAD.left"
1106
+ [attr.x2]="W - PAD.right"
1107
+ [attr.y1]="y(0)"
1108
+ [attr.y2]="y(0)"
1109
+ />
1110
+ }
1111
+ @for (label of axisLabels(); track $index; let i = $index) {
1112
+ <text
1113
+ class="star-chart__axis"
1114
+ [attr.x]="x(i)"
1115
+ [attr.y]="H - 12"
1116
+ text-anchor="middle"
1117
+ >
1118
+ {{ label.text }}
1119
+ @if (label.text !== label.full) {
1120
+ <title>{{ label.full }}</title>
1121
+ }
1122
+ </text>
1123
+ }
1124
+ @if (type() === 'bar') {
1125
+ @for (bar of bars(); track bar.key) {
1126
+ <path
1127
+ class="star-chart__bar"
1128
+ [attr.d]="bar.path"
1129
+ [style.fill]="bar.color"
1130
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== bar.index"
1131
+ />
1132
+ }
1133
+ } @else if (type() === 'stacked-bar') {
1134
+ @for (segment of segments(); track segment.key) {
1135
+ <rect
1136
+ class="star-chart__mark star-chart__segment"
1137
+ [attr.x]="segment.x"
1138
+ [attr.y]="segment.y"
1139
+ [attr.width]="segment.width"
1140
+ [attr.height]="segment.height"
1141
+ [style.--mark]="segment.color"
1142
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== segment.index"
1143
+ />
1144
+ }
1145
+ } @else {
1146
+ @if (hover() !== null) {
1147
+ <line
1148
+ class="star-chart__crosshair"
1149
+ [attr.x1]="x(hover()!)"
1150
+ [attr.x2]="x(hover()!)"
1151
+ [attr.y1]="PAD.top"
1152
+ [attr.y2]="H - PAD.bottom"
1153
+ />
1154
+ }
1155
+ @for (line of lines(); track line.label) {
1156
+ @if (type() === 'area') {
1157
+ <path class="star-chart__area" [attr.d]="line.area" [style.fill]="line.color" />
1158
+ }
1159
+ <path class="star-chart__line" [attr.d]="line.path" [style.stroke]="line.color" />
1160
+ @if (hover() !== null) {
1161
+ <circle
1162
+ class="star-chart__dot"
1163
+ r="4.5"
1164
+ [attr.cx]="x(hover()!)"
1165
+ [attr.cy]="y(line.data[hover()!] ?? 0)"
1166
+ [style.fill]="line.color"
1167
+ />
1168
+ }
1169
+ }
1170
+ }
1171
+ <!-- Hit targets: one full-height column per category, wider than the marks. -->
1172
+ @for (label of labels(); track $index; let i = $index) {
1173
+ <rect
1174
+ class="star-chart__hit"
1175
+ [attr.x]="x(i) - band() / 2"
1176
+ [attr.y]="PAD.top"
1177
+ [attr.width]="band()"
1178
+ [attr.height]="H - PAD.top - PAD.bottom"
1179
+ (mouseenter)="hover.set(i)"
1180
+ />
1181
+ }
1182
+ </svg>
1183
+ @if (hover() !== null) {
1184
+ <div
1185
+ class="star-chart__tip"
1186
+ [style.left.%]="(x(hover()!) / W) * 100"
1187
+ [style.top.%]="6"
1188
+ >
1189
+ <span class="star-chart__tip-title">{{ labels()[hover()!] }}</span>
1190
+ @for (s of drawn(); track s.label; let si = $index) {
1191
+ <span class="star-chart__tip-row">
1192
+ <span class="star-chart__swatch" [style.background]="color(si)"></span>
1193
+ {{ s.label }}: <strong>{{ cell(s, hover()!) }}</strong>
1194
+ @if (type() === 'stacked-bar' && percent()) {
1195
+ ({{ share(stack()[hover()!]?.segments?.[si]) }}%)
1196
+ }
1197
+ </span>
1198
+ }
1199
+ @if (type() === 'stacked-bar') {
1200
+ <span class="star-chart__tip-row star-chart__tip-total">
1201
+ {{ text.chartTotal }}:
1202
+ <strong>{{ format(stack()[hover()!]?.total ?? 0) }}</strong>
1203
+ </span>
1204
+ }
1205
+ </div>
1206
+ }
1207
+ }
1208
+ }
1209
+ </div>
1210
+
1211
+ <table class="star-chart__table" [class.star-sr-only]="!showTable()">
1212
+ <caption class="star-sr-only">
1213
+ {{
1214
+ title()
1215
+ }}
1216
+ </caption>
1217
+ <thead>
1218
+ <tr>
1219
+ <th scope="col">
1220
+ {{ firstHeader() }}
1221
+ </th>
1222
+ @if (round()) {
1223
+ <th scope="col">{{ series()[0]?.label ?? text.chartValue }}</th>
1224
+ <th scope="col">{{ text.chartShare }}</th>
1225
+ } @else if (kind() === 'polar') {
1226
+ <th scope="col">{{ valueName() }}</th>
1227
+ } @else if (kind() === 'scatter') {
1228
+ <th scope="col">{{ xName() }}</th>
1229
+ <th scope="col">{{ yName() }}</th>
1230
+ } @else {
1231
+ @for (s of series(); track s.label) {
1232
+ <th scope="col">{{ s.label }}</th>
1233
+ }
1234
+ @if (type() === 'stacked-bar') {
1235
+ <th scope="col">{{ text.chartTotal }}</th>
1236
+ }
1237
+ }
1238
+ </tr>
1239
+ </thead>
1240
+ <tbody>
1241
+ @if (round()) {
1242
+ @for (slice of slices(); track slice.label) {
1243
+ <tr>
1244
+ <th scope="row">{{ slice.label }}</th>
1245
+ <td>{{ format(slice.value) }}</td>
1246
+ <td>{{ slice.percent }}%</td>
1247
+ </tr>
1248
+ }
1249
+ } @else if (kind() === 'polar') {
1250
+ @for (label of labels(); track $index; let i = $index) {
1251
+ <tr>
1252
+ <th scope="row">{{ label }}</th>
1253
+ <td>{{ cell(numeric()[0], i) }}</td>
1254
+ </tr>
1255
+ }
1256
+ } @else if (kind() === 'scatter') {
1257
+ @for (row of scatterRows(); track $index) {
1258
+ <tr>
1259
+ <th scope="row">{{ row.series }}</th>
1260
+ <td>{{ precise(row.x) }}</td>
1261
+ <td>{{ precise(row.y) }}</td>
1262
+ </tr>
1263
+ }
1264
+ } @else {
1265
+ @for (label of labels(); track $index; let i = $index) {
1266
+ <tr>
1267
+ <th scope="row">{{ label }}</th>
1268
+ @for (s of numeric(); track s.label) {
1269
+ <td>{{ cell(s, i) }}</td>
1270
+ }
1271
+ @if (type() === 'stacked-bar') {
1272
+ <td>{{ format(stack()[i]?.total ?? 0) }}</td>
1273
+ }
1274
+ </tr>
1275
+ }
1276
+ }
1277
+ </tbody>
1278
+ </table>
1279
+ </figure>
1280
+ `,
1281
+ isInline: true,
1282
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
1283
+ });
1284
+ };
1285
+ i0.ɵɵngDeclareClassMetadata({
1286
+ minVersion: "12.0.0",
1287
+ version: "22.2.6",
1288
+ ngImport: i0,
1289
+ type: StarChart,
1290
+ decorators: [{
1291
+ type: Component,
1292
+ args: [{
1293
+ selector: "star-chart",
1294
+ changeDetection: ChangeDetectionStrategy.OnPush,
1295
+ host: { class: "star-chart" },
1296
+ template: `
1297
+ <figure
1298
+ class="star-chart__figure"
1299
+ [attr.aria-labelledby]="titleId"
1300
+ [attr.aria-describedby]="descriptionId"
1301
+ >
1302
+ <figcaption class="star-chart__head">
1303
+ <span class="star-chart__title" [id]="titleId">{{ title() }}</span>
1304
+ <button
1305
+ type="button"
1306
+ class="star-btn star-btn--ghost star-btn--sm"
1307
+ [attr.aria-pressed]="showTable()"
1308
+ (click)="showTable.set(!showTable())"
1309
+ >
1310
+ <i
1311
+ class="ph-bold"
1312
+ [class.ph-table]="!showTable()"
1313
+ [class.ph-chart-bar]="showTable()"
1314
+ aria-hidden="true"
1315
+ ></i>
1316
+ {{ showTable() ? text.chartView : text.tableView }}
1317
+ </button>
1318
+ </figcaption>
1319
+ <p class="star-sr-only" [id]="descriptionId">{{ description() }}</p>
1320
+
1321
+ @if (legend().length > 1 && !showTable()) {
1322
+ <ul class="star-chart__legend" aria-hidden="true">
1323
+ @for (item of legend(); track item.label) {
1324
+ <li>
1325
+ @if (item.shape) {
1326
+ <svg class="star-chart__swatch-shape" viewBox="-6 -6 12 12">
1327
+ <path
1328
+ class="star-chart__mark star-chart__marker"
1329
+ [attr.d]="item.shape"
1330
+ [style.--mark]="item.color"
1331
+ />
1332
+ </svg>
1333
+ } @else {
1334
+ <span class="star-chart__swatch" [style.background]="item.color"></span>
1335
+ }
1336
+ {{ item.label }}
1337
+ </li>
1338
+ }
1339
+ </ul>
1340
+ }
1341
+
1342
+ <div
1343
+ class="star-chart__plot"
1344
+ [hidden]="showTable()"
1345
+ aria-hidden="true"
1346
+ (mouseleave)="hover.set(null)"
1347
+ >
1348
+ @switch (kind()) {
1349
+ @case ('round') {
1350
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
1351
+ <g [attr.transform]="'translate(' + W / 2 + ',' + H / 2 + ')'">
1352
+ @for (slice of slices(); track slice.label; let i = $index) {
1353
+ <path
1354
+ class="star-chart__slice"
1355
+ [attr.d]="slice.path"
1356
+ [style.fill]="slice.color"
1357
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== i"
1358
+ (mouseenter)="hover.set(i)"
1359
+ />
1360
+ }
1361
+ @if (type() === 'doughnut') {
1362
+ <text class="star-chart__total" y="-2" text-anchor="middle">
1363
+ {{ format(total()) }}
1364
+ </text>
1365
+ <text class="star-chart__total-label" y="18" text-anchor="middle">
1366
+ {{ text.chartTotal }}
1367
+ </text>
1368
+ }
1369
+ </g>
1370
+ </svg>
1371
+ @if (hover() !== null) {
1372
+ @let slice = slices()[hover()!];
1373
+ @if (slice) {
1374
+ <div class="star-chart__tip" [style.left.%]="50" [style.top.%]="8">
1375
+ <span class="star-chart__swatch" [style.background]="slice.color"></span>
1376
+ {{ slice.label }}: <strong>{{ format(slice.value) }}</strong> ({{
1377
+ slice.percent
1378
+ }}%)
1379
+ </div>
1380
+ }
1381
+ }
1382
+ }
1383
+ @case ('radar') {
1384
+ @let plot = radar();
1385
+ <svg [attr.viewBox]="'0 0 ' + RW + ' ' + RH" class="star-chart__svg">
1386
+ <g [attr.transform]="'translate(' + RW / 2 + ',' + RH / 2 + ')'">
1387
+ @for (ring of plot.rings; track ring.value) {
1388
+ <path class="star-chart__ring" [attr.d]="ring.path" />
1389
+ }
1390
+ @for (spoke of plot.spokes; track $index) {
1391
+ <line
1392
+ class="star-chart__grid"
1393
+ x1="0"
1394
+ y1="0"
1395
+ [attr.x2]="spoke.x"
1396
+ [attr.y2]="spoke.y"
1397
+ />
1398
+ }
1399
+ @if (hover() !== null && plot.spokes[hover()!]) {
1400
+ <line
1401
+ class="star-chart__crosshair"
1402
+ x1="0"
1403
+ y1="0"
1404
+ [attr.x2]="plot.spokes[hover()!].x"
1405
+ [attr.y2]="plot.spokes[hover()!].y"
1406
+ />
1407
+ }
1408
+ @for (polygon of plot.polygons; track polygon.label) {
1409
+ <path
1410
+ class="star-chart__mark star-chart__polygon"
1411
+ [attr.d]="polygon.path"
1412
+ [style.--mark]="polygon.color"
1413
+ />
1414
+ }
1415
+ @for (polygon of plot.polygons; track polygon.label) {
1416
+ @for (vertex of polygon.vertices; track vertex.index) {
1417
+ <path
1418
+ class="star-chart__mark star-chart__vertex"
1419
+ [attr.d]="vertex.shape"
1420
+ [style.--mark]="polygon.color"
1421
+ />
1422
+ }
1423
+ }
1424
+ @for (ring of plot.rings; track ring.value) {
1425
+ <text
1426
+ class="star-chart__ring-label"
1427
+ [attr.x]="4"
1428
+ [attr.y]="-ring.radius + 11"
1429
+ text-anchor="start"
1430
+ >
1431
+ {{ ring.text }}
1432
+ </text>
1433
+ }
1434
+ @for (label of plot.labels; track $index) {
1435
+ <text
1436
+ class="star-chart__axis"
1437
+ [attr.x]="label.x"
1438
+ [attr.y]="label.y"
1439
+ [attr.dy]="label.dy"
1440
+ [attr.text-anchor]="label.anchor"
1441
+ >
1442
+ {{ label.text }}
1443
+ @if (label.text !== label.full) {
1444
+ <title>{{ label.full }}</title>
1445
+ }
1446
+ </text>
1447
+ }
1448
+ @for (hit of plot.hits; track $index; let i = $index) {
1449
+ <path class="star-chart__hit" [attr.d]="hit" (mouseenter)="hover.set(i)" />
1450
+ }
1451
+ </g>
1452
+ </svg>
1453
+ @if (hover() !== null && labels()[hover()!] !== undefined) {
1454
+ <div class="star-chart__tip star-chart__tip--corner">
1455
+ <span class="star-chart__tip-title">{{ labels()[hover()!] }}</span>
1456
+ @for (s of drawn(); track s.label; let si = $index) {
1457
+ <span class="star-chart__tip-row">
1458
+ <span class="star-chart__swatch" [style.background]="color(si)"></span>
1459
+ {{ s.label }}: <strong>{{ cell(s, hover()!) }}</strong>
1460
+ </span>
1461
+ }
1462
+ </div>
1463
+ }
1464
+ }
1465
+ @case ('polar') {
1466
+ @let plot = polar();
1467
+ <svg [attr.viewBox]="'0 0 ' + RW + ' ' + RH" class="star-chart__svg">
1468
+ <g [attr.transform]="'translate(' + RW / 2 + ',' + RH / 2 + ')'">
1469
+ @for (ring of plot.rings; track ring.value) {
1470
+ <circle class="star-chart__ring" [attr.r]="ring.radius" />
1471
+ }
1472
+ @for (sector of plot.sectors; track sector.index) {
1473
+ @if (sector.path) {
1474
+ <path
1475
+ class="star-chart__mark star-chart__sector"
1476
+ [attr.d]="sector.path"
1477
+ [style.--mark]="color(0)"
1478
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== sector.index"
1479
+ />
1480
+ }
1481
+ }
1482
+ @for (ring of plot.rings; track ring.value) {
1483
+ <text
1484
+ class="star-chart__ring-label"
1485
+ [attr.x]="ring.x"
1486
+ [attr.y]="ring.y"
1487
+ text-anchor="start"
1488
+ >
1489
+ {{ ring.text }}
1490
+ </text>
1491
+ }
1492
+ @for (sector of plot.sectors; track sector.index) {
1493
+ <text
1494
+ class="star-chart__axis"
1495
+ [attr.x]="sector.label.x"
1496
+ [attr.y]="sector.label.y"
1497
+ [attr.dy]="sector.label.dy"
1498
+ [attr.text-anchor]="sector.label.anchor"
1499
+ >
1500
+ {{ sector.label.text }}
1501
+ @if (sector.label.text !== sector.label.full) {
1502
+ <title>{{ sector.label.full }}</title>
1503
+ }
1504
+ </text>
1505
+ }
1506
+ @for (sector of plot.sectors; track sector.index) {
1507
+ <path
1508
+ class="star-chart__hit"
1509
+ [attr.d]="sector.hit"
1510
+ (mouseenter)="hover.set(sector.index)"
1511
+ />
1512
+ }
1513
+ </g>
1514
+ </svg>
1515
+ @if (hover() !== null) {
1516
+ @let sector = plot.sectors[hover()!];
1517
+ @if (sector) {
1518
+ <div class="star-chart__tip star-chart__tip--corner">
1519
+ <span class="star-chart__tip-title">{{ sector.label.full }}</span>
1520
+ <span class="star-chart__tip-row">
1521
+ <span class="star-chart__swatch" [style.background]="color(0)"></span>
1522
+ {{ valueName() }}: <strong>{{ format(sector.value) }}</strong>
1523
+ </span>
1524
+ </div>
1525
+ }
1526
+ }
1527
+ }
1528
+ @case ('scatter') {
1529
+ @let plot = scatter();
1530
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
1531
+ @for (tick of plot.yTicks; track tick.value) {
1532
+ <line
1533
+ class="star-chart__grid"
1534
+ [attr.x1]="SP.left"
1535
+ [attr.x2]="W - SP.right"
1536
+ [attr.y1]="tick.position"
1537
+ [attr.y2]="tick.position"
1538
+ />
1539
+ <text
1540
+ class="star-chart__axis"
1541
+ [attr.x]="SP.left - 8"
1542
+ [attr.y]="tick.position + 4"
1543
+ text-anchor="end"
1544
+ >
1545
+ {{ tick.text }}
1546
+ </text>
1547
+ }
1548
+ @for (tick of plot.xTicks; track tick.value) {
1549
+ <line
1550
+ class="star-chart__grid"
1551
+ [attr.x1]="tick.position"
1552
+ [attr.x2]="tick.position"
1553
+ [attr.y1]="SP.top"
1554
+ [attr.y2]="H - SP.bottom"
1555
+ />
1556
+ <text
1557
+ class="star-chart__axis"
1558
+ [attr.x]="tick.position"
1559
+ [attr.y]="H - SP.bottom + 16"
1560
+ text-anchor="middle"
1561
+ >
1562
+ {{ tick.text }}
1563
+ </text>
1564
+ }
1565
+ @if (categoryLabel()) {
1566
+ <text
1567
+ class="star-chart__axis-title"
1568
+ [attr.x]="W - SP.right"
1569
+ [attr.y]="H - 4"
1570
+ text-anchor="end"
1571
+ >
1572
+ {{ categoryLabel() }}
1573
+ </text>
1574
+ }
1575
+ @if (valueLabel()) {
1576
+ <text class="star-chart__axis-title" x="4" y="12" text-anchor="start">
1577
+ {{ valueLabel() }}
1578
+ </text>
1579
+ }
1580
+ @for (point of plot.points; track point.index) {
1581
+ <path
1582
+ class="star-chart__mark star-chart__point"
1583
+ [attr.d]="point.shape"
1584
+ [style.--mark]="point.color"
1585
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== point.index"
1586
+ />
1587
+ }
1588
+ @for (point of plot.points; track point.index) {
1589
+ <circle
1590
+ class="star-chart__hit"
1591
+ r="10"
1592
+ [attr.cx]="point.px"
1593
+ [attr.cy]="point.py"
1594
+ (mouseenter)="hover.set(point.index)"
1595
+ />
1596
+ }
1597
+ </svg>
1598
+ @if (hover() !== null) {
1599
+ @let point = plot.points[hover()!];
1600
+ @if (point) {
1601
+ <div
1602
+ class="star-chart__tip star-chart__tip--point"
1603
+ [style.left.%]="(point.px / W) * 100"
1604
+ [style.top.%]="(point.py / H) * 100"
1605
+ [style.translate]="
1606
+ point.px / W > 0.7 ? '-100% 0' : point.px / W < 0.3 ? '0 0' : null
1607
+ "
1608
+ >
1609
+ <span class="star-chart__tip-title">{{ point.seriesLabel }}</span>
1610
+ <span class="star-chart__tip-row">
1611
+ <svg class="star-chart__swatch-shape" viewBox="-6 -6 12 12">
1612
+ <path
1613
+ class="star-chart__mark star-chart__marker"
1614
+ [attr.d]="point.legendShape"
1615
+ [style.--mark]="point.color"
1616
+ />
1617
+ </svg>
1618
+ {{ xName() }}: <strong>{{ precise(point.x) }}</strong>
1619
+ </span>
1620
+ <span class="star-chart__tip-row star-chart__tip-indent">
1621
+ {{ yName() }}: <strong>{{ precise(point.y) }}</strong>
1622
+ </span>
1623
+ </div>
1624
+ }
1625
+ }
1626
+ }
1627
+ @default {
1628
+ <svg [attr.viewBox]="'0 0 ' + W + ' ' + H" class="star-chart__svg">
1629
+ @for (tick of ticks(); track tick) {
1630
+ <line
1631
+ class="star-chart__grid"
1632
+ [attr.x1]="PAD.left"
1633
+ [attr.x2]="W - PAD.right"
1634
+ [attr.y1]="y(tick)"
1635
+ [attr.y2]="y(tick)"
1636
+ />
1637
+ <text
1638
+ class="star-chart__axis"
1639
+ [attr.x]="PAD.left - 8"
1640
+ [attr.y]="y(tick) + 4"
1641
+ text-anchor="end"
1642
+ >
1643
+ {{ yTick()(tick) }}
1644
+ </text>
1645
+ }
1646
+ @if (yScale().min < 0) {
1647
+ <line
1648
+ class="star-chart__baseline"
1649
+ [attr.x1]="PAD.left"
1650
+ [attr.x2]="W - PAD.right"
1651
+ [attr.y1]="y(0)"
1652
+ [attr.y2]="y(0)"
1653
+ />
1654
+ }
1655
+ @for (label of axisLabels(); track $index; let i = $index) {
1656
+ <text
1657
+ class="star-chart__axis"
1658
+ [attr.x]="x(i)"
1659
+ [attr.y]="H - 12"
1660
+ text-anchor="middle"
1661
+ >
1662
+ {{ label.text }}
1663
+ @if (label.text !== label.full) {
1664
+ <title>{{ label.full }}</title>
1665
+ }
1666
+ </text>
1667
+ }
1668
+ @if (type() === 'bar') {
1669
+ @for (bar of bars(); track bar.key) {
1670
+ <path
1671
+ class="star-chart__bar"
1672
+ [attr.d]="bar.path"
1673
+ [style.fill]="bar.color"
1674
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== bar.index"
1675
+ />
1676
+ }
1677
+ } @else if (type() === 'stacked-bar') {
1678
+ @for (segment of segments(); track segment.key) {
1679
+ <rect
1680
+ class="star-chart__mark star-chart__segment"
1681
+ [attr.x]="segment.x"
1682
+ [attr.y]="segment.y"
1683
+ [attr.width]="segment.width"
1684
+ [attr.height]="segment.height"
1685
+ [style.--mark]="segment.color"
1686
+ [class.star-chart__mark--dim]="hover() !== null && hover() !== segment.index"
1687
+ />
1688
+ }
1689
+ } @else {
1690
+ @if (hover() !== null) {
1691
+ <line
1692
+ class="star-chart__crosshair"
1693
+ [attr.x1]="x(hover()!)"
1694
+ [attr.x2]="x(hover()!)"
1695
+ [attr.y1]="PAD.top"
1696
+ [attr.y2]="H - PAD.bottom"
1697
+ />
1698
+ }
1699
+ @for (line of lines(); track line.label) {
1700
+ @if (type() === 'area') {
1701
+ <path class="star-chart__area" [attr.d]="line.area" [style.fill]="line.color" />
1702
+ }
1703
+ <path class="star-chart__line" [attr.d]="line.path" [style.stroke]="line.color" />
1704
+ @if (hover() !== null) {
1705
+ <circle
1706
+ class="star-chart__dot"
1707
+ r="4.5"
1708
+ [attr.cx]="x(hover()!)"
1709
+ [attr.cy]="y(line.data[hover()!] ?? 0)"
1710
+ [style.fill]="line.color"
1711
+ />
1712
+ }
1713
+ }
1714
+ }
1715
+ <!-- Hit targets: one full-height column per category, wider than the marks. -->
1716
+ @for (label of labels(); track $index; let i = $index) {
1717
+ <rect
1718
+ class="star-chart__hit"
1719
+ [attr.x]="x(i) - band() / 2"
1720
+ [attr.y]="PAD.top"
1721
+ [attr.width]="band()"
1722
+ [attr.height]="H - PAD.top - PAD.bottom"
1723
+ (mouseenter)="hover.set(i)"
1724
+ />
1725
+ }
1726
+ </svg>
1727
+ @if (hover() !== null) {
1728
+ <div
1729
+ class="star-chart__tip"
1730
+ [style.left.%]="(x(hover()!) / W) * 100"
1731
+ [style.top.%]="6"
1732
+ >
1733
+ <span class="star-chart__tip-title">{{ labels()[hover()!] }}</span>
1734
+ @for (s of drawn(); track s.label; let si = $index) {
1735
+ <span class="star-chart__tip-row">
1736
+ <span class="star-chart__swatch" [style.background]="color(si)"></span>
1737
+ {{ s.label }}: <strong>{{ cell(s, hover()!) }}</strong>
1738
+ @if (type() === 'stacked-bar' && percent()) {
1739
+ ({{ share(stack()[hover()!]?.segments?.[si]) }}%)
1740
+ }
1741
+ </span>
1742
+ }
1743
+ @if (type() === 'stacked-bar') {
1744
+ <span class="star-chart__tip-row star-chart__tip-total">
1745
+ {{ text.chartTotal }}:
1746
+ <strong>{{ format(stack()[hover()!]?.total ?? 0) }}</strong>
1747
+ </span>
1748
+ }
1749
+ </div>
1750
+ }
1751
+ }
1752
+ }
1753
+ </div>
1754
+
1755
+ <table class="star-chart__table" [class.star-sr-only]="!showTable()">
1756
+ <caption class="star-sr-only">
1757
+ {{
1758
+ title()
1759
+ }}
1760
+ </caption>
1761
+ <thead>
1762
+ <tr>
1763
+ <th scope="col">
1764
+ {{ firstHeader() }}
1765
+ </th>
1766
+ @if (round()) {
1767
+ <th scope="col">{{ series()[0]?.label ?? text.chartValue }}</th>
1768
+ <th scope="col">{{ text.chartShare }}</th>
1769
+ } @else if (kind() === 'polar') {
1770
+ <th scope="col">{{ valueName() }}</th>
1771
+ } @else if (kind() === 'scatter') {
1772
+ <th scope="col">{{ xName() }}</th>
1773
+ <th scope="col">{{ yName() }}</th>
1774
+ } @else {
1775
+ @for (s of series(); track s.label) {
1776
+ <th scope="col">{{ s.label }}</th>
1777
+ }
1778
+ @if (type() === 'stacked-bar') {
1779
+ <th scope="col">{{ text.chartTotal }}</th>
1780
+ }
1781
+ }
1782
+ </tr>
1783
+ </thead>
1784
+ <tbody>
1785
+ @if (round()) {
1786
+ @for (slice of slices(); track slice.label) {
1787
+ <tr>
1788
+ <th scope="row">{{ slice.label }}</th>
1789
+ <td>{{ format(slice.value) }}</td>
1790
+ <td>{{ slice.percent }}%</td>
1791
+ </tr>
1792
+ }
1793
+ } @else if (kind() === 'polar') {
1794
+ @for (label of labels(); track $index; let i = $index) {
1795
+ <tr>
1796
+ <th scope="row">{{ label }}</th>
1797
+ <td>{{ cell(numeric()[0], i) }}</td>
1798
+ </tr>
1799
+ }
1800
+ } @else if (kind() === 'scatter') {
1801
+ @for (row of scatterRows(); track $index) {
1802
+ <tr>
1803
+ <th scope="row">{{ row.series }}</th>
1804
+ <td>{{ precise(row.x) }}</td>
1805
+ <td>{{ precise(row.y) }}</td>
1806
+ </tr>
1807
+ }
1808
+ } @else {
1809
+ @for (label of labels(); track $index; let i = $index) {
1810
+ <tr>
1811
+ <th scope="row">{{ label }}</th>
1812
+ @for (s of numeric(); track s.label) {
1813
+ <td>{{ cell(s, i) }}</td>
1814
+ }
1815
+ @if (type() === 'stacked-bar') {
1816
+ <td>{{ format(stack()[i]?.total ?? 0) }}</td>
1817
+ }
1818
+ </tr>
1819
+ }
1820
+ }
1821
+ </tbody>
1822
+ </table>
1823
+ </figure>
1824
+ `
1825
+ }]
1826
+ }],
1827
+ propDecorators: {
1828
+ type: [{
1829
+ type: i0.Input,
1830
+ args: [{
1831
+ isSignal: true,
1832
+ alias: "type",
1833
+ required: false
1834
+ }]
1835
+ }],
1836
+ percent: [{
1837
+ type: i0.Input,
1838
+ args: [{
1839
+ isSignal: true,
1840
+ alias: "percent",
1841
+ required: false
1842
+ }]
1843
+ }],
1844
+ title: [{
1845
+ type: i0.Input,
1846
+ args: [{
1847
+ isSignal: true,
1848
+ alias: "title",
1849
+ required: true
1850
+ }]
1851
+ }],
1852
+ labels: [{
1853
+ type: i0.Input,
1854
+ args: [{
1855
+ isSignal: true,
1856
+ alias: "labels",
1857
+ required: false
1858
+ }]
1859
+ }],
1860
+ series: [{
1861
+ type: i0.Input,
1862
+ args: [{
1863
+ isSignal: true,
1864
+ alias: "series",
1865
+ required: false
1866
+ }]
1867
+ }],
1868
+ categoryLabel: [{
1869
+ type: i0.Input,
1870
+ args: [{
1871
+ isSignal: true,
1872
+ alias: "categoryLabel",
1873
+ required: false
1874
+ }]
1875
+ }],
1876
+ valueLabel: [{
1877
+ type: i0.Input,
1878
+ args: [{
1879
+ isSignal: true,
1880
+ alias: "valueLabel",
1881
+ required: false
1882
+ }]
1883
+ }],
1884
+ locale: [{
1885
+ type: i0.Input,
1886
+ args: [{
1887
+ isSignal: true,
1888
+ alias: "locale",
1889
+ required: false
1890
+ }]
1891
+ }],
1892
+ table: [{
1893
+ type: i0.Input,
1894
+ args: [{
1895
+ isSignal: true,
1896
+ alias: "table",
1897
+ required: false
1898
+ }]
1899
+ }]
1900
+ }
1901
+ });
1902
+ export { STAR_CHART_SLOTS, StarChart };
1903
+
1904
+ //# sourceMappingURL=star-ng-ui-chart.mjs.map