@trismegisto/charts 3.3.2 → 3.3.4

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.
@@ -31,6 +31,11 @@ const CHARTS_MESSAGES_EN = {
31
31
  median: 'Median',
32
32
  q3: 'Third quartile',
33
33
  max: 'Maximum',
34
+ goal: 'Target',
35
+ ranges: 'Ranges',
36
+ change: 'Change',
37
+ cumulative: 'Cumulative',
38
+ size: 'Size',
34
39
  },
35
40
  types: {
36
41
  bar: 'Bar chart',
@@ -47,6 +52,10 @@ const CHARTS_MESSAGES_EN = {
47
52
  treemap: 'Treemap',
48
53
  sankey: 'Sankey diagram',
49
54
  boxplot: 'Box plot',
55
+ sparkline: 'Sparkline',
56
+ bubble: 'Bubble chart',
57
+ bullet: 'Bullet chart',
58
+ waterfall: 'Waterfall chart',
50
59
  chart: 'Chart',
51
60
  },
52
61
  summary: {
@@ -67,6 +76,22 @@ const CHARTS_MESSAGES_EN = {
67
76
  one: '{type} with 1 item.',
68
77
  other: '{type} with {count} items.',
69
78
  },
79
+ gaugeCaption: '{type}: {value} {caption}, on a scale from {min} to {max}.',
80
+ sparkline: {
81
+ one: '{type} with 1 point: {last}.',
82
+ other: '{type} with {count} points, from {first} to {last}. Minimum {min}, maximum {max}.',
83
+ },
84
+ bulletItem: '{name}: {value}, target {target}.',
85
+ bulletItemNoTarget: '{name}: {value}.',
86
+ waterfall: {
87
+ one: '{type} with 1 step: from {start} to {end}.',
88
+ other: '{type} with {count} steps: from {start} to {end}.',
89
+ },
90
+ },
91
+ waterfall: {
92
+ increase: 'Increase',
93
+ decrease: 'Decrease',
94
+ total: 'Total',
70
95
  },
71
96
  engine: {
72
97
  legendAll: 'All',
@@ -112,6 +137,11 @@ const CHARTS_MESSAGES_ES = {
112
137
  median: 'Mediana',
113
138
  q3: 'Tercer cuartil',
114
139
  max: 'Máximo',
140
+ goal: 'Meta',
141
+ ranges: 'Rangos',
142
+ change: 'Variación',
143
+ cumulative: 'Acumulado',
144
+ size: 'Tamaño',
115
145
  },
116
146
  types: {
117
147
  bar: 'Gráfico de barras',
@@ -128,6 +158,10 @@ const CHARTS_MESSAGES_ES = {
128
158
  treemap: 'Mapa de árbol',
129
159
  sankey: 'Diagrama de Sankey',
130
160
  boxplot: 'Diagrama de caja',
161
+ sparkline: 'Minigráfico',
162
+ bubble: 'Gráfico de burbujas',
163
+ bullet: 'Gráfico de bala',
164
+ waterfall: 'Gráfico de cascada',
131
165
  chart: 'Gráfico',
132
166
  },
133
167
  summary: {
@@ -148,6 +182,22 @@ const CHARTS_MESSAGES_ES = {
148
182
  one: '{type} con 1 elemento.',
149
183
  other: '{type} con {count} elementos.',
150
184
  },
185
+ gaugeCaption: '{type}: {value} {caption}, en una escala de {min} a {max}.',
186
+ sparkline: {
187
+ one: '{type} con 1 punto: {last}.',
188
+ other: '{type} con {count} puntos, de {first} a {last}. Mínimo {min}, máximo {max}.',
189
+ },
190
+ bulletItem: '{name}: {value}, meta {target}.',
191
+ bulletItemNoTarget: '{name}: {value}.',
192
+ waterfall: {
193
+ one: '{type} con 1 etapa: de {start} a {end}.',
194
+ other: '{type} con {count} etapas: de {start} a {end}.',
195
+ },
196
+ },
197
+ waterfall: {
198
+ increase: 'Aumento',
199
+ decrease: 'Disminución',
200
+ total: 'Total',
151
201
  },
152
202
  engine: {
153
203
  legendAll: 'Todos',
@@ -193,6 +243,11 @@ const CHARTS_MESSAGES_PT_BR = {
193
243
  median: 'Mediana',
194
244
  q3: '3º quartil',
195
245
  max: 'Máximo',
246
+ goal: 'Meta',
247
+ ranges: 'Faixas',
248
+ change: 'Variação',
249
+ cumulative: 'Acumulado',
250
+ size: 'Tamanho',
196
251
  },
197
252
  types: {
198
253
  bar: 'Gráfico de barras',
@@ -209,6 +264,10 @@ const CHARTS_MESSAGES_PT_BR = {
209
264
  treemap: 'Mapa de árvore',
210
265
  sankey: 'Diagrama de Sankey',
211
266
  boxplot: 'Diagrama de caixa',
267
+ sparkline: 'Minigráfico',
268
+ bubble: 'Gráfico de bolhas',
269
+ bullet: 'Gráfico de bala',
270
+ waterfall: 'Gráfico de cascata',
212
271
  chart: 'Gráfico',
213
272
  },
214
273
  summary: {
@@ -229,6 +288,22 @@ const CHARTS_MESSAGES_PT_BR = {
229
288
  one: '{type} com 1 item.',
230
289
  other: '{type} com {count} itens.',
231
290
  },
291
+ gaugeCaption: '{type}: {value} {caption}, numa escala de {min} a {max}.',
292
+ sparkline: {
293
+ one: '{type} com 1 ponto: {last}.',
294
+ other: '{type} com {count} pontos, de {first} a {last}. Mínimo {min}, máximo {max}.',
295
+ },
296
+ bulletItem: '{name}: {value}, meta {target}.',
297
+ bulletItemNoTarget: '{name}: {value}.',
298
+ waterfall: {
299
+ one: '{type} com 1 etapa: de {start} a {end}.',
300
+ other: '{type} com {count} etapas: de {start} a {end}.',
301
+ },
302
+ },
303
+ waterfall: {
304
+ increase: 'Aumento',
305
+ decrease: 'Redução',
306
+ total: 'Total',
232
307
  },
233
308
  engine: {
234
309
  legendAll: 'Todos',
@@ -4304,8 +4379,8 @@ class Storage {
4304
4379
  * Licensed under the BSD 3-Clause License. The full license text is in
4305
4380
  * LICENSES/zrender-BSD-3-Clause.txt at the root of this package.
4306
4381
  */
4307
- let requestAnimationFrame;
4308
- requestAnimationFrame = (env.hasGlobalWindow
4382
+ let requestAnimationFrame$1;
4383
+ requestAnimationFrame$1 = (env.hasGlobalWindow
4309
4384
  && ((window.requestAnimationFrame && window.requestAnimationFrame.bind(window))
4310
4385
  // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809
4311
4386
  || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))
@@ -4314,7 +4389,7 @@ requestAnimationFrame = (env.hasGlobalWindow
4314
4389
  || window.webkitRequestAnimationFrame)) || function (func) {
4315
4390
  return setTimeout(func, 16);
4316
4391
  };
4317
- var requestAnimationFrame$1 = requestAnimationFrame;
4392
+ var requestAnimationFrame$2 = requestAnimationFrame$1;
4318
4393
 
4319
4394
  /*
4320
4395
  * Copyright (c) 2017, Baidu Inc.
@@ -7024,11 +7099,11 @@ class Animation extends Eventful {
7024
7099
  this._running = true;
7025
7100
  function step() {
7026
7101
  if (self._running) {
7027
- requestAnimationFrame$1(step);
7102
+ requestAnimationFrame$2(step);
7028
7103
  !self._paused && self.update();
7029
7104
  }
7030
7105
  }
7031
- requestAnimationFrame$1(step);
7106
+ requestAnimationFrame$2(step);
7032
7107
  }
7033
7108
  /**
7034
7109
  * Start animation.
@@ -75203,6 +75278,19 @@ function resolveColor(probe, token) {
75203
75278
  const value = getComputedStyle(probe).color;
75204
75279
  return value && !value.includes('var(') ? value : undefined;
75205
75280
  }
75281
+ /** Um token de cor resolvido para `rgb(...)` no elemento (sonda temporária); `undefined` se não resolver. */
75282
+ function resolveTokenColor(host, token) {
75283
+ const probe = host.ownerDocument.createElement('span');
75284
+ probe.setAttribute('aria-hidden', 'true');
75285
+ probe.style.display = 'none';
75286
+ host.appendChild(probe);
75287
+ try {
75288
+ return resolveColor(probe, token);
75289
+ }
75290
+ finally {
75291
+ probe.remove();
75292
+ }
75293
+ }
75206
75294
  function readToken(host, token) {
75207
75295
  const value = getComputedStyle(host).getPropertyValue(token).trim();
75208
75296
  return value || undefined;
@@ -75255,7 +75343,17 @@ function readChartTheme(host, forced = false) {
75255
75343
  radar: { axisName: { color: muted }, axisLine: { lineStyle: { color: divider } }, splitLine: { lineStyle: { color: divider } } },
75256
75344
  calendar: { dayLabel: { color: muted }, monthLabel: { color: muted }, yearLabel: { color: muted }, splitLine: { lineStyle: { color: border } }, itemStyle: { borderColor: surface } },
75257
75345
  visualMap: { textStyle: { color: muted }, inRange: sequential.length ? { color: sequential } : undefined },
75258
- gauge: { axisLabel: { color: muted }, title: { color: muted }, detail: { color: text }, axisLine: { lineStyle: { color: [[1, divider]] } } },
75346
+ gauge: {
75347
+ axisLabel: { color: muted },
75348
+ title: { color: muted },
75349
+ detail: { color: text },
75350
+ axisLine: { lineStyle: { color: [[1, divider]] } },
75351
+ // Escala e agulha do medidor: marcas neutras, agulha na cor do texto com o pino recortado na superfície.
75352
+ splitLine: { lineStyle: { color: muted } },
75353
+ axisTick: { lineStyle: { color: border } },
75354
+ pointer: { itemStyle: { color: text } },
75355
+ anchor: { itemStyle: { color: text, borderColor: surface } },
75356
+ },
75259
75357
  pie: { itemStyle: { borderColor: surface } },
75260
75358
  funnel: { itemStyle: { borderColor: surface } },
75261
75359
  treemap: { itemStyle: { borderColor: surface }, upperLabel: { color: text } },
@@ -75340,6 +75438,12 @@ class HmChartComponent {
75340
75438
  #resize;
75341
75439
  #scope;
75342
75440
  #cursor;
75441
+ /**
75442
+ * O tema foi lido com o gráfico fora do documento (conteúdo projetado num painel que ainda não está na
75443
+ * página, como um `hm-tab` sem `hmTabContent`): os tokens não resolvem e as cores saem vazias. Relido na
75444
+ * primeira medição com o gráfico já no documento; quem nasce visível nunca passa por aqui.
75445
+ */
75446
+ #themeStale;
75343
75447
  #cleanups;
75344
75448
  #locale;
75345
75449
  #finalOption;
@@ -75359,6 +75463,12 @@ class HmChartComponent {
75359
75463
  this.#resize = null;
75360
75464
  this.#scope = null;
75361
75465
  this.#cursor = -1;
75466
+ /**
75467
+ * O tema foi lido com o gráfico fora do documento (conteúdo projetado num painel que ainda não está na
75468
+ * página, como um `hm-tab` sem `hmTabContent`): os tokens não resolvem e as cores saem vazias. Relido na
75469
+ * primeira medição com o gráfico já no documento; quem nasce visível nunca passa por aqui.
75470
+ */
75471
+ this.#themeStale = false;
75362
75472
  this.#cleanups = [];
75363
75473
  this.announcement = signal('', ...(ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []));
75364
75474
  this.#locale = computed(() => engineLocale(this.#i18n.messages(), this.#i18n.locale()), ...(ngDevMode ? [{ debugName: "#locale" }] : /* istanbul ignore next */ []));
@@ -75376,7 +75486,11 @@ class HmChartComponent {
75376
75486
  this.#watchMedia('(prefers-reduced-motion: reduce)', this.#reducedMotion);
75377
75487
  this.#watchMedia('(forced-colors: active)', this.#forcedColors);
75378
75488
  if (typeof ResizeObserver !== 'undefined') {
75379
- this.#resize = new ResizeObserver(() => this.#chart?.resize());
75489
+ this.#resize = new ResizeObserver(() => {
75490
+ if (this.#themeStale && host.isConnected)
75491
+ this.#applyTheme();
75492
+ this.#chart?.resize();
75493
+ });
75380
75494
  this.#resize.observe(host);
75381
75495
  }
75382
75496
  this.#watchScope(host);
@@ -75390,7 +75504,7 @@ class HmChartComponent {
75390
75504
  untracked(() => {
75391
75505
  const host = this.#host.nativeElement;
75392
75506
  this.#chart?.dispose();
75393
- this.#chart = init(host, readChartTheme(host, this.#forcedColors()), { locale });
75507
+ this.#chart = init(host, this.#readTheme(), { locale });
75394
75508
  this.#chart.setOption(this.#finalOption(), { notMerge: true });
75395
75509
  });
75396
75510
  });
@@ -75399,8 +75513,8 @@ class HmChartComponent {
75399
75513
  untracked(() => this.#chart?.setOption(option, { notMerge: true }));
75400
75514
  });
75401
75515
  effect(() => {
75402
- const forced = this.#forcedColors();
75403
- untracked(() => this.#chart?.setTheme(readChartTheme(this.#host.nativeElement, forced)));
75516
+ this.#forcedColors();
75517
+ untracked(() => this.#applyTheme());
75404
75518
  });
75405
75519
  inject(DestroyRef).onDestroy(() => {
75406
75520
  this.#cleanups.forEach((fn) => fn());
@@ -75465,6 +75579,16 @@ class HmChartComponent {
75465
75579
  chart.dispatchAction({ type: 'showTip', seriesIndex: point.seriesIndex, dataIndex: point.dataIndex });
75466
75580
  this.announcement.set(point.text);
75467
75581
  }
75582
+ /** Tema lido dos tokens no elemento; marca para reler se o gráfico ainda não está no documento. */
75583
+ #readTheme() {
75584
+ const host = this.#host.nativeElement;
75585
+ this.#themeStale = !host.isConnected;
75586
+ return readChartTheme(host, this.#forcedColors());
75587
+ }
75588
+ #applyTheme() {
75589
+ if (this.#chart)
75590
+ this.#chart.setTheme(this.#readTheme());
75591
+ }
75468
75592
  #watchMedia(query, target) {
75469
75593
  const list = media(query);
75470
75594
  if (!list)
@@ -75488,7 +75612,7 @@ class HmChartComponent {
75488
75612
  pending = true;
75489
75613
  queueMicrotask(() => {
75490
75614
  pending = false;
75491
- this.#chart?.setTheme(readChartTheme(host, this.#forcedColors()));
75615
+ this.#applyTheme();
75492
75616
  });
75493
75617
  });
75494
75618
  this.#scope.observe(host.ownerDocument.documentElement, {
@@ -75524,6 +75648,8 @@ class HmChartFrameComponent {
75524
75648
  this.label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
75525
75649
  this.description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
75526
75650
  this.height = input('', ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
75651
+ /** Mostra o botão "Ver como tabela". Desligado (minigráfico), a tabela fica só na árvore de acessibilidade. */
75652
+ this.tableToggle = input(true, ...(ngDevMode ? [{ debugName: "tableToggle" }] : /* istanbul ignore next */ []));
75527
75653
  /** Mostra a tabela no lugar do gráfico. */
75528
75654
  this.showTable = model(false, ...(ngDevMode ? [{ debugName: "showTable" }] : /* istanbul ignore next */ []));
75529
75655
  this.m = inject(ChartsI18nService).messages;
@@ -75536,12 +75662,14 @@ class HmChartFrameComponent {
75536
75662
  return this.view().table.align?.[index] ?? 'start';
75537
75663
  }
75538
75664
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmChartFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
75539
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HmChartFrameComponent, isStandalone: true, selector: "hm-chart-frame", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, showTable: { classPropertyName: "showTable", publicName: "showTable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { showTable: "showTableChange" }, host: { classAttribute: "hm-chart-frame" }, ngImport: i0, template: `
75665
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HmChartFrameComponent, isStandalone: true, selector: "hm-chart-frame", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, tableToggle: { classPropertyName: "tableToggle", publicName: "tableToggle", isSignal: true, isRequired: false, transformFunction: null }, showTable: { classPropertyName: "showTable", publicName: "showTable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { showTable: "showTableChange" }, host: { classAttribute: "hm-chart-frame" }, ngImport: i0, template: `
75666
+ @if (tableToggle()) {
75540
75667
  <div class="hm-chart-frame__bar">
75541
75668
  <button type="button" class="hm-btn hm-btn--minimal hm-btn--small" (click)="showTable.set(!showTable())">
75542
75669
  {{ showTable() ? m().frame.showChart : m().frame.showTable }}
75543
75670
  </button>
75544
75671
  </div>
75672
+ }
75545
75673
  <hm-chart
75546
75674
  [class.hm-chart-frame__off]="showTable()"
75547
75675
  [option]="view().option"
@@ -75590,11 +75718,13 @@ class HmChartFrameComponent {
75590
75718
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmChartFrameComponent, decorators: [{
75591
75719
  type: Component,
75592
75720
  args: [{ selector: 'hm-chart-frame', standalone: true, imports: [HmChartComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
75721
+ @if (tableToggle()) {
75593
75722
  <div class="hm-chart-frame__bar">
75594
75723
  <button type="button" class="hm-btn hm-btn--minimal hm-btn--small" (click)="showTable.set(!showTable())">
75595
75724
  {{ showTable() ? m().frame.showChart : m().frame.showTable }}
75596
75725
  </button>
75597
75726
  </div>
75727
+ }
75598
75728
  <hm-chart
75599
75729
  [class.hm-chart-frame__off]="showTable()"
75600
75730
  [option]="view().option"
@@ -75639,7 +75769,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
75639
75769
  </table>
75640
75770
  </div>
75641
75771
  `, host: { class: 'hm-chart-frame' }, styles: [":host{display:flex;flex-direction:column;inline-size:100%;gap:var(--hm-space-xxxs);min-inline-size:0}.hm-chart-frame__bar{display:flex;justify-content:flex-end}.hm-chart-frame__off{display:none}.hm-chart-frame__table:not(.hm-visually-hidden){overflow:auto;max-block-size:calc(var(--hm-control-height) * 12)}.hm-chart-frame__table caption{text-align:start;color:var(--hm-muted);font-size:var(--hm-font-size-sm);padding-block-end:var(--hm-space-xxxs)}.hm-chart-frame__num{text-align:end;font-variant-numeric:tabular-nums}\n"] }]
75642
- }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], showTable: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTable", required: false }] }, { type: i0.Output, args: ["showTableChange"] }] } });
75772
+ }], propDecorators: { view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], tableToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableToggle", required: false }] }], showTable: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTable", required: false }] }, { type: i0.Output, args: ["showTableChange"] }] } });
75643
75773
 
75644
75774
  /** Tabela categoria × série (barras, linhas). */
75645
75775
  function categoryTable(ctx, categories, series) {
@@ -75702,7 +75832,7 @@ class HmBarChartComponent extends HmChartBase {
75702
75832
  };
75703
75833
  }
75704
75834
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBarChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
75705
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmBarChartComponent, isStandalone: true, selector: "hm-bar-chart", inputs: { categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75835
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmBarChartComponent, isStandalone: true, selector: "hm-bar-chart", inputs: { categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75706
75836
  }
75707
75837
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBarChartComponent, decorators: [{
75708
75838
  type: Component,
@@ -75750,7 +75880,7 @@ class HmLineChartComponent extends HmChartBase {
75750
75880
  };
75751
75881
  }
75752
75882
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmLineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
75753
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmLineChartComponent, isStandalone: true, selector: "hm-line-chart", inputs: { categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null }, smooth: { classPropertyName: "smooth", publicName: "smooth", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75883
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmLineChartComponent, isStandalone: true, selector: "hm-line-chart", inputs: { categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null }, smooth: { classPropertyName: "smooth", publicName: "smooth", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75754
75884
  }
75755
75885
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmLineChartComponent, decorators: [{
75756
75886
  type: Component,
@@ -75797,7 +75927,7 @@ class HmPieChartComponent extends HmChartBase {
75797
75927
  };
75798
75928
  }
75799
75929
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmPieChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
75800
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmPieChartComponent, isStandalone: true, selector: "hm-pie-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, donut: { classPropertyName: "donut", publicName: "donut", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75930
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmPieChartComponent, isStandalone: true, selector: "hm-pie-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, donut: { classPropertyName: "donut", publicName: "donut", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75801
75931
  }
75802
75932
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmPieChartComponent, decorators: [{
75803
75933
  type: Component,
@@ -75868,7 +75998,7 @@ class HmHeatmapChartComponent extends HmChartBase {
75868
75998
  };
75869
75999
  }
75870
76000
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmHeatmapChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
75871
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmHeatmapChartComponent, isStandalone: true, selector: "hm-heatmap-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, xCategories: { classPropertyName: "xCategories", publicName: "xCategories", isSignal: true, isRequired: false, transformFunction: null }, yCategories: { classPropertyName: "yCategories", publicName: "yCategories", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76001
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmHeatmapChartComponent, isStandalone: true, selector: "hm-heatmap-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, xCategories: { classPropertyName: "xCategories", publicName: "xCategories", isSignal: true, isRequired: false, transformFunction: null }, yCategories: { classPropertyName: "yCategories", publicName: "yCategories", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75872
76002
  }
75873
76003
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmHeatmapChartComponent, decorators: [{
75874
76004
  type: Component,
@@ -75953,7 +76083,7 @@ class HmCalendarHeatmapComponent extends HmChartBase {
75953
76083
  };
75954
76084
  }
75955
76085
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmCalendarHeatmapComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
75956
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmCalendarHeatmapComponent, isStandalone: true, selector: "hm-calendar-heatmap", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76086
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmCalendarHeatmapComponent, isStandalone: true, selector: "hm-calendar-heatmap", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
75957
76087
  }
75958
76088
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmCalendarHeatmapComponent, decorators: [{
75959
76089
  type: Component,
@@ -75973,7 +76103,13 @@ function weekStart(locale) {
75973
76103
  return /^(pt|en-US|es-MX)/.test(locale) ? 0 : 1;
75974
76104
  }
75975
76105
 
75976
- /** Relação entre duas medidas (preço × volume, prazo × satisfação), uma ou várias séries. */
76106
+ /** Diâmetro (px) do menor e do maior ponto no gráfico de bolhas. */
76107
+ const BUBBLE_MIN = 8;
76108
+ const BUBBLE_MAX = 44;
76109
+ /**
76110
+ * Relação entre duas medidas (preço × volume, prazo × satisfação), uma ou várias séries. Com `size`
76111
+ * nos pontos, vira gráfico de bolhas (a área de cada bolha mostra uma terceira medida).
76112
+ */
75977
76113
  class HmScatterChartComponent extends HmChartBase {
75978
76114
  constructor() {
75979
76115
  super(...arguments);
@@ -75982,16 +76118,26 @@ class HmScatterChartComponent extends HmChartBase {
75982
76118
  this.xLabel = input('', ...(ngDevMode ? [{ debugName: "xLabel" }] : /* istanbul ignore next */ []));
75983
76119
  /** Nome do eixo vertical (texto do app). */
75984
76120
  this.yLabel = input('', ...(ngDevMode ? [{ debugName: "yLabel" }] : /* istanbul ignore next */ []));
76121
+ /** Nome da medida do tamanho das bolhas (texto do app); padrão "Tamanho". */
76122
+ this.sizeLabel = input('', ...(ngDevMode ? [{ debugName: "sizeLabel" }] : /* istanbul ignore next */ []));
75985
76123
  }
75986
76124
  build(ctx) {
75987
76125
  const series = this.series();
75988
76126
  const xName = this.xLabel() || ctx.m.columns.x;
75989
76127
  const yName = this.yLabel() || ctx.m.columns.y;
75990
76128
  const hasLegend = series.length > 1;
75991
- const describe = (s, p) => `${p.name ?? s.name}: ${xName} ${ctx.num(p.x)}, ${yName} ${ctx.num(p.y)}`;
76129
+ const sizeName = this.sizeLabel() || ctx.m.columns.size;
76130
+ const sizes = series.flatMap((s) => s.data.map((p) => p.size)).filter((v) => v != null && Number.isFinite(v) && v >= 0);
76131
+ const bubble = sizes.length > 0;
76132
+ const biggest = Math.max(0, ...sizes);
76133
+ // Área proporcional ao valor: o diâmetro cresce com a raiz quadrada, entre o ponto comum e uma bolha grande.
76134
+ const radius = (v) => v == null || !Number.isFinite(v) || v < 0 || biggest === 0 ? BUBBLE_MIN : BUBBLE_MIN + (BUBBLE_MAX - BUBBLE_MIN) * Math.sqrt(v / biggest);
76135
+ const describe = (s, p) => `${p.name ?? s.name}: ${xName} ${ctx.num(p.x)}, ${yName} ${ctx.num(p.y)}` + (bubble ? `, ${sizeName} ${ctx.num(p.size)}` : '');
75992
76136
  return {
75993
76137
  option: {
75994
- grid: { ...gridOption(hasLegend && ctx.legend), top: 36 },
76138
+ // Bolhas: folga no fim dos eixos para a bolha da ponta não ser cortada. Com nome no eixo X (o `containLabel` não
76139
+ // conta o nome), espaço entre ele e a legenda.
76140
+ grid: { ...gridOption(hasLegend && ctx.legend), top: 36, ...(bubble || this.xLabel() ? { bottom: hasLegend && ctx.legend ? 58 : 30 } : {}) },
75995
76141
  tooltip: {
75996
76142
  ...tooltipOption(ctx, 'item'),
75997
76143
  formatter: (p) => {
@@ -76001,71 +76147,348 @@ class HmScatterChartComponent extends HmChartBase {
76001
76147
  },
76002
76148
  },
76003
76149
  legend: legendOption(ctx, hasLegend),
76004
- xAxis: { type: 'value', name: this.xLabel(), nameLocation: 'middle', nameGap: 30, scale: true, axisLabel: { formatter: (v) => ctx.num(v) } },
76005
- yAxis: { type: 'value', name: this.yLabel(), scale: true, axisLabel: { formatter: (v) => ctx.num(v) } },
76150
+ xAxis: { type: 'value', name: this.xLabel(), nameLocation: 'middle', nameGap: 30, scale: true, axisLabel: { formatter: (v) => ctx.num(v) }, ...(bubble ? { boundaryGap: ['8%', '8%'] } : {}) },
76151
+ yAxis: { type: 'value', name: this.yLabel(), scale: true, axisLabel: { formatter: (v) => ctx.num(v) }, ...(bubble ? { boundaryGap: ['12%', '12%'] } : {}) },
76006
76152
  series: series.map((s) => ({
76007
76153
  type: 'scatter',
76008
76154
  name: s.name,
76009
- symbolSize: 9,
76155
+ symbolSize: bubble ? (_, params) => radius(s.data[params.dataIndex]?.size) : 9,
76010
76156
  data: s.data.map((p) => [p.x, p.y]),
76157
+ ...(bubble ? { itemStyle: { opacity: 0.72 } } : {}),
76011
76158
  emphasis: { focus: 'series' },
76012
76159
  })),
76013
76160
  },
76014
- summary: seriesSummary(ctx, 'scatter', series.length, series.reduce((n, s) => n + s.data.length, 0), series.flatMap((s) => s.data.map((p) => p.y))),
76161
+ summary: seriesSummary(ctx, bubble ? 'bubble' : 'scatter', series.length, series.reduce((n, s) => n + s.data.length, 0), series.flatMap((s) => s.data.map((p) => p.y))),
76015
76162
  table: {
76016
- columns: [ctx.m.columns.series, xName, yName],
76017
- align: ['start', 'end', 'end'],
76163
+ columns: bubble ? [ctx.m.columns.series, xName, yName, sizeName] : [ctx.m.columns.series, xName, yName],
76164
+ align: bubble ? ['start', 'end', 'end', 'end'] : ['start', 'end', 'end'],
76018
76165
  rows: series.flatMap((s) => s.data.map((p) => ({
76019
76166
  header: p.name ? `${s.name} · ${p.name}` : s.name,
76020
- cells: [ctx.num(p.x), ctx.num(p.y)],
76167
+ cells: bubble ? [ctx.num(p.x), ctx.num(p.y), ctx.num(p.size)] : [ctx.num(p.x), ctx.num(p.y)],
76021
76168
  }))),
76022
76169
  },
76023
76170
  points: series.flatMap((s, si) => s.data.map((p, di) => ({ seriesIndex: si, dataIndex: di, text: describe(s, p) }))),
76024
76171
  };
76025
76172
  }
76026
76173
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmScatterChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76027
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmScatterChartComponent, isStandalone: true, selector: "hm-scatter-chart", inputs: { series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, xLabel: { classPropertyName: "xLabel", publicName: "xLabel", isSignal: true, isRequired: false, transformFunction: null }, yLabel: { classPropertyName: "yLabel", publicName: "yLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76174
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmScatterChartComponent, isStandalone: true, selector: "hm-scatter-chart", inputs: { series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null }, xLabel: { classPropertyName: "xLabel", publicName: "xLabel", isSignal: true, isRequired: false, transformFunction: null }, yLabel: { classPropertyName: "yLabel", publicName: "yLabel", isSignal: true, isRequired: false, transformFunction: null }, sizeLabel: { classPropertyName: "sizeLabel", publicName: "sizeLabel", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76028
76175
  }
76029
76176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmScatterChartComponent, decorators: [{
76030
76177
  type: Component,
76031
76178
  args: [{ selector: 'hm-scatter-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: CHART_TEMPLATE, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
76032
- }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: true }] }], xLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "xLabel", required: false }] }], yLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yLabel", required: false }] }] } });
76179
+ }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: true }] }], xLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "xLabel", required: false }] }], yLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yLabel", required: false }] }], sizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sizeLabel", required: false }] }] } });
76033
76180
 
76034
- /** Um valor numa escala (meta atingida, ocupação, SLA). Para vários indicadores, vários medidores. */
76181
+ // Geometria do medidor: raio, centro e posição de cada rótulo da escala, calculados a partir do
76182
+ // tamanho real do gráfico e do tamanho das fontes (lidos dos tokens no elemento). Sem framework e
76183
+ // sem DOM: só números, para ser testável e portável.
76184
+ /** Ângulos do arco no sistema do motor (graus, anti-horário a partir das 3 horas): 240° com a abertura embaixo. */
76185
+ const GAUGE_START_ANGLE = 210;
76186
+ const GAUGE_END_ANGLE = -30;
76187
+ const SWEEP = GAUGE_START_ANGLE - GAUGE_END_ANGLE;
76188
+ /** Largura aproximada de um texto (média de glifos de uma fonte sem serifa com algarismos tabulares). */
76189
+ function textWidth(text, font) {
76190
+ return text.length * font * 0.6;
76191
+ }
76192
+ /** Ângulo (graus do motor) da marca `i` de `n`. */
76193
+ function tickAngle(i, n) {
76194
+ return GAUGE_START_ANGLE - (SWEEP * i) / n;
76195
+ }
76196
+ /** Mede tudo para um raio `r` com o centro em (0,0): devolve as posições e a caixa ocupada. */
76197
+ function measure(r, input) {
76198
+ const { box, labels } = input;
76199
+ const labelFont = box.smallFont;
76200
+ const captionFont = box.smallFont;
76201
+ const arcWidth = Math.max(6, r * 0.1);
76202
+ const tickGap = input.ticks ? Math.max(2, r * 0.045) : 0;
76203
+ const majorLength = input.ticks ? Math.max(4, r * 0.08) : 0;
76204
+ const minorLength = majorLength * 0.55;
76205
+ const labelGap = labelFont * 0.45;
76206
+ const labelRadius = r + tickGap + majorLength + labelGap;
76207
+ const labelHeight = labelFont * 1.2;
76208
+ const extent = { minX: -r, maxX: r, minY: -r, maxY: r * Math.sin((30 * Math.PI) / 180) + arcWidth / 2 };
76209
+ const grow = (x0, x1, y0, y1) => {
76210
+ extent.minX = Math.min(extent.minX, x0);
76211
+ extent.maxX = Math.max(extent.maxX, x1);
76212
+ extent.minY = Math.min(extent.minY, y0);
76213
+ extent.maxY = Math.max(extent.maxY, y1);
76214
+ };
76215
+ const n = Math.max(1, labels.length - 1);
76216
+ const placed = [];
76217
+ labels.forEach((text, i) => {
76218
+ if (text == null || text === '')
76219
+ return;
76220
+ const a = (tickAngle(i, n) * Math.PI) / 180;
76221
+ const ux = Math.cos(a);
76222
+ const uy = -Math.sin(a);
76223
+ const w = textWidth(text, labelFont);
76224
+ // Centro do rótulo afastado do arco pela metade da caixa na direção do raio: o texto fica
76225
+ // sempre do lado de fora, sem encostar nas marcas, em qualquer ângulo.
76226
+ const reach = labelRadius + Math.abs(ux) * (w / 2) + Math.abs(uy) * (labelHeight / 2);
76227
+ const dx = ux * reach;
76228
+ const dy = uy * reach;
76229
+ placed.push({ text, dx, dy });
76230
+ grow(dx - w / 2, dx + w / 2, dy - labelHeight / 2, dy + labelHeight / 2);
76231
+ });
76232
+ const hubSize = input.needle ? Math.max(8, r * 0.13) : 0;
76233
+ const valueFont = Math.min(box.baseFont * 3, Math.max(box.baseFont * 1.35, r * (input.needle ? 0.26 : 0.32)));
76234
+ const valueOffset = input.needle ? Math.max(r * 0.34, hubSize / 2 + valueFont * 0.75) : input.hasCaption ? -valueFont * 0.1 : 0;
76235
+ const captionOffset = valueOffset + valueFont * 0.62 + captionFont * 0.95;
76236
+ const valueW = textWidth(input.valueText, valueFont);
76237
+ grow(-valueW / 2, valueW / 2, valueOffset - valueFont * 0.6, valueOffset + valueFont * 0.6);
76238
+ if (input.hasCaption)
76239
+ grow(-r * 0.8, r * 0.8, captionOffset - captionFont * 0.7, captionOffset + captionFont * 0.7);
76240
+ return {
76241
+ layout: {
76242
+ radius: r,
76243
+ arcWidth,
76244
+ tickGap,
76245
+ majorLength,
76246
+ minorLength,
76247
+ labelFont,
76248
+ valueFont,
76249
+ captionFont,
76250
+ valueOffset,
76251
+ captionOffset,
76252
+ needleLength: r - arcWidth * 0.55,
76253
+ needleWidth: Math.max(3, r * 0.045),
76254
+ hubSize,
76255
+ labels: placed,
76256
+ },
76257
+ extent,
76258
+ };
76259
+ }
76260
+ /**
76261
+ * Maior raio em que arco, escala, valor e legenda cabem na caixa, com o conjunto centralizado.
76262
+ * Caixa sem tamanho (ainda não medida, testes em jsdom): `null`, e o componente usa porcentagens.
76263
+ */
76264
+ function gaugeLayout(input) {
76265
+ const { width, height } = input.box;
76266
+ if (!(width > 0 && height > 0))
76267
+ return null;
76268
+ const pad = Math.max(2, input.box.smallFont * 0.25);
76269
+ const availW = width - pad * 2;
76270
+ const availH = height - pad * 2;
76271
+ const fits = (r) => {
76272
+ const { extent } = measure(r, input);
76273
+ return extent.maxX - extent.minX <= availW && extent.maxY - extent.minY <= availH;
76274
+ };
76275
+ let lo = 4;
76276
+ let hi = Math.max(lo, Math.min(availW, availH));
76277
+ if (!fits(lo))
76278
+ hi = lo;
76279
+ for (let i = 0; i < 24 && hi - lo > 0.25; i++) {
76280
+ const mid = (lo + hi) / 2;
76281
+ if (fits(mid))
76282
+ lo = mid;
76283
+ else
76284
+ hi = mid;
76285
+ }
76286
+ const { layout, extent } = measure(lo, input);
76287
+ const cx = pad + (availW - (extent.maxX - extent.minX)) / 2 - extent.minX;
76288
+ const cy = pad + (availH - (extent.maxY - extent.minY)) / 2 - extent.minY;
76289
+ return { ...layout, cx, cy };
76290
+ }
76291
+ /**
76292
+ * Quantas marcas maiores e de quantas em quantas há rótulo, sem rótulos se atropelando. `step` é o
76293
+ * intervalo pedido (na unidade do valor); inválido ou com marcas demais, a escala cai em 10 partes.
76294
+ */
76295
+ function gaugeScale(min, max, step) {
76296
+ const span = max - min;
76297
+ if (step && step > 0 && span > 0) {
76298
+ const splits = span / step;
76299
+ if (Math.abs(splits - Math.round(splits)) < 1e-6 && Math.round(splits) >= 1 && Math.round(splits) <= 24) {
76300
+ return { splits: Math.round(splits) };
76301
+ }
76302
+ }
76303
+ return { splits: 10 };
76304
+ }
76305
+ /**
76306
+ * Menor passo de rótulo (divisor de `splits`, para a última marca sempre ter rótulo) em que os
76307
+ * rótulos não se encostam ao longo do arco de raio `radius`.
76308
+ */
76309
+ function labelEvery(splits, radius, labelWidth, font) {
76310
+ const spacing = ((SWEEP * Math.PI) / 180 / splits) * radius;
76311
+ const need = labelWidth + font * 0.8;
76312
+ for (let k = 1; k <= splits; k++) {
76313
+ if (splits % k !== 0)
76314
+ continue;
76315
+ if (spacing * k >= need)
76316
+ return k;
76317
+ }
76318
+ return splits;
76319
+ }
76320
+
76321
+ /** Duração do preenchimento animado (ms): a mesma para o arco, a agulha e o número. */
76322
+ const DURATION = 900;
76323
+ /** Agulha fina com as pontas arredondadas (caminho na grade do motor, esticado até o comprimento pedido). */
76324
+ const NEEDLE_PATH = 'path://M2.9,0.7L2.9,0.7c1.4,0,2.6,1.2,2.6,2.6v115c0,1.4-1.2,2.6-2.6,2.6l0,0c-1.4,0-2.6-1.2-2.6-2.6V3.3C0.3,1.9,1.4,0.7,2.9,0.7z';
76325
+ /** Lê o tamanho de fonte de um token (`--hm-font-size-*`) em px, resolvido no elemento. */
76326
+ function tokenFont(host, token, fallback) {
76327
+ const probe = host.ownerDocument.createElement('span');
76328
+ probe.setAttribute('aria-hidden', 'true');
76329
+ probe.style.cssText = `position:absolute;visibility:hidden;font-size:var(${token})`;
76330
+ host.appendChild(probe);
76331
+ try {
76332
+ const px = parseFloat(getComputedStyle(probe).fontSize);
76333
+ return Number.isFinite(px) && px > 0 ? px : fallback;
76334
+ }
76335
+ finally {
76336
+ probe.remove();
76337
+ }
76338
+ }
76339
+ /**
76340
+ * Um valor numa escala (meta atingida, ocupação, SLA). Para vários indicadores, vários medidores.
76341
+ * Arco de 240° com a escala por fora, agulha e valor no centro; ao aparecer e a cada troca de valor,
76342
+ * o arco preenche animado do valor anterior até o novo, com a agulha e o número acompanhando.
76343
+ */
76035
76344
  class HmGaugeChartComponent extends HmChartBase {
76345
+ /**
76346
+ * Tamanho medido do gráfico e das fontes (px). `undefined` até a primeira medição: até lá o motor
76347
+ * recebe só a moldura vazia, para a animação de entrada começar uma vez só, já na geometria final
76348
+ * (um primeiro desenho provisório recriaria a agulha no meio do caminho, fora de compasso com o número).
76349
+ */
76350
+ #box;
76351
+ /**
76352
+ * Valor desenhado agora (arco, agulha e número). A animação é do próprio componente, quadro a quadro,
76353
+ * com o motor sem animação: assim os três saem sempre do mesmo número, mesmo que o motor redesenhe no
76354
+ * meio do caminho (troca de tema, de tamanho), o que faria a agulha recomeçar e o número não.
76355
+ */
76356
+ #shown;
76357
+ #target;
76358
+ #frame;
76036
76359
  constructor() {
76037
- super(...arguments);
76360
+ super();
76038
76361
  this.value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
76039
76362
  this.min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
76040
76363
  this.max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
76364
+ /**
76365
+ * Preenche o arco animado ao aparecer e a cada troca de valor (do valor anterior até o novo).
76366
+ * Com `prefers-reduced-motion`, nunca anima. O resumo e a tabela já trazem o valor final.
76367
+ */
76368
+ this.animated = input(true, ...(ngDevMode ? [{ debugName: "animated" }] : /* istanbul ignore next */ []));
76369
+ /** Agulha que gira junto com a ponta do arco. Sem ela, o valor vai para o centro do arco. */
76370
+ this.needle = input(true, ...(ngDevMode ? [{ debugName: "needle" }] : /* istanbul ignore next */ []));
76371
+ /** Marcas da escala por fora do arco, com rótulos. Desligado, só o mínimo e o máximo aparecem. */
76372
+ this.ticks = input(true, ...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
76373
+ /** Intervalo entre as marcas, na unidade do valor; padrão (ou intervalo que não divide a escala): um décimo. */
76374
+ this.tickStep = input(null, ...(ngDevMode ? [{ debugName: "tickStep" }] : /* istanbul ignore next */ []));
76375
+ /** Legenda curta abaixo do valor (ex.: "das PAs conectadas"); entra também no resumo acessível. */
76376
+ this.caption = input('', ...(ngDevMode ? [{ debugName: "caption" }] : /* istanbul ignore next */ []));
76377
+ /** Formato do valor no centro, quando difere do `numberFormat` (que vale para a escala e a tabela). */
76378
+ this.valueFormat = input(null, ...(ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []));
76379
+ /**
76380
+ * Tamanho medido do gráfico e das fontes (px). `undefined` até a primeira medição: até lá o motor
76381
+ * recebe só a moldura vazia, para a animação de entrada começar uma vez só, já na geometria final
76382
+ * (um primeiro desenho provisório recriaria a agulha no meio do caminho, fora de compasso com o número).
76383
+ */
76384
+ this.#box = signal(undefined, { ...(ngDevMode ? { debugName: "#box" } : /* istanbul ignore next */ {}), equal: sameBox });
76385
+ /**
76386
+ * Valor desenhado agora (arco, agulha e número). A animação é do próprio componente, quadro a quadro,
76387
+ * com o motor sem animação: assim os três saem sempre do mesmo número, mesmo que o motor redesenhe no
76388
+ * meio do caminho (troca de tema, de tamanho), o que faria a agulha recomeçar e o número não.
76389
+ */
76390
+ this.#shown = signal(undefined, ...(ngDevMode ? [{ debugName: "#shown" }] : /* istanbul ignore next */ []));
76391
+ this.#frame = 0;
76392
+ const host = inject(ElementRef).nativeElement;
76393
+ let observer = null;
76394
+ afterNextRender(() => {
76395
+ const target = host.querySelector('.hm-chart');
76396
+ if (!target) {
76397
+ this.#box.set({ width: 0, height: 0, smallFont: 12, baseFont: 14 });
76398
+ return;
76399
+ }
76400
+ const measure = () => {
76401
+ this.#box.set({
76402
+ width: Math.round(target.clientWidth),
76403
+ height: Math.round(target.clientHeight),
76404
+ smallFont: tokenFont(target, '--hm-font-size-sm', 12),
76405
+ baseFont: tokenFont(target, '--hm-font-size-md', 14),
76406
+ });
76407
+ };
76408
+ measure();
76409
+ if (typeof ResizeObserver !== 'undefined') {
76410
+ observer = new ResizeObserver(measure);
76411
+ observer.observe(target);
76412
+ }
76413
+ });
76414
+ inject(DestroyRef).onDestroy(() => {
76415
+ observer?.disconnect();
76416
+ this.#stop();
76417
+ });
76418
+ effect(() => {
76419
+ const value = this.value();
76420
+ const min = this.min();
76421
+ const animated = this.animated();
76422
+ const box = this.#box();
76423
+ untracked(() => this.#animateTo(value, min, animated, box));
76424
+ });
76425
+ }
76426
+ /** Leva o valor desenhado até `value`: animado do valor atual (ou do mínimo, na entrada), ou direto. */
76427
+ #animateTo(value, min, animated, box) {
76428
+ if (box === undefined)
76429
+ return; // ainda sem desenho: a entrada começa quando houver medida
76430
+ if (this.#target === value)
76431
+ return; // mesmo alvo (só mudou o tamanho): segue o que já estava
76432
+ this.#target = value;
76433
+ this.#stop();
76434
+ const reduced = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
76435
+ if (!animated || reduced || !(box.width > 0) || typeof requestAnimationFrame !== 'function' || !Number.isFinite(value)) {
76436
+ this.#shown.set(value);
76437
+ return;
76438
+ }
76439
+ const from = this.#shown() ?? min;
76440
+ const start = performance.now();
76441
+ const step = (now) => {
76442
+ const t = Math.min(1, (now - start) / DURATION);
76443
+ const eased = 1 - (1 - t) ** 3; // cubicOut: arranca rápido e assenta devagar
76444
+ this.#shown.set(t >= 1 ? value : from + (value - from) * eased);
76445
+ this.#frame = t < 1 ? requestAnimationFrame(step) : 0;
76446
+ };
76447
+ this.#shown.set(from);
76448
+ this.#frame = requestAnimationFrame(step);
76449
+ }
76450
+ #stop() {
76451
+ if (this.#frame && typeof cancelAnimationFrame === 'function')
76452
+ cancelAnimationFrame(this.#frame);
76453
+ this.#frame = 0;
76041
76454
  }
76042
76455
  build(ctx) {
76043
76456
  const value = this.value();
76044
76457
  const min = this.min();
76045
76458
  const max = this.max();
76459
+ const caption = this.caption();
76460
+ const needle = this.needle();
76461
+ const ticks = this.ticks();
76462
+ const valueNum = this.valueFormat() ? numberFormatter(ctx.locale, this.valueFormat()) : ctx.num;
76463
+ const { splits } = ticks ? gaugeScale(min, max, this.tickStep()) : { splits: 1 };
76464
+ const tickValue = (i) => min + ((max - min) * i) / splits;
76465
+ const allLabels = Array.from({ length: splits + 1 }, (_, i) => ctx.num(tickValue(i)));
76466
+ // Reserva a largura do valor mais longo da escala (o número conta de min até max na animação).
76467
+ const valueText = [valueNum(min), valueNum(max), valueNum(value)].reduce((a, b) => (b.length > a.length ? b : a));
76468
+ const box = this.#box();
76469
+ const measured = box !== undefined;
76470
+ const layoutFor = (labels) => box ? gaugeLayout({ box, labels, valueText, hasCaption: !!caption, needle, ticks }) : null;
76471
+ let labels = allLabels;
76472
+ let layout = layoutFor(labels);
76473
+ if (layout && splits > 1) {
76474
+ const widest = Math.max(...allLabels.map((l) => l.length)) * layout.labelFont * 0.6;
76475
+ const every = labelEvery(splits, layout.radius + layout.tickGap + layout.majorLength, widest, layout.labelFont);
76476
+ if (every > 1) {
76477
+ labels = allLabels.map((l, i) => (i % every === 0 ? l : null));
76478
+ layout = layoutFor(labels);
76479
+ }
76480
+ }
76046
76481
  return {
76047
76482
  option: {
76048
76483
  tooltip: { show: false },
76049
- series: [{
76050
- type: 'gauge',
76051
- min,
76052
- max,
76053
- startAngle: 220,
76054
- endAngle: -40,
76055
- radius: '94%',
76056
- progress: { show: true, width: 12, roundCap: true },
76057
- axisLine: { roundCap: true, lineStyle: { width: 12 } },
76058
- pointer: { show: false },
76059
- axisTick: { show: false },
76060
- splitLine: { show: false },
76061
- axisLabel: { distance: 18, formatter: (v) => (v === min || v === max ? ctx.num(v) : '') },
76062
- anchor: { show: false },
76063
- title: { show: false },
76064
- detail: { valueAnimation: true, offsetCenter: [0, '0%'], fontSize: 30, formatter: (v) => ctx.num(v) },
76065
- data: [{ value, name: this.label() }],
76066
- }],
76484
+ series: !measured ? [] : [
76485
+ this.#mainSeries(ctx, { value: this.#shown() ?? value, min, max, caption, needle, ticks, splits, layout, valueNum }),
76486
+ ...(labels.some((l) => l) ? [this.#labelSeries(labels, layout, min, max)] : []),
76487
+ ],
76067
76488
  },
76068
- summary: ctx.i18n.format(ctx.m.summary.gauge, { type: ctx.m.types.gauge, value: ctx.num(value), min: ctx.num(min), max: ctx.num(max) }),
76489
+ summary: caption
76490
+ ? ctx.i18n.format(ctx.m.summary.gaugeCaption, { type: ctx.m.types.gauge, value: valueNum(value), caption, min: ctx.num(min), max: ctx.num(max) })
76491
+ : ctx.i18n.format(ctx.m.summary.gauge, { type: ctx.m.types.gauge, value: valueNum(value), min: ctx.num(min), max: ctx.num(max) }),
76069
76492
  table: {
76070
76493
  columns: [ctx.m.columns.indicator, ctx.m.columns.value, ctx.m.columns.min, ctx.m.columns.max],
76071
76494
  align: ['start', 'end', 'end', 'end'],
@@ -76074,13 +76497,102 @@ class HmGaugeChartComponent extends HmChartBase {
76074
76497
  points: [],
76075
76498
  };
76076
76499
  }
76077
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmGaugeChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76078
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmGaugeChartComponent, isStandalone: true, selector: "hm-gauge-chart", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76500
+ /** Arco, progresso, agulha, marcas, valor e legenda. */
76501
+ #mainSeries(ctx, o) {
76502
+ const l = o.layout;
76503
+ const arcWidth = l?.arcWidth ?? 12;
76504
+ const gap = l?.tickGap ?? 4;
76505
+ const major = l?.majorLength ?? 8;
76506
+ const minor = l?.minorLength ?? 4;
76507
+ // As marcas ficam por fora: distância negativa conta a partir da borda externa do arco.
76508
+ const showMinor = o.ticks && (l ? l.radius >= 72 : true);
76509
+ return {
76510
+ type: 'gauge',
76511
+ min: o.min,
76512
+ max: o.max,
76513
+ startAngle: GAUGE_START_ANGLE,
76514
+ endAngle: GAUGE_END_ANGLE,
76515
+ center: l ? [l.cx, l.cy] : ['50%', '58%'],
76516
+ radius: l ? l.radius : '62%',
76517
+ splitNumber: o.splits,
76518
+ silent: true,
76519
+ // A animação é do componente (ver `#shown`): o motor só desenha cada quadro.
76520
+ animation: false,
76521
+ progress: { show: true, width: arcWidth, roundCap: true },
76522
+ axisLine: { roundCap: true, lineStyle: { width: arcWidth } },
76523
+ splitLine: { show: o.ticks, length: major, distance: -(arcWidth + gap + major), lineStyle: { width: Math.max(1.5, arcWidth * 0.16), cap: 'round' } },
76524
+ axisTick: { show: showMinor, splitNumber: 2, length: minor, distance: -(arcWidth + gap + minor), lineStyle: { width: 1, cap: 'round' } },
76525
+ axisLabel: { show: false },
76526
+ pointer: o.needle
76527
+ ? { show: true, icon: NEEDLE_PATH, length: l?.needleLength ?? '82%', width: l?.needleWidth ?? 4, keepAspect: false, showAbove: true }
76528
+ : { show: false },
76529
+ anchor: o.needle
76530
+ ? { show: true, showAbove: true, size: l?.hubSize ?? 14, itemStyle: { borderWidth: Math.max(2, (l?.hubSize ?? 14) * 0.22) } }
76531
+ : { show: false },
76532
+ title: {
76533
+ show: !!o.caption,
76534
+ offsetCenter: [0, l ? l.captionOffset : o.needle ? '72%' : '30%'],
76535
+ fontSize: l?.captionFont ?? 12,
76536
+ },
76537
+ detail: {
76538
+ offsetCenter: [0, l ? l.valueOffset : o.needle ? '42%' : '0%'],
76539
+ fontSize: l?.valueFont ?? 28,
76540
+ fontWeight: 'bold',
76541
+ color: 'inherit',
76542
+ formatter: (v) => o.valueNum(v),
76543
+ },
76544
+ data: [{ value: o.value, name: o.caption }],
76545
+ };
76546
+ }
76547
+ /**
76548
+ * Rótulos da escala, cada um posicionado por fora do arco (o rótulo nativo do motor fica por
76549
+ * dentro e alinhado para dentro). Série só de textos, sem arco nem agulha.
76550
+ */
76551
+ #labelSeries(labels, l, min, max) {
76552
+ const n = Math.max(1, labels.length - 1);
76553
+ const placed = l?.labels;
76554
+ let k = 0;
76555
+ const data = labels.flatMap((text, i) => {
76556
+ if (!text)
76557
+ return [];
76558
+ const spot = placed?.[k++];
76559
+ // Sem medição (jsdom), uma aproximação em % do raio.
76560
+ const a = ((GAUGE_START_ANGLE - ((GAUGE_START_ANGLE - GAUGE_END_ANGLE) * i) / n) * Math.PI) / 180;
76561
+ const offset = spot ? [spot.dx, spot.dy] : [`${Math.round(Math.cos(a) * 128)}%`, `${Math.round(-Math.sin(a) * 124)}%`];
76562
+ return [{ value: min, name: text, title: { offsetCenter: offset } }];
76563
+ });
76564
+ return {
76565
+ type: 'gauge',
76566
+ min,
76567
+ max,
76568
+ startAngle: GAUGE_START_ANGLE,
76569
+ endAngle: GAUGE_END_ANGLE,
76570
+ center: l ? [l.cx, l.cy] : ['50%', '58%'],
76571
+ radius: l ? l.radius : '62%',
76572
+ silent: true,
76573
+ animation: false,
76574
+ progress: { show: false },
76575
+ axisLine: { show: false },
76576
+ splitLine: { show: false },
76577
+ axisTick: { show: false },
76578
+ axisLabel: { show: false },
76579
+ pointer: { show: false },
76580
+ anchor: { show: false },
76581
+ detail: { show: false },
76582
+ title: { show: true, fontSize: l?.labelFont ?? 12 },
76583
+ data,
76584
+ };
76585
+ }
76586
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmGaugeChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
76587
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmGaugeChartComponent, isStandalone: true, selector: "hm-gauge-chart", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null }, needle: { classPropertyName: "needle", publicName: "needle", isSignal: true, isRequired: false, transformFunction: null }, ticks: { classPropertyName: "ticks", publicName: "ticks", isSignal: true, isRequired: false, transformFunction: null }, tickStep: { classPropertyName: "tickStep", publicName: "tickStep", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `<hm-chart-frame [view]="view()" [label]="label()" [description]="description()" [height]="height()" [(showTable)]="showTable" />`, isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76079
76588
  }
76080
76589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmGaugeChartComponent, decorators: [{
76081
76590
  type: Component,
76082
- args: [{ selector: 'hm-gauge-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: CHART_TEMPLATE, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
76083
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }] } });
76591
+ args: [{ selector: 'hm-gauge-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `<hm-chart-frame [view]="view()" [label]="label()" [description]="description()" [height]="height()" [(showTable)]="showTable" />`, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
76592
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }], needle: [{ type: i0.Input, args: [{ isSignal: true, alias: "needle", required: false }] }], ticks: [{ type: i0.Input, args: [{ isSignal: true, alias: "ticks", required: false }] }], tickStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickStep", required: false }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }] } });
76593
+ function sameBox(a, b) {
76594
+ return a === b || (!!a && !!b && a.width === b.width && a.height === b.height && a.smallFont === b.smallFont && a.baseFont === b.baseFont);
76595
+ }
76084
76596
 
76085
76597
  /**
76086
76598
  * Etapas sucessivas de um processo (visitas → cadastros → compras). A ordem de `data` é a ordem das
@@ -76122,7 +76634,7 @@ class HmFunnelChartComponent extends HmChartBase {
76122
76634
  };
76123
76635
  }
76124
76636
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmFunnelChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76125
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmFunnelChartComponent, isStandalone: true, selector: "hm-funnel-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76637
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmFunnelChartComponent, isStandalone: true, selector: "hm-funnel-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76126
76638
  }
76127
76639
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmFunnelChartComponent, decorators: [{
76128
76640
  type: Component,
@@ -76168,7 +76680,7 @@ class HmRadarChartComponent extends HmChartBase {
76168
76680
  };
76169
76681
  }
76170
76682
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmRadarChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76171
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmRadarChartComponent, isStandalone: true, selector: "hm-radar-chart", inputs: { indicators: { classPropertyName: "indicators", publicName: "indicators", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76683
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmRadarChartComponent, isStandalone: true, selector: "hm-radar-chart", inputs: { indicators: { classPropertyName: "indicators", publicName: "indicators", isSignal: true, isRequired: true, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76172
76684
  }
76173
76685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmRadarChartComponent, decorators: [{
76174
76686
  type: Component,
@@ -76223,7 +76735,7 @@ class HmTreemapChartComponent extends HmChartBase {
76223
76735
  };
76224
76736
  }
76225
76737
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmTreemapChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76226
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmTreemapChartComponent, isStandalone: true, selector: "hm-treemap-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76738
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmTreemapChartComponent, isStandalone: true, selector: "hm-treemap-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76227
76739
  }
76228
76740
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmTreemapChartComponent, decorators: [{
76229
76741
  type: Component,
@@ -76268,7 +76780,7 @@ class HmSankeyChartComponent extends HmChartBase {
76268
76780
  };
76269
76781
  }
76270
76782
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmSankeyChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76271
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmSankeyChartComponent, isStandalone: true, selector: "hm-sankey-chart", inputs: { links: { classPropertyName: "links", publicName: "links", isSignal: true, isRequired: true, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76783
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmSankeyChartComponent, isStandalone: true, selector: "hm-sankey-chart", inputs: { links: { classPropertyName: "links", publicName: "links", isSignal: true, isRequired: true, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76272
76784
  }
76273
76785
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmSankeyChartComponent, decorators: [{
76274
76786
  type: Component,
@@ -76347,13 +76859,446 @@ class HmBoxplotChartComponent extends HmChartBase {
76347
76859
  };
76348
76860
  }
76349
76861
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBoxplotChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76350
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmBoxplotChartComponent, isStandalone: true, selector: "hm-boxplot-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76862
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmBoxplotChartComponent, isStandalone: true, selector: "hm-boxplot-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76351
76863
  }
76352
76864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBoxplotChartComponent, decorators: [{
76353
76865
  type: Component,
76354
76866
  args: [{ selector: 'hm-boxplot-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: CHART_TEMPLATE, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
76355
76867
  }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }] } });
76356
76868
 
76869
+ /**
76870
+ * Minigráfico: a tendência de uma série em pouco espaço, sem eixos nem legenda (dentro de um card de
76871
+ * indicador, numa linha de tabela). O resumo (primeiro, último, mínimo e máximo) e a tabela de dados
76872
+ * ficam na árvore de acessibilidade; sem o botão "Ver como tabela", para caber no `[footer]` do
76873
+ * `hm-stat-card`.
76874
+ */
76875
+ class HmSparklineChartComponent extends HmChartBase {
76876
+ constructor() {
76877
+ super(...arguments);
76878
+ /** Valores na ordem (o mais antigo primeiro); `null` é lacuna. */
76879
+ this.data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
76880
+ /** Rótulo de cada valor (datas, meses) para a tabela e o tooltip; padrão: a posição (1, 2, 3...). */
76881
+ this.categories = input([], ...(ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []));
76882
+ /** Preenche a área sob a linha. */
76883
+ this.area = input(false, ...(ngDevMode ? [{ debugName: "area" }] : /* istanbul ignore next */ []));
76884
+ /** Destaca o último ponto (o valor atual). */
76885
+ this.showLast = input(true, ...(ngDevMode ? [{ debugName: "showLast" }] : /* istanbul ignore next */ []));
76886
+ /** Barras em vez de linha (valores discretos: pedidos por dia). */
76887
+ this.bars = input(false, ...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
76888
+ /**
76889
+ * Entra na ordem de foco e mostra o tooltip (setas percorrem os pontos). Desligado (padrão), o
76890
+ * minigráfico é só uma imagem com resumo: um card de indicador não ganha uma parada de Tab a mais.
76891
+ */
76892
+ this.interactive = input(false, ...(ngDevMode ? [{ debugName: "interactive" }] : /* istanbul ignore next */ []));
76893
+ }
76894
+ build(ctx) {
76895
+ const data = this.data();
76896
+ const names = data.map((_, i) => this.categories()[i] ?? String(i + 1));
76897
+ const last = data.length - 1;
76898
+ const interactive = this.interactive();
76899
+ const values = data.map((v, i) => !this.bars() && this.showLast() && i === last && v != null ? { value: v, symbol: 'circle', symbolSize: 6 } : v);
76900
+ const finite = data.filter((v) => v != null && Number.isFinite(v));
76901
+ const range = extent(finite);
76902
+ const describe = (i) => `${names[i]}: ${ctx.num(data[i])}`;
76903
+ return {
76904
+ option: {
76905
+ grid: { left: 4, right: 6, top: 6, bottom: 4, containLabel: false },
76906
+ tooltip: interactive
76907
+ ? {
76908
+ ...tooltipOption(ctx, 'axis'),
76909
+ axisPointer: { type: 'line' },
76910
+ formatter: (p) => escapeHtml(describe((Array.isArray(p) ? p[0] : p).dataIndex)),
76911
+ }
76912
+ : { show: false },
76913
+ xAxis: { type: 'category', data: names, show: false, boundaryGap: this.bars() },
76914
+ yAxis: { type: 'value', show: false, scale: !this.bars() },
76915
+ series: [
76916
+ this.bars()
76917
+ ? { type: 'bar', name: this.label(), data: [...data], barCategoryGap: '30%', silent: !interactive }
76918
+ : {
76919
+ type: 'line',
76920
+ name: this.label(),
76921
+ data: values,
76922
+ symbol: 'none',
76923
+ lineStyle: { width: 1.75 },
76924
+ areaStyle: this.area() ? { opacity: 0.18 } : undefined,
76925
+ silent: !interactive,
76926
+ },
76927
+ ],
76928
+ },
76929
+ summary: ctx.i18n.plural(ctx.m.summary.sparkline, finite.length, {
76930
+ type: ctx.m.types.sparkline,
76931
+ first: ctx.num(finite[0]),
76932
+ last: ctx.num(finite[finite.length - 1]),
76933
+ min: ctx.num(range?.[0]),
76934
+ max: ctx.num(range?.[1]),
76935
+ }),
76936
+ table: {
76937
+ columns: [ctx.m.columns.category, ctx.m.columns.value],
76938
+ align: ['start', 'end'],
76939
+ rows: data.map((v, i) => ({ header: names[i], cells: [ctx.num(v)] })),
76940
+ },
76941
+ points: interactive ? data.map((_, i) => ({ seriesIndex: 0, dataIndex: i, text: describe(i) })) : [],
76942
+ };
76943
+ }
76944
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmSparklineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
76945
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmSparklineChartComponent, isStandalone: true, selector: "hm-sparkline-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null }, area: { classPropertyName: "area", publicName: "area", isSignal: true, isRequired: false, transformFunction: null }, showLast: { classPropertyName: "showLast", publicName: "showLast", isSignal: true, isRequired: false, transformFunction: null }, bars: { classPropertyName: "bars", publicName: "bars", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `<hm-chart-frame
76946
+ [view]="view()"
76947
+ [label]="label()"
76948
+ [description]="description()"
76949
+ [height]="height() || 'calc(var(--hm-control-height) * 1.5)'"
76950
+ [tableToggle]="false"
76951
+ [(showTable)]="showTable"
76952
+ />`, isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
76953
+ }
76954
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmSparklineChartComponent, decorators: [{
76955
+ type: Component,
76956
+ args: [{ selector: 'hm-sparkline-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `<hm-chart-frame
76957
+ [view]="view()"
76958
+ [label]="label()"
76959
+ [description]="description()"
76960
+ [height]="height() || 'calc(var(--hm-control-height) * 1.5)'"
76961
+ [tableToggle]="false"
76962
+ [(showTable)]="showTable"
76963
+ />`, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
76964
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], categories: [{ type: i0.Input, args: [{ isSignal: true, alias: "categories", required: false }] }], area: [{ type: i0.Input, args: [{ isSignal: true, alias: "area", required: false }] }], showLast: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLast", required: false }] }], bars: [{ type: i0.Input, args: [{ isSignal: true, alias: "bars", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }] } });
76965
+
76966
+ /**
76967
+ * Tamanho real da área do gráfico (o `.hm-chart` dentro do componente), medido depois da primeira
76968
+ * pintura e a cada redimensionamento. `null` até a primeira medição (e em ambiente sem layout).
76969
+ * Chame no construtor de um gráfico tipado.
76970
+ */
76971
+ function injectChartBox() {
76972
+ const host = inject(ElementRef).nativeElement;
76973
+ const box = signal(null, { ...(ngDevMode ? { debugName: "box" } : /* istanbul ignore next */ {}), equal: (a, b) => a === b || (!!a && !!b && a.width === b.width && a.height === b.height) });
76974
+ let observer = null;
76975
+ afterNextRender(() => {
76976
+ const target = host.querySelector('.hm-chart');
76977
+ if (!target)
76978
+ return;
76979
+ const measure = () => {
76980
+ const width = Math.round(target.clientWidth);
76981
+ const height = Math.round(target.clientHeight);
76982
+ box.set(width > 0 && height > 0 ? { width, height } : null);
76983
+ };
76984
+ measure();
76985
+ if (typeof ResizeObserver !== 'undefined') {
76986
+ observer = new ResizeObserver(measure);
76987
+ observer.observe(target);
76988
+ }
76989
+ });
76990
+ inject(DestroyRef).onDestroy(() => observer?.disconnect());
76991
+ return box;
76992
+ }
76993
+ /**
76994
+ * Cores de tokens (`--hm-*`) resolvidas para `rgb(...)` no elemento do gráfico, para os gráficos
76995
+ * que pintam partes fora da paleta (faixas neutras, aumento/redução). Relidas quando tema, família,
76996
+ * densidade ou paleta mudam num ancestral. `null` antes da primeira pintura e em `forced-colors`
76997
+ * (aí o tema do motor já usa cores de sistema e o gráfico cai na paleta dele).
76998
+ */
76999
+ function injectTokenColors(tokens) {
77000
+ const host = inject(ElementRef).nativeElement;
77001
+ const colors = signal(null, { ...(ngDevMode ? { debugName: "colors" } : /* istanbul ignore next */ {}), equal: (a, b) => JSON.stringify(a) === JSON.stringify(b) });
77002
+ let scope = null;
77003
+ let forced = null;
77004
+ // Fora do documento (painel de aba ainda não exibido) os tokens não resolvem: relê ao entrar na página.
77005
+ let attach = null;
77006
+ const watchAttach = () => {
77007
+ if (attach || host.isConnected || typeof ResizeObserver === 'undefined')
77008
+ return;
77009
+ attach = new ResizeObserver(() => {
77010
+ if (!host.isConnected)
77011
+ return;
77012
+ attach?.disconnect();
77013
+ attach = null;
77014
+ read();
77015
+ });
77016
+ attach.observe(host);
77017
+ };
77018
+ const read = () => {
77019
+ if (forced?.matches) {
77020
+ colors.set(null);
77021
+ return;
77022
+ }
77023
+ const out = {};
77024
+ for (const key of Object.keys(tokens)) {
77025
+ const value = resolveTokenColor(host, tokens[key]);
77026
+ if (!value) {
77027
+ colors.set(null);
77028
+ return;
77029
+ }
77030
+ out[key] = value;
77031
+ }
77032
+ colors.set(out);
77033
+ };
77034
+ const onForced = () => read();
77035
+ afterNextRender(() => {
77036
+ forced = typeof matchMedia === 'function' ? matchMedia('(forced-colors: active)') : null;
77037
+ forced?.addEventListener?.('change', onForced);
77038
+ read();
77039
+ watchAttach();
77040
+ if (typeof MutationObserver === 'undefined')
77041
+ return;
77042
+ scope = new MutationObserver((records) => {
77043
+ if (records.some((r) => r.target.contains(host)))
77044
+ queueMicrotask(read);
77045
+ });
77046
+ scope.observe(host.ownerDocument.documentElement, {
77047
+ subtree: true,
77048
+ attributes: true,
77049
+ attributeFilter: ['data-theme', 'data-family', 'data-density', 'data-font', 'style'],
77050
+ });
77051
+ });
77052
+ inject(DestroyRef).onDestroy(() => {
77053
+ scope?.disconnect();
77054
+ attach?.disconnect();
77055
+ forced?.removeEventListener?.('change', onForced);
77056
+ });
77057
+ return colors;
77058
+ }
77059
+ /** `rgb(r, g, b)` (ou `rgba`) com outra opacidade; texto que não for rgb volta como veio. */
77060
+ function withAlpha(color, alpha) {
77061
+ const m = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/.exec(color);
77062
+ return m ? `rgba(${m[1]}, ${m[2]}, ${m[3]}, ${alpha})` : color;
77063
+ }
77064
+
77065
+ /** Opacidade das faixas, da primeira (mais escura) à última: o texto translúcido funciona nos dois temas. */
77066
+ const BAND_ALPHA = [0.22, 0.14, 0.08, 0.05];
77067
+ /**
77068
+ * Gráfico de bala: cada linha é um indicador com o valor (barra fina na cor da série), a meta (marca
77069
+ * vertical) e as faixas qualitativas ao fundo. Substitui um painel de medidores lado a lado em pouco
77070
+ * espaço, com todos na mesma escala.
77071
+ */
77072
+ class HmBulletChartComponent extends HmChartBase {
77073
+ constructor() {
77074
+ super(...arguments);
77075
+ this.items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
77076
+ /** Fim da escala (comum a todos); padrão: um valor redondo que cobre valores, metas e faixas. */
77077
+ this.max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
77078
+ this.#box = injectChartBox();
77079
+ this.#colors = injectTokenColors({ text: '--hm-text' });
77080
+ }
77081
+ #box;
77082
+ #colors;
77083
+ build(ctx) {
77084
+ const items = this.items();
77085
+ const names = items.map((i) => i.name);
77086
+ const bands = Math.max(0, ...items.map((i) => i.ranges?.length ?? 0));
77087
+ // Sem `max`, o motor escolhe um fim de escala redondo que cobre valores, metas e faixas (um fim
77088
+ // quebrado, como 270, cola o último rótulo no penúltimo).
77089
+ const top = this.max();
77090
+ const reach = Math.max(0, ...items.flatMap((i) => [i.value, i.target ?? 0, ...(i.ranges ?? [])]));
77091
+ const text = this.#colors()?.text;
77092
+ const box = this.#box();
77093
+ // Altura da marca da meta: 70% da faixa de cada linha (medida); antes da medida, um valor seguro.
77094
+ const row = box ? (box.height - 28) / Math.max(1, items.length) : 40;
77095
+ const markHeight = Math.max(10, Math.min(36, row * 0.62));
77096
+ const bandSeries = Array.from({ length: bands }, (_, b) => ({
77097
+ type: 'bar',
77098
+ name: `band-${b}`,
77099
+ stack: 'bands',
77100
+ yAxisIndex: 0,
77101
+ barWidth: '62%',
77102
+ silent: true,
77103
+ itemStyle: text ? { color: withAlpha(text, BAND_ALPHA[Math.min(b, BAND_ALPHA.length - 1)]) } : { opacity: 0.12 + 0.06 * (bands - b) },
77104
+ data: items.map((i) => {
77105
+ const r = i.ranges ?? [];
77106
+ return b < r.length ? r[b] - (b ? r[b - 1] : 0) : 0;
77107
+ }),
77108
+ tooltip: { show: false },
77109
+ animation: false,
77110
+ }));
77111
+ const series = [
77112
+ ...bandSeries,
77113
+ {
77114
+ type: 'bar',
77115
+ name: ctx.m.columns.value,
77116
+ yAxisIndex: 1,
77117
+ barWidth: '24%',
77118
+ data: items.map((i) => i.value),
77119
+ emphasis: { focus: 'self' },
77120
+ },
77121
+ {
77122
+ type: 'scatter',
77123
+ name: ctx.m.columns.goal,
77124
+ yAxisIndex: 0,
77125
+ symbol: 'rect',
77126
+ symbolSize: [3, markHeight],
77127
+ itemStyle: text ? { color: text } : undefined,
77128
+ data: items.map((i, idx) => (i.target == null ? null : [i.target, idx])),
77129
+ z: 5,
77130
+ },
77131
+ ];
77132
+ const describe = (i) => i.target == null
77133
+ ? ctx.i18n.format(ctx.m.summary.bulletItemNoTarget, { name: i.name, value: ctx.num(i.value) })
77134
+ : ctx.i18n.format(ctx.m.summary.bulletItem, { name: i.name, value: ctx.num(i.value), target: ctx.num(i.target) });
77135
+ const valueSeries = bands;
77136
+ return {
77137
+ option: {
77138
+ grid: { left: 6, right: 20, top: 8, bottom: 6, containLabel: true },
77139
+ tooltip: {
77140
+ ...tooltipOption(ctx, 'axis'),
77141
+ formatter: (p) => {
77142
+ const first = (Array.isArray(p) ? p[0] : p);
77143
+ return escapeHtml(describe(items[first.dataIndex]));
77144
+ },
77145
+ },
77146
+ legend: { show: false },
77147
+ xAxis: { type: 'value', min: 0, max: top ?? (reach > 0 ? undefined : 1), axisLabel: { formatter: (v) => ctx.num(v) } },
77148
+ yAxis: [
77149
+ { type: 'category', data: names, inverse: true, axisTick: { show: false } },
77150
+ { type: 'category', data: names, inverse: true, show: false },
77151
+ ],
77152
+ series,
77153
+ },
77154
+ summary: [ctx.i18n.plural(ctx.m.summary.items, items.length, { type: ctx.m.types.bullet }), ...items.map(describe)].join(' '),
77155
+ table: {
77156
+ columns: [ctx.m.columns.indicator, ctx.m.columns.value, ctx.m.columns.goal, ctx.m.columns.ranges],
77157
+ align: ['start', 'end', 'end', 'end'],
77158
+ rows: items.map((i) => ({
77159
+ header: i.name,
77160
+ cells: [ctx.num(i.value), i.target == null ? EMPTY_VALUE : ctx.num(i.target), i.ranges?.length ? i.ranges.map((r) => ctx.num(r)).join(' · ') : EMPTY_VALUE],
77161
+ })),
77162
+ },
77163
+ points: items.map((i, idx) => ({ seriesIndex: valueSeries, dataIndex: idx, text: describe(i) })),
77164
+ };
77165
+ }
77166
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBulletChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
77167
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmBulletChartComponent, isStandalone: true, selector: "hm-bullet-chart", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
77168
+ }
77169
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmBulletChartComponent, decorators: [{
77170
+ type: Component,
77171
+ args: [{ selector: 'hm-bullet-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: CHART_TEMPLATE, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
77172
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }] } });
77173
+
77174
+ /** Calcula as barras da cascata (sem framework: testável e portável). */
77175
+ function waterfallBars(steps) {
77176
+ let running = 0;
77177
+ return steps.map((s) => {
77178
+ if (s.total)
77179
+ return { kind: 'total', from: 0, to: running, change: running, cumulative: running };
77180
+ const change = Number.isFinite(s.value) ? s.value : 0;
77181
+ const from = running;
77182
+ running += change;
77183
+ return { kind: change < 0 ? 'decrease' : 'increase', from, to: running, change, cumulative: running };
77184
+ });
77185
+ }
77186
+ /**
77187
+ * Gráfico de cascata: como um valor inicial chega ao final, etapa por etapa (receita → custos →
77188
+ * lucro). Aumentos e reduções flutuam a partir do acumulado; totais partem do zero. Cores da escala
77189
+ * divergente dos tokens (um polo para aumento, outro para redução, o ponto neutro para totais).
77190
+ */
77191
+ class HmWaterfallChartComponent extends HmChartBase {
77192
+ constructor() {
77193
+ super(...arguments);
77194
+ this.steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
77195
+ this.#colors = injectTokenColors({
77196
+ increase: '--hm-data-diverging-6',
77197
+ decrease: '--hm-data-diverging-2',
77198
+ total: '--hm-data-diverging-4',
77199
+ });
77200
+ }
77201
+ #colors;
77202
+ build(ctx) {
77203
+ const steps = this.steps();
77204
+ const bars = waterfallBars(steps);
77205
+ const names = steps.map((s) => s.name);
77206
+ const colors = this.#colors();
77207
+ const signed = numberFormatter(ctx.locale, { ...(this.numberFormat() ?? {}), signDisplay: 'exceptZero' });
77208
+ const label = { increase: ctx.m.waterfall.increase, decrease: ctx.m.waterfall.decrease, total: ctx.m.waterfall.total };
77209
+ // Empilhamento por sinal (padrão do motor): base invisível + a parte positiva e a negativa de cada barra.
77210
+ // Barra que cruza o zero sai do zero para os dois lados.
77211
+ const base = [];
77212
+ const parts = {
77213
+ increase: { pos: [], neg: [] },
77214
+ decrease: { pos: [], neg: [] },
77215
+ total: { pos: [], neg: [] },
77216
+ };
77217
+ bars.forEach((b, i) => {
77218
+ const low = Math.min(b.from, b.to);
77219
+ const high = Math.max(b.from, b.to);
77220
+ for (const k of Object.keys(parts)) {
77221
+ parts[k].pos[i] = null;
77222
+ parts[k].neg[i] = null;
77223
+ }
77224
+ if (low >= 0) {
77225
+ base[i] = low;
77226
+ parts[b.kind].pos[i] = high - low;
77227
+ }
77228
+ else if (high <= 0) {
77229
+ base[i] = high;
77230
+ parts[b.kind].neg[i] = low - high;
77231
+ }
77232
+ else {
77233
+ base[i] = 0;
77234
+ parts[b.kind].pos[i] = high;
77235
+ parts[b.kind].neg[i] = low;
77236
+ }
77237
+ });
77238
+ const kinds = ['increase', 'decrease', 'total'].filter((k) => bars.some((b) => b.kind === k));
77239
+ const series = [
77240
+ {
77241
+ type: 'bar',
77242
+ name: 'base',
77243
+ stack: 'waterfall',
77244
+ silent: true,
77245
+ itemStyle: { color: 'transparent', borderColor: 'transparent' },
77246
+ emphasis: { disabled: true },
77247
+ tooltip: { show: false },
77248
+ data: base,
77249
+ },
77250
+ ...kinds.flatMap((k) => ['pos', 'neg'].map((side) => ({
77251
+ type: 'bar',
77252
+ name: label[k],
77253
+ stack: 'waterfall',
77254
+ barCategoryGap: '30%',
77255
+ itemStyle: colors ? { color: colors[k] } : undefined,
77256
+ data: parts[k][side],
77257
+ }))),
77258
+ ];
77259
+ const describe = (i) => {
77260
+ const b = bars[i];
77261
+ return b.kind === 'total'
77262
+ ? `${names[i]}: ${label.total} ${ctx.num(b.cumulative)}`
77263
+ : `${names[i]}: ${label[b.kind]} ${signed(b.change)}, ${ctx.m.columns.cumulative} ${ctx.num(b.cumulative)}`;
77264
+ };
77265
+ const hasLegend = kinds.length > 1;
77266
+ const end = bars.length ? bars[bars.length - 1].cumulative : 0;
77267
+ const start = bars.length ? bars[0].change : 0;
77268
+ return {
77269
+ option: {
77270
+ grid: gridOption(hasLegend && ctx.legend),
77271
+ tooltip: {
77272
+ ...tooltipOption(ctx, 'axis'),
77273
+ formatter: (p) => escapeHtml(describe((Array.isArray(p) ? p[0] : p).dataIndex)),
77274
+ },
77275
+ legend: { ...legendOption(ctx, hasLegend), data: kinds.map((k) => label[k]) },
77276
+ xAxis: { type: 'category', data: names, axisTick: { alignWithLabel: true } },
77277
+ yAxis: { type: 'value', axisLabel: { formatter: (v) => ctx.num(v) } },
77278
+ series,
77279
+ },
77280
+ summary: ctx.i18n.plural(ctx.m.summary.waterfall, steps.length, { type: ctx.m.types.waterfall, start: ctx.num(start), end: ctx.num(end) }),
77281
+ table: {
77282
+ columns: [ctx.m.columns.category, ctx.m.columns.change, ctx.m.columns.cumulative],
77283
+ align: ['start', 'end', 'end'],
77284
+ rows: bars.map((b, i) => ({ header: names[i], cells: [b.kind === 'total' ? label.total : signed(b.change), ctx.num(b.cumulative)] })),
77285
+ },
77286
+ // Destaca a série visível da etapa (a da cor dela) ao navegar com as setas.
77287
+ points: bars.map((b, i) => {
77288
+ const k = kinds.indexOf(b.kind);
77289
+ const side = parts[b.kind].pos[i] != null ? 0 : 1;
77290
+ return { seriesIndex: 1 + k * 2 + side, dataIndex: i, text: describe(i) };
77291
+ }),
77292
+ };
77293
+ }
77294
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmWaterfallChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
77295
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: HmWaterfallChartComponent, isStandalone: true, selector: "hm-waterfall-chart", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<hm-chart-frame [view]=\"view()\" [label]=\"label()\" [description]=\"description()\" [height]=\"height()\" [(showTable)]=\"showTable\" />", isInline: true, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"], dependencies: [{ kind: "component", type: HmChartFrameComponent, selector: "hm-chart-frame", inputs: ["view", "label", "description", "height", "tableToggle", "showTable"], outputs: ["showTableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
77296
+ }
77297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HmWaterfallChartComponent, decorators: [{
77298
+ type: Component,
77299
+ args: [{ selector: 'hm-waterfall-chart', standalone: true, imports: [HmChartFrameComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: CHART_TEMPLATE, styles: [":host{display:block;inline-size:100%;min-inline-size:0}\n"] }]
77300
+ }], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }] } });
77301
+
76357
77302
  // API pública de @trismegisto/charts.
76358
77303
  // Gráficos tipados (API orientada a dados)
76359
77304
 
@@ -76361,5 +77306,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImpo
76361
77306
  * Generated bundle index. Do not edit.
76362
77307
  */
76363
77308
 
76364
- export { CHARTS_I18N_CONFIG, CHARTS_MESSAGES_EN, CHARTS_MESSAGES_ES, CHARTS_MESSAGES_PT_BR, ChartsI18nService, HmBarChartComponent, HmBoxplotChartComponent, HmCalendarHeatmapComponent, HmChartBase, HmChartComponent, HmFunnelChartComponent, HmGaugeChartComponent, HmHeatmapChartComponent, HmLineChartComponent, HmPieChartComponent, HmRadarChartComponent, HmSankeyChartComponent, HmScatterChartComponent, HmTreemapChartComponent, provideChartsMessages };
77309
+ export { CHARTS_I18N_CONFIG, CHARTS_MESSAGES_EN, CHARTS_MESSAGES_ES, CHARTS_MESSAGES_PT_BR, ChartsI18nService, HmBarChartComponent, HmBoxplotChartComponent, HmBulletChartComponent, HmCalendarHeatmapComponent, HmChartBase, HmChartComponent, HmFunnelChartComponent, HmGaugeChartComponent, HmHeatmapChartComponent, HmLineChartComponent, HmPieChartComponent, HmRadarChartComponent, HmSankeyChartComponent, HmScatterChartComponent, HmSparklineChartComponent, HmTreemapChartComponent, HmWaterfallChartComponent, provideChartsMessages, waterfallBars };
76365
77310
  //# sourceMappingURL=trismegisto-charts.mjs.map