@magmonium/one 0.4.80 → 0.4.81

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.
@@ -18005,15 +18005,14 @@ const toChartTime = (value) => {
18005
18005
  const parsed = Date.parse(value);
18006
18006
  return Number.isFinite(parsed) ? parsed : null;
18007
18007
  };
18008
- const readChartPoints = (rows, x, y) => {
18008
+ const readChartPoints = (rows, x, y, per) => {
18009
18009
  const pairs = [];
18010
18010
  for (const row of rows ?? []) {
18011
18011
  if (row == null || typeof row !== "object") continue;
18012
18012
  const record = row;
18013
18013
  const t = toChartTime(record[x]);
18014
- const raw = record[y];
18015
- const v = typeof raw === "string" && raw.trim() ? Number(raw) : raw;
18016
- if (t === null || typeof v !== "number" || !Number.isFinite(v)) continue;
18014
+ const v = readChartValue(record, y, per);
18015
+ if (t === null || v === null) continue;
18017
18016
  pairs.push([t, v]);
18018
18017
  }
18019
18018
  for (let i = 1; i < pairs.length; i++) if (pairs[i][0] < pairs[i - 1][0]) {
@@ -18025,6 +18024,46 @@ const readChartPoints = (rows, x, y) => {
18025
18024
  y: pairs.map((p) => p[1])
18026
18025
  };
18027
18026
  };
18027
+ const toChartNumber = (raw) => {
18028
+ const v = typeof raw === "string" && raw.trim() ? Number(raw) : raw;
18029
+ return typeof v === "number" && Number.isFinite(v) ? v : null;
18030
+ };
18031
+ const readChartValue = (record, y, per) => {
18032
+ const v = toChartNumber(record[y]);
18033
+ if (v === null || !per) return v;
18034
+ const base = toChartNumber(record[per]);
18035
+ return base ? v / base * 100 : null;
18036
+ };
18037
+ const readChartCategories = (rows, x, y, per) => {
18038
+ const out = {
18039
+ x: [],
18040
+ y: []
18041
+ };
18042
+ for (const row of rows ?? []) {
18043
+ if (row == null || typeof row !== "object") continue;
18044
+ const record = row;
18045
+ const raw = record[x];
18046
+ const label = typeof raw === "string" || typeof raw === "number" ? String(raw).trim() : "";
18047
+ const v = readChartValue(record, y, per);
18048
+ if (!label || v === null) continue;
18049
+ out.x.push(label);
18050
+ out.y.push(v);
18051
+ }
18052
+ return out;
18053
+ };
18054
+ const mergeCategories = (series) => {
18055
+ const seen = /* @__PURE__ */ new Set();
18056
+ for (const { x } of series) for (const label of x) seen.add(label);
18057
+ return [...seen];
18058
+ };
18059
+ const columnPath = (x, width, y0, y1, radius = 4) => {
18060
+ const h = Math.abs(y0 - y1);
18061
+ const r = Math.max(0, Math.min(radius, h / 2, width / 2));
18062
+ const f = (v) => v.toFixed(1);
18063
+ const dir = y1 <= y0 ? 1 : -1;
18064
+ const right = x + width;
18065
+ return `M${f(x)} ${f(y0)}V${f(y1 + dir * r)}Q${f(x)} ${f(y1)} ${f(x + r)} ${f(y1)}H${f(right - r)}Q${f(right)} ${f(y1)} ${f(right)} ${f(y1 + dir * r)}V${f(y0)}Z`;
18066
+ };
18028
18067
  const lowerBound = (times, x) => {
18029
18068
  let lo = 0;
18030
18069
  let hi = times.length;
@@ -18265,6 +18304,22 @@ const sampleChartPoints = (index, end = Date.UTC(2026, 0, 2)) => {
18265
18304
  y
18266
18305
  };
18267
18306
  };
18307
+ const sampleChartCategories = (index) => ({
18308
+ x: [
18309
+ "2022",
18310
+ "2023",
18311
+ "2024",
18312
+ "2025",
18313
+ "2026"
18314
+ ],
18315
+ y: [
18316
+ 59,
18317
+ 68,
18318
+ 94,
18319
+ 107,
18320
+ 108
18321
+ ].map((v) => v * .25 ** index)
18322
+ });
18268
18323
  const MARGIN = {
18269
18324
  top: 12,
18270
18325
  right: 16,
@@ -18288,6 +18343,12 @@ const NAV_TOP = 4;
18288
18343
  const GRIP_SLOP = 8;
18289
18344
  const MIN_WINDOW_SHARE = .02;
18290
18345
  const KEY_PAN_SHARE = .1;
18346
+ const STRIP_GAP = 40;
18347
+ const STRIP_HEIGHT = 72;
18348
+ const COLUMN_MAX = 40;
18349
+ const COLUMN_MIN = 4;
18350
+ const COLUMN_GAP = 2;
18351
+ const COLUMN_FILL = .6;
18291
18352
  const optionalNumber = (value) => value == null || value === "" ? void 0 : numberAttribute(value, void 0);
18292
18353
  const optionalBoolean = (value) => value == null ? void 0 : booleanAttribute(value);
18293
18354
  let nextId$2 = 0;
@@ -18345,7 +18406,7 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18345
18406
  minimal = computed(() => (this.variant() ?? this.config()?.variant) === "minimal", ...ngDevMode ? [{ debugName: "minimal" }] : /* istanbul ignore next */ []);
18346
18407
  margin = computed(() => this.minimal() ? MINIMAL_MARGIN : MARGIN, ...ngDevMode ? [{ debugName: "margin" }] : /* istanbul ignore next */ []);
18347
18408
  showNavigator = computed(() => !this.minimal() && (this.navigator() ?? this.config()?.navigator ?? false), ...ngDevMode ? [{ debugName: "showNavigator" }] : /* istanbul ignore next */ []);
18348
- canMeasure = computed(() => !this.minimal() && (this.measure() ?? this.config()?.measure ?? false), ...ngDevMode ? [{ debugName: "canMeasure" }] : /* istanbul ignore next */ []);
18409
+ canMeasure = computed(() => !this.minimal() && !this.categorical() && (this.measure() ?? this.config()?.measure ?? false), ...ngDevMode ? [{ debugName: "canMeasure" }] : /* istanbul ignore next */ []);
18349
18410
  presets = computed(() => {
18350
18411
  const authored = this.config()?.ranges;
18351
18412
  const ids = (authored?.length ? authored : DEFAULT_SECTION_CHART_RANGES).filter(isPresetId).map((id) => id.trim().toLowerCase());
@@ -18370,7 +18431,158 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18370
18431
  };
18371
18432
  });
18372
18433
  }, ...ngDevMode ? [{ debugName: "painted" }] : /* istanbul ignore next */ []);
18434
+ categorical = computed(() => this.members().some(({ member }) => member.mark() === "column"), ...ngDevMode ? [{ debugName: "categorical" }] : /* istanbul ignore next */ []);
18435
+ categoryData = computed(() => {
18436
+ if (!this.categorical()) return {
18437
+ categories: [],
18438
+ series: []
18439
+ };
18440
+ const read = this.painted().map(({ member, color }) => ({
18441
+ member,
18442
+ color,
18443
+ label: member.label(),
18444
+ noTranslate: member.noTranslate(),
18445
+ params: member.params(),
18446
+ mark: member.mark(),
18447
+ panel: member.panel(),
18448
+ ratio: member.ratio(),
18449
+ ...member.categories()
18450
+ }));
18451
+ const withData = read.filter((s) => s.x.length);
18452
+ const source = withData.length || !this.isDesignMode ? withData : read.map((s, i) => ({
18453
+ ...s,
18454
+ ...sampleChartCategories(i)
18455
+ }));
18456
+ const categories = mergeCategories(source);
18457
+ return {
18458
+ categories,
18459
+ series: source.map(({ x, y, ...s }) => ({
18460
+ ...s,
18461
+ values: categories.map((c) => {
18462
+ const j = x.indexOf(c);
18463
+ return j < 0 ? null : y[j];
18464
+ })
18465
+ }))
18466
+ };
18467
+ }, ...ngDevMode ? [{ debugName: "categoryData" }] : /* istanbul ignore next */ []);
18468
+ hasStrip = computed(() => this.categoryData().series.some((s) => s.panel === "strip"), ...ngDevMode ? [{ debugName: "hasStrip" }] : /* istanbul ignore next */ []);
18469
+ svgHeight = computed(() => this.resolvedHeight() + (this.hasStrip() ? 112 : 0), ...ngDevMode ? [{ debugName: "svgHeight" }] : /* istanbul ignore next */ []);
18470
+ bandCentre = computed(() => {
18471
+ const band = this.plotWidth() / Math.max(1, this.categoryData().categories.length);
18472
+ const left = this.left();
18473
+ return (i) => left + band * (i + .5);
18474
+ }, ...ngDevMode ? [{ debugName: "bandCentre" }] : /* istanbul ignore next */ []);
18475
+ categoryExtent = computed(() => {
18476
+ const main = this.categoryData().series.filter((s) => s.panel === "main");
18477
+ const values = main.flatMap((s) => s.values.filter((v) => v !== null));
18478
+ if (!values.length) return null;
18479
+ return {
18480
+ ...niceTicks(Math.min(0, ...values), Math.max(0, ...values)),
18481
+ ratio: main.every((s) => s.ratio)
18482
+ };
18483
+ }, ...ngDevMode ? [{ debugName: "categoryExtent" }] : /* istanbul ignore next */ []);
18484
+ categorySy = computed(() => {
18485
+ const extent = this.categoryExtent();
18486
+ const height = this.plotHeight();
18487
+ const top = this.top();
18488
+ return (v) => extent ? top + (1 - (v - extent.min) / (extent.max - extent.min)) * height : top + height;
18489
+ }, ...ngDevMode ? [{ debugName: "categorySy" }] : /* istanbul ignore next */ []);
18490
+ categoryView = computed(() => {
18491
+ const { categories, series } = this.categoryData();
18492
+ const extent = this.categoryExtent();
18493
+ if (!categories.length) return null;
18494
+ const n = categories.length;
18495
+ const band = this.plotWidth() / n;
18496
+ const centre = this.bandCentre();
18497
+ const sy = this.categorySy();
18498
+ const last = n - 1;
18499
+ const columnSeries = series.filter((s) => s.panel === "main" && s.mark === "column");
18500
+ const k = Math.max(1, columnSeries.length);
18501
+ const colWidth = Math.max(COLUMN_MIN, Math.min(COLUMN_MAX, (band * COLUMN_FILL - (k - 1) * COLUMN_GAP) / k));
18502
+ const group = k * colWidth + (k - 1) * COLUMN_GAP;
18503
+ const base = extent ? sy(0) : this.bottom();
18504
+ const columns = [];
18505
+ const labels = [];
18506
+ columnSeries.forEach((s, c) => {
18507
+ s.values.forEach((v, i) => {
18508
+ if (v === null) return;
18509
+ const x = centre(i) - group / 2 + c * (colWidth + COLUMN_GAP);
18510
+ columns.push({
18511
+ d: columnPath(x, colWidth, base, sy(v)),
18512
+ color: s.color
18513
+ });
18514
+ if (i === last) labels.push({
18515
+ x: x + colWidth / 2,
18516
+ y: Math.min(sy(v), base) - 6,
18517
+ text: this.formatShort(v, s.ratio)
18518
+ });
18519
+ });
18520
+ });
18521
+ const lineOf = (s, y) => {
18522
+ const dots = s.values.flatMap((v, i) => v === null ? [] : [{
18523
+ cx: centre(i),
18524
+ cy: y(v),
18525
+ v
18526
+ }]);
18527
+ return {
18528
+ d: dots.map((p, i) => `${i ? "L" : "M"}${p.cx.toFixed(1)} ${p.cy.toFixed(1)}`).join(""),
18529
+ dots
18530
+ };
18531
+ };
18532
+ return {
18533
+ columns,
18534
+ labels,
18535
+ lines: series.filter((s) => s.panel === "main" && s.mark === "line").map((s) => {
18536
+ const { d, dots } = lineOf(s, sy);
18537
+ const end = dots[dots.length - 1];
18538
+ return {
18539
+ d,
18540
+ color: s.color,
18541
+ endX: end?.cx ?? 0,
18542
+ endY: end?.cy ?? 0
18543
+ };
18544
+ }),
18545
+ strip: this.stripView(series, lineOf)
18546
+ };
18547
+ }, ...ngDevMode ? [{ debugName: "categoryView" }] : /* istanbul ignore next */ []);
18548
+ stripView = (series, lineOf) => {
18549
+ const strip = series.filter((s) => s.panel === "strip");
18550
+ const values = strip.flatMap((s) => s.values.filter((v) => v !== null));
18551
+ if (!values.length) return null;
18552
+ const lo = Math.min(...values);
18553
+ const hi = Math.max(...values);
18554
+ const pad = (hi - lo || Math.abs(hi) || 1) * .2;
18555
+ const ticks = niceTicks(lo - pad, hi + pad, 2);
18556
+ const top = this.bottom() + STRIP_GAP;
18557
+ const sy = (v) => top + (1 - (v - ticks.min) / (ticks.max - ticks.min || 1)) * STRIP_HEIGHT;
18558
+ const ratio = strip.every((s) => s.ratio);
18559
+ return {
18560
+ top,
18561
+ bottom: top + STRIP_HEIGHT,
18562
+ ticks: [ticks.min, ticks.max].map((v) => ({
18563
+ y: sy(v),
18564
+ label: this.formatShort(v, ratio)
18565
+ })),
18566
+ lines: strip.map((s) => {
18567
+ const { d, dots } = lineOf(s, sy);
18568
+ return {
18569
+ d,
18570
+ color: s.color,
18571
+ dots: dots.map((p) => ({
18572
+ ...p,
18573
+ text: this.formatShort(p.v, s.ratio)
18574
+ }))
18575
+ };
18576
+ })
18577
+ };
18578
+ };
18579
+ categoryIndex = linkedSignal({
18580
+ ...ngDevMode ? { debugName: "categoryIndex" } : /* istanbul ignore next */ {},
18581
+ source: this.categoryData,
18582
+ computation: () => null
18583
+ });
18373
18584
  lines = computed(() => {
18585
+ if (this.categorical()) return [];
18374
18586
  const palette = this.palette();
18375
18587
  const drawn = this.painted().map(({ member, color }) => ({
18376
18588
  ...member.points(),
@@ -18427,7 +18639,7 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18427
18639
  top = computed(() => this.margin().top, ...ngDevMode ? [{ debugName: "top" }] : /* istanbul ignore next */ []);
18428
18640
  right = computed(() => this.left() + this.plotWidth(), ...ngDevMode ? [{ debugName: "right" }] : /* istanbul ignore next */ []);
18429
18641
  bottom = computed(() => this.top() + this.plotHeight(), ...ngDevMode ? [{ debugName: "bottom" }] : /* istanbul ignore next */ []);
18430
- viewBox = computed(() => `0 0 ${this.width()} ${this.resolvedHeight()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
18642
+ viewBox = computed(() => `0 0 ${this.width()} ${this.svgHeight()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
18431
18643
  plotted = computed(() => {
18432
18644
  const pct = this.percent();
18433
18645
  const maxPoints = Math.max(3, Math.round(this.plotWidth() / 1.5));
@@ -18491,8 +18703,18 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18491
18703
  });
18492
18704
  }, ...ngDevMode ? [{ debugName: "paths" }] : /* istanbul ignore next */ []);
18493
18705
  yTicks = computed(() => {
18706
+ if (this.minimal()) return [];
18707
+ if (this.categorical()) {
18708
+ const extent = this.categoryExtent();
18709
+ const sy = this.categorySy();
18710
+ return (extent?.ticks ?? []).map((v) => ({
18711
+ y: sy(v),
18712
+ label: this.formatShort(v, extent?.ratio ?? false),
18713
+ zero: v === 0
18714
+ }));
18715
+ }
18494
18716
  const extent = this.extent();
18495
- if (!extent || this.minimal()) return [];
18717
+ if (!extent) return [];
18496
18718
  const sy = this.sy();
18497
18719
  const pct = this.percent();
18498
18720
  return extent.ticks.map((v) => ({
@@ -18502,8 +18724,16 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18502
18724
  }));
18503
18725
  }, ...ngDevMode ? [{ debugName: "yTicks" }] : /* istanbul ignore next */ []);
18504
18726
  xTicks = computed(() => {
18727
+ if (this.minimal()) return [];
18728
+ if (this.categorical()) {
18729
+ const centre = this.bandCentre();
18730
+ return this.categoryData().categories.map((label, i) => ({
18731
+ x: centre(i),
18732
+ label
18733
+ }));
18734
+ }
18505
18735
  const extent = this.extent();
18506
- if (!extent || this.minimal()) return [];
18736
+ if (!extent) return [];
18507
18737
  const sx = this.sx();
18508
18738
  return timeTicks(extent.t0, extent.t1, this.plotWidth() / 80).map((tick) => ({
18509
18739
  x: sx(tick.t),
@@ -18511,11 +18741,18 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18511
18741
  }));
18512
18742
  }, ...ngDevMode ? [{ debugName: "xTicks" }] : /* istanbul ignore next */ []);
18513
18743
  windowLabel = computed(() => {
18744
+ const { categories } = this.categoryData();
18745
+ if (categories.length) {
18746
+ const first = categories[0];
18747
+ const last = categories[categories.length - 1];
18748
+ return first === last ? first : `${first} – ${last}`;
18749
+ }
18514
18750
  const span = this.drawnSpan();
18515
18751
  return span ? `${this.dateFormat.format(span[0])} – ${this.dateFormat.format(span[1])}` : "";
18516
18752
  }, ...ngDevMode ? [{ debugName: "windowLabel" }] : /* istanbul ignore next */ []);
18517
18753
  periodLabel = computed(() => this.displayPeriod() || this.config()?.displayPeriod || this.windowLabel(), ...ngDevMode ? [{ debugName: "periodLabel" }] : /* istanbul ignore next */ []);
18518
18754
  legendRows = computed(() => {
18755
+ if (this.categorical()) return this.categoryLegendRows();
18519
18756
  const changes = /* @__PURE__ */ new Map();
18520
18757
  for (const line of this.windowed()) if (line.member) changes.set(line.member, chartChange(line.y));
18521
18758
  return new Map(this.painted().map(({ member, color }) => [member, {
@@ -18575,7 +18812,68 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18575
18812
  }
18576
18813
  };
18577
18814
  }, ...ngDevMode ? [{ debugName: "measureView" }] : /* istanbul ignore next */ []);
18815
+ categoryLegendRows = () => {
18816
+ const series = new Map(this.categoryData().series.map((s) => [s.member, s]));
18817
+ return new Map(this.painted().map(({ member, color }) => {
18818
+ const s = series.get(member);
18819
+ return [member, {
18820
+ color,
18821
+ ...s ? this.categoryChange(s.values, s.ratio, s.values.length - 1) : this.signedChange(null)
18822
+ }];
18823
+ }));
18824
+ };
18825
+ categoryChange = (values, ratio, i) => {
18826
+ let last = i;
18827
+ while (last >= 0 && values[last] === null) last--;
18828
+ let prev = last - 1;
18829
+ while (prev >= 0 && values[prev] === null) prev--;
18830
+ const to = values[last];
18831
+ const from = values[prev];
18832
+ if (last < 0 || prev < 0 || to == null || from == null) return this.signedChange(null);
18833
+ if (ratio) return this.signedPoints(to - from);
18834
+ return this.signedChange(from ? (to / from - 1) * 100 : null);
18835
+ };
18836
+ categoryHover = computed(() => {
18837
+ const index = this.categoryIndex();
18838
+ const { categories, series } = this.categoryData();
18839
+ if (index === null || !categories.length || this.minimal()) return null;
18840
+ const i = Math.min(index, categories.length - 1);
18841
+ const centre = this.bandCentre();
18842
+ const band = this.plotWidth() / categories.length;
18843
+ const sy = this.categorySy();
18844
+ const strip = this.categoryView()?.strip;
18845
+ const x = centre(i);
18846
+ const rows = series.flatMap((s) => {
18847
+ const v = s.values[i];
18848
+ if (v === null) return [];
18849
+ const line = s.panel === "main" && s.mark === "line";
18850
+ const change = this.categoryChange(s.values, s.ratio, i);
18851
+ return [{
18852
+ color: s.color,
18853
+ label: s.label,
18854
+ noTranslate: s.noTranslate,
18855
+ params: s.params,
18856
+ v,
18857
+ value: s.ratio ? this.formatShort(v, true) : this.numberFormat.format(v),
18858
+ sub: change.change === "—" ? "" : change.change,
18859
+ cx: line ? x : null,
18860
+ cy: line ? sy(v) : null
18861
+ }];
18862
+ });
18863
+ return {
18864
+ x,
18865
+ title: categories[i],
18866
+ rows,
18867
+ flip: x > this.width() - TOOLTIP_ROOM,
18868
+ band: {
18869
+ x: x - band / 2,
18870
+ width: band,
18871
+ bottom: strip?.bottom ?? this.bottom()
18872
+ }
18873
+ };
18874
+ }, ...ngDevMode ? [{ debugName: "categoryHover" }] : /* istanbul ignore next */ []);
18578
18875
  hover = computed(() => {
18876
+ if (this.categorical()) return this.categoryHover();
18579
18877
  const index = this.hoverIndex();
18580
18878
  const times = this.times();
18581
18879
  if (index === null || !times.length || this.minimal()) return null;
@@ -18603,7 +18901,8 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18603
18901
  x,
18604
18902
  title: this.dateFormat.format(t),
18605
18903
  rows,
18606
- flip: x > this.width() - TOOLTIP_ROOM
18904
+ flip: x > this.width() - TOOLTIP_ROOM,
18905
+ band: null
18607
18906
  };
18608
18907
  }, ...ngDevMode ? [{ debugName: "hover" }] : /* istanbul ignore next */ []);
18609
18908
  navScale = computed(() => {
@@ -18651,6 +18950,24 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18651
18950
  navTop = NAV_TOP;
18652
18951
  navViewBox = computed(() => `0 0 ${this.width()} ${NAV_HEIGHT}`, ...ngDevMode ? [{ debugName: "navViewBox" }] : /* istanbul ignore next */ []);
18653
18952
  table = computed(() => {
18953
+ if (this.categorical()) {
18954
+ const { categories, series } = this.categoryData();
18955
+ return {
18956
+ columns: series.map((s) => ({
18957
+ label: s.label,
18958
+ noTranslate: s.noTranslate,
18959
+ params: s.params
18960
+ })),
18961
+ rows: categories.map((date, i) => ({
18962
+ date,
18963
+ cells: series.map((s) => {
18964
+ const v = s.values[i];
18965
+ if (v === null) return "—";
18966
+ return s.ratio ? this.formatShort(v, true) : this.numberFormat.format(v);
18967
+ })
18968
+ })).reverse()
18969
+ };
18970
+ }
18654
18971
  const plotted = this.plotted();
18655
18972
  const pct = this.percent();
18656
18973
  const rows = [...plotted.reduce((best, p) => !best || p.line.t.length > best.line.t.length ? p : best, null)?.ds.t ?? []].reverse().map((t) => ({
@@ -18788,6 +19105,15 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18788
19105
  return times[nearestIndex(times, t)];
18789
19106
  };
18790
19107
  onPointerMove = (event) => {
19108
+ if (this.categorical()) {
19109
+ const count = this.categoryData().categories.length;
19110
+ if (!count) return;
19111
+ const rect = event.currentTarget.getBoundingClientRect();
19112
+ const px = event.clientX - rect.left - this.left();
19113
+ if (px < 0 || px > this.plotWidth()) return;
19114
+ this.categoryIndex.set(Math.min(count - 1, Math.floor(px / this.plotWidth() * count)));
19115
+ return;
19116
+ }
18791
19117
  const t = this.plotTime(event);
18792
19118
  if (t === null) return;
18793
19119
  const measured = this.measured();
@@ -18815,9 +19141,37 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18815
19141
  if (measured && measured[0] === measured[1]) this.measured.set(null);
18816
19142
  };
18817
19143
  clearHover = () => {
19144
+ this.categoryIndex.set(null);
18818
19145
  if (!this.measuring) this.hoverIndex.set(null);
18819
19146
  };
19147
+ onCategoryKeydown = (event) => {
19148
+ const count = this.categoryData().categories.length;
19149
+ if (!count) return;
19150
+ const current = this.categoryIndex();
19151
+ let next;
19152
+ switch (event.key) {
19153
+ case "ArrowLeft":
19154
+ next = Math.max(0, (current ?? count) - 1);
19155
+ break;
19156
+ case "ArrowRight":
19157
+ next = Math.min(count - 1, (current ?? -1) + 1);
19158
+ break;
19159
+ case "Home":
19160
+ next = 0;
19161
+ break;
19162
+ case "End":
19163
+ next = count - 1;
19164
+ break;
19165
+ case "Escape":
19166
+ next = null;
19167
+ break;
19168
+ default: return;
19169
+ }
19170
+ event.preventDefault();
19171
+ this.categoryIndex.set(next);
19172
+ };
18820
19173
  onKeydown = (event) => {
19174
+ if (this.categorical()) return this.onCategoryKeydown(event);
18821
19175
  const times = this.times();
18822
19176
  const count = times.length;
18823
19177
  if (!count) return;
@@ -18874,6 +19228,24 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18874
19228
  trend
18875
19229
  };
18876
19230
  };
19231
+ signedPoints = (diff) => {
19232
+ const trend = diff > 0 ? "up" : diff < 0 ? "down" : "flat";
19233
+ return {
19234
+ change: `${trend === "up" ? "▲" : trend === "down" ? "▼" : "■"} ${this.pointsFormat.format(diff)} pp`,
19235
+ trend
19236
+ };
19237
+ };
19238
+ pointsFormat = new Intl.NumberFormat(this.locale, {
19239
+ signDisplay: "exceptZero",
19240
+ minimumFractionDigits: 1,
19241
+ maximumFractionDigits: 1
19242
+ });
19243
+ levelFormat = new Intl.NumberFormat(this.locale, {
19244
+ style: "percent",
19245
+ minimumFractionDigits: 1,
19246
+ maximumFractionDigits: 1
19247
+ });
19248
+ formatShort = (v, ratio) => ratio ? this.levelFormat.format(v / 100) : this.compactFormat.format(v);
18877
19249
  percentFormats = /* @__PURE__ */ new Map();
18878
19250
  formatPercent = (v, digits) => {
18879
19251
  let format = this.percentFormats.get(digits);
@@ -18984,8 +19356,8 @@ var SectionChartComponent = class SectionChartComponent extends ConfigComponent
18984
19356
  }],
18985
19357
  usesInheritance: true,
18986
19358
  ngImport: i0,
18987
- template: "<div class=\"m-section-chart__top\">\n <!-- Each series draws its own legend row: the row is the series' element,\n which is what the editor's Canvas selects it by. -->\n <div class=\"m-section-chart__legend\" role=\"list\">\n <ng-content />\n </div>\n @if (periodLabel(); as label) {\n <span class=\"m-section-chart__window\">{{ label }}</span>\n }\n</div>\n\n<div class=\"m-section-chart__plot\">\n <svg\n class=\"m-section-chart__svg\"\n role=\"img\"\n tabindex=\"0\"\n [class.is-measurable]=\"canMeasure()\"\n [attr.width]=\"width()\"\n [attr.height]=\"resolvedHeight()\"\n [attr.viewBox]=\"viewBox()\"\n [attr.aria-label]=\"windowLabel()\"\n [attr.aria-describedby]=\"tableId\"\n (pointerdown)=\"onPlotDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPlotUp()\"\n (pointercancel)=\"onPlotUp()\"\n (pointerleave)=\"clearHover()\"\n (blur)=\"clearHover()\"\n (keydown)=\"onKeydown($event)\"\n >\n @for (tick of yTicks(); track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [class.m-section-chart__grid--zero]=\"tick.zero\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (!minimal()) {\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"bottom()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (tick of xTicks(); track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"bottom() + 18\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (measureView(); as band) {\n <svg:rect\n class=\"m-section-chart__band\"\n [attr.x]=\"band.start\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"bottom() - top()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start\"\n [attr.x2]=\"band.start\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start + band.width\"\n [attr.x2]=\"band.start + band.width\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (path of paths(); track $index) {\n @if (path.area; as area) {\n <svg:defs>\n <svg:linearGradient [attr.id]=\"path.fillId\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <svg:stop offset=\"0\" stop-opacity=\"0.22\" [attr.stop-color]=\"path.color\" />\n <svg:stop offset=\"1\" stop-opacity=\"0\" [attr.stop-color]=\"path.color\" />\n </svg:linearGradient>\n </svg:defs>\n <svg:path class=\"m-section-chart__area\" [attr.d]=\"area\" [attr.fill]=\"path.fill\" />\n }\n }\n @for (path of paths(); track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"path.d\"\n [style.stroke]=\"path.color\"\n />\n }\n @if (!minimal()) {\n @for (path of paths(); track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"path.endX\"\n [attr.cy]=\"path.endY\"\n [style.fill]=\"path.color\"\n />\n }\n }\n @if (hover(); as h) {\n <svg:line\n class=\"m-section-chart__cross\"\n [attr.x1]=\"h.x\"\n [attr.x2]=\"h.x\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n @for (row of h.rows; track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"row.cx\"\n [attr.cy]=\"row.cy\"\n [style.fill]=\"row.color\"\n />\n }\n }\n </svg>\n\n @if (hover(); as h) {\n <div\n class=\"m-section-chart__tip\"\n role=\"status\"\n [class.m-section-chart__tip--flip]=\"h.flip\"\n [style.left.px]=\"h.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ h.title }}</span>\n @for (row of h.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n\n @if (measureView()?.card; as card) {\n <div\n class=\"m-section-chart__measure\"\n role=\"status\"\n [class.m-section-chart__measure--flip]=\"card.flip\"\n [style.left.px]=\"card.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ card.title }}</span>\n @for (row of card.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n</div>\n\n@if (presets().length > 1 && !minimal()) {\n <div class=\"m-section-chart__presets\">\n <m-section-toggle\n [items]=\"presets()\"\n [selectedIndex]=\"presetIndex()\"\n [border]=\"false\"\n (action)=\"selectPreset($event)\"\n >\n <ng-template [mSectionToggleItem]=\"presets()\" let-preset>\n <span class=\"m-section-chart__preset\">{{ preset.label }}</span>\n </ng-template>\n </m-section-toggle>\n </div>\n}\n\n@if (navigatorView(); as nav) {\n <svg\n class=\"m-section-chart__navigator\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'zoom' | translate\"\n [attr.aria-valuenow]=\"nav.position\"\n [attr.aria-valuetext]=\"windowLabel()\"\n [attr.width]=\"width()\"\n [attr.height]=\"navHeight\"\n [attr.viewBox]=\"navViewBox()\"\n (pointerdown)=\"onNavigatorDown($event)\"\n (pointermove)=\"onNavigatorMove($event)\"\n (pointerup)=\"onNavigatorUp()\"\n (pointercancel)=\"onNavigatorUp()\"\n (keydown)=\"onNavigatorKeydown($event)\"\n >\n <svg:path class=\"m-section-chart__nav-area\" [attr.d]=\"nav.area\" />\n <svg:path class=\"m-section-chart__nav-line\" [attr.d]=\"nav.d\" />\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"nav.base\"\n [attr.y2]=\"nav.base\"\n />\n @for (tick of nav.ticks; track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"nav.base + 15\"\n >\n {{ tick.label }}\n </svg:text>\n }\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"left()\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.start - left()\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"nav.end\"\n [attr.y]=\"navTop\"\n [attr.width]=\"right() - nav.end\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-window\"\n [attr.x]=\"nav.start\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.end - nav.start\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.start - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.end - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n </svg>\n}\n\n<table class=\"m-section-chart__table\" [id]=\"tableId\">\n <thead>\n <tr>\n <th scope=\"col\">{{ 'date' | translate }}</th>\n @for (column of table().columns; track $index) {\n <th scope=\"col\">\n {{ column.noTranslate ? column.label : (column.label | translate: column.params) }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table().rows; track $index) {\n <tr>\n <td>{{ row.date }}</td>\n @for (cell of row.cells; track $index) {\n <td>{{ cell }}</td>\n }\n </tr>\n }\n </tbody>\n</table>\n",
18988
- styles: ["@keyframes toggle-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.02)}}@keyframes thumb-slide{0%{transform:translate(0) scale(1)}50%{transform:translate(.3em) scale(.9)}to{transform:translate(.6em) scale(1)}}:host{display:block;position:relative;width:100%;min-width:0}.m-section-chart__top{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:.5rem 1rem;margin-bottom:.5rem}.m-section-chart__legend{display:grid;gap:.15rem;min-width:0}.m-section-chart__tip-key{display:inline-block;width:.75rem;height:2px;border-radius:1px}.m-section-chart__window{color:var(--m-text-tertiary);font-size:.8rem}:host(.m-section-chart--minimal) .m-section-chart__svg{cursor:default}:host(.m-section-chart--minimal) .m-section-chart__line{stroke-width:2.25}.m-section-chart__area{stroke:none}.m-section-chart__plot{position:relative}.m-section-chart__svg{display:block;overflow:visible}.m-section-chart__svg:focus{outline:none}.m-section-chart__svg:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__svg.is-measurable{cursor:crosshair;touch-action:none;-webkit-user-select:none;user-select:none}.m-section-chart__band{fill:var(--m-text);opacity:.06}.m-section-chart__band-edge{stroke:var(--m-text-secondary);stroke-width:1}.m-section-chart__grid{stroke:var(--m-text-septenary);stroke-width:1}.m-section-chart__grid--zero{stroke:var(--m-text-quinary);stroke-width:1.5}.m-section-chart__axis{stroke:var(--m-text-quinary);stroke-width:1}.m-section-chart__tick{fill:var(--m-text-tertiary);font-size:11px;font-variant-numeric:tabular-nums}.m-section-chart__line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}.m-section-chart__dot{stroke:var(--m-background);stroke-width:2}.m-section-chart__cross{stroke:var(--m-text-secondary);stroke-width:1;opacity:.55}.m-section-chart__tip,.m-section-chart__measure{position:absolute;z-index:2;display:grid;gap:.25rem;min-width:10rem;padding:.5rem .625rem;border:1px solid var(--m-backdrop-border);border-radius:.5rem;background:var(--m-background);box-shadow:0 6px 20px var(--m-backdrop-shadow);font-size:.75rem;pointer-events:none}.m-section-chart__tip{top:0;margin-left:.875rem}.m-section-chart__tip--flip{transform:translate(calc(-100% - 1.75rem))}.m-section-chart__measure{bottom:2.25rem}.m-section-chart__measure--flip{transform:translate(-100%)}.m-section-chart__tip-title{color:var(--m-text-secondary);font-weight:600}.m-section-chart__tip-row{display:grid;grid-template-columns:.75rem auto 1fr auto;align-items:center;gap:.5rem}.m-section-chart__tip-value{color:var(--m-text);font-weight:650;font-variant-numeric:tabular-nums}.m-section-chart__tip-label{color:var(--m-text-secondary);white-space:nowrap}.m-section-chart__tip-sub{color:var(--m-text-tertiary);font-variant-numeric:tabular-nums}.m-section-chart__presets{--section-px: 0;margin-top:.5rem}.m-section-chart__preset{font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__navigator{display:block;margin-top:.25rem;overflow:visible;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}.m-section-chart__navigator:focus{outline:none}.m-section-chart__navigator:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__nav-area{fill:var(--m-text-tertiary);opacity:.12}.m-section-chart__nav-line{fill:none;stroke:var(--m-text-tertiary);stroke-width:1.25}.m-section-chart__nav-dim{fill:var(--m-background);opacity:.6}.m-section-chart__nav-window{fill:transparent;stroke:var(--m-text-secondary);stroke-width:1;cursor:grab}.m-section-chart__nav-handle{fill:var(--m-text-secondary);cursor:ew-resize}.m-section-chart__table{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"],
19359
+ template: "<div class=\"m-section-chart__top\">\n <!-- Each series draws its own legend row: the row is the series' element,\n which is what the editor's Canvas selects it by. -->\n <div class=\"m-section-chart__legend\" role=\"list\">\n <ng-content />\n </div>\n @if (periodLabel(); as label) {\n <span class=\"m-section-chart__window\">{{ label }}</span>\n }\n</div>\n\n<div class=\"m-section-chart__plot\">\n <svg\n class=\"m-section-chart__svg\"\n role=\"img\"\n tabindex=\"0\"\n [class.is-measurable]=\"canMeasure()\"\n [attr.width]=\"width()\"\n [attr.height]=\"svgHeight()\"\n [attr.viewBox]=\"viewBox()\"\n [attr.aria-label]=\"windowLabel()\"\n [attr.aria-describedby]=\"tableId\"\n (pointerdown)=\"onPlotDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPlotUp()\"\n (pointercancel)=\"onPlotUp()\"\n (pointerleave)=\"clearHover()\"\n (blur)=\"clearHover()\"\n (keydown)=\"onKeydown($event)\"\n >\n @for (tick of yTicks(); track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [class.m-section-chart__grid--zero]=\"tick.zero\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (!minimal()) {\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"bottom()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (tick of xTicks(); track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"bottom() + 18\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (measureView(); as band) {\n <svg:rect\n class=\"m-section-chart__band\"\n [attr.x]=\"band.start\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"bottom() - top()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start\"\n [attr.x2]=\"band.start\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start + band.width\"\n [attr.x2]=\"band.start + band.width\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @if (hover()?.band; as band) {\n <svg:rect\n class=\"m-section-chart__hover-band\"\n [attr.x]=\"band.x\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"band.bottom - top()\"\n />\n }\n @if (categoryView(); as cat) {\n @for (column of cat.columns; track $index) {\n <svg:path\n class=\"m-section-chart__column\"\n [attr.d]=\"column.d\"\n [style.fill]=\"column.color\"\n />\n }\n @for (line of cat.lines; track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"line.d\"\n [style.stroke]=\"line.color\"\n />\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"line.endX\"\n [attr.cy]=\"line.endY\"\n [style.fill]=\"line.color\"\n />\n }\n @for (label of cat.labels; track $index) {\n <svg:text\n class=\"m-section-chart__value\"\n text-anchor=\"middle\"\n [attr.x]=\"label.x\"\n [attr.y]=\"label.y\"\n >\n {{ label.text }}\n </svg:text>\n }\n @if (cat.strip; as strip) {\n @for (tick of strip.ticks; track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @for (line of strip.lines; track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"line.d\"\n [style.stroke]=\"line.color\"\n />\n @for (dot of line.dots; track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"dot.cx\"\n [attr.cy]=\"dot.cy\"\n [style.fill]=\"line.color\"\n />\n <svg:text\n class=\"m-section-chart__value\"\n text-anchor=\"middle\"\n [attr.x]=\"dot.cx\"\n [attr.y]=\"dot.cy - 9\"\n >\n {{ dot.text }}\n </svg:text>\n }\n }\n }\n }\n @for (path of paths(); track $index) {\n @if (path.area; as area) {\n <svg:defs>\n <svg:linearGradient [attr.id]=\"path.fillId\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <svg:stop offset=\"0\" stop-opacity=\"0.22\" [attr.stop-color]=\"path.color\" />\n <svg:stop offset=\"1\" stop-opacity=\"0\" [attr.stop-color]=\"path.color\" />\n </svg:linearGradient>\n </svg:defs>\n <svg:path class=\"m-section-chart__area\" [attr.d]=\"area\" [attr.fill]=\"path.fill\" />\n }\n }\n @for (path of paths(); track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"path.d\"\n [style.stroke]=\"path.color\"\n />\n }\n @if (!minimal()) {\n @for (path of paths(); track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"path.endX\"\n [attr.cy]=\"path.endY\"\n [style.fill]=\"path.color\"\n />\n }\n }\n @if (hover(); as h) {\n @if (!h.band) {\n <svg:line\n class=\"m-section-chart__cross\"\n [attr.x1]=\"h.x\"\n [attr.x2]=\"h.x\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (row of h.rows; track $index) {\n @if (row.cx !== null) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"row.cx\"\n [attr.cy]=\"row.cy\"\n [style.fill]=\"row.color\"\n />\n }\n }\n }\n </svg>\n\n @if (hover(); as h) {\n <div\n class=\"m-section-chart__tip\"\n role=\"status\"\n [class.m-section-chart__tip--flip]=\"h.flip\"\n [style.left.px]=\"h.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ h.title }}</span>\n @for (row of h.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n\n @if (measureView()?.card; as card) {\n <div\n class=\"m-section-chart__measure\"\n role=\"status\"\n [class.m-section-chart__measure--flip]=\"card.flip\"\n [style.left.px]=\"card.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ card.title }}</span>\n @for (row of card.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n</div>\n\n@if (presets().length > 1 && !minimal() && !categorical()) {\n <div class=\"m-section-chart__presets\">\n <m-section-toggle\n [items]=\"presets()\"\n [selectedIndex]=\"presetIndex()\"\n [border]=\"false\"\n (action)=\"selectPreset($event)\"\n >\n <ng-template [mSectionToggleItem]=\"presets()\" let-preset>\n <span class=\"m-section-chart__preset\">{{ preset.label }}</span>\n </ng-template>\n </m-section-toggle>\n </div>\n}\n\n@if (navigatorView(); as nav) {\n <svg\n class=\"m-section-chart__navigator\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'zoom' | translate\"\n [attr.aria-valuenow]=\"nav.position\"\n [attr.aria-valuetext]=\"windowLabel()\"\n [attr.width]=\"width()\"\n [attr.height]=\"navHeight\"\n [attr.viewBox]=\"navViewBox()\"\n (pointerdown)=\"onNavigatorDown($event)\"\n (pointermove)=\"onNavigatorMove($event)\"\n (pointerup)=\"onNavigatorUp()\"\n (pointercancel)=\"onNavigatorUp()\"\n (keydown)=\"onNavigatorKeydown($event)\"\n >\n <svg:path class=\"m-section-chart__nav-area\" [attr.d]=\"nav.area\" />\n <svg:path class=\"m-section-chart__nav-line\" [attr.d]=\"nav.d\" />\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"nav.base\"\n [attr.y2]=\"nav.base\"\n />\n @for (tick of nav.ticks; track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"nav.base + 15\"\n >\n {{ tick.label }}\n </svg:text>\n }\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"left()\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.start - left()\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"nav.end\"\n [attr.y]=\"navTop\"\n [attr.width]=\"right() - nav.end\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-window\"\n [attr.x]=\"nav.start\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.end - nav.start\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.start - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.end - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n </svg>\n}\n\n<table class=\"m-section-chart__table\" [id]=\"tableId\">\n <thead>\n <tr>\n <th scope=\"col\">{{ 'date' | translate }}</th>\n @for (column of table().columns; track $index) {\n <th scope=\"col\">\n {{ column.noTranslate ? column.label : (column.label | translate: column.params) }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table().rows; track $index) {\n <tr>\n <td>{{ row.date }}</td>\n @for (cell of row.cells; track $index) {\n <td>{{ cell }}</td>\n }\n </tr>\n }\n </tbody>\n</table>\n",
19360
+ styles: ["@keyframes toggle-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.02)}}@keyframes thumb-slide{0%{transform:translate(0) scale(1)}50%{transform:translate(.3em) scale(.9)}to{transform:translate(.6em) scale(1)}}:host{display:block;position:relative;width:100%;min-width:0}.m-section-chart__top{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:.5rem 1rem;margin-bottom:.5rem}.m-section-chart__legend{display:grid;gap:.15rem;min-width:0}.m-section-chart__tip-key{display:inline-block;width:.75rem;height:2px;border-radius:1px}.m-section-chart__window{color:var(--m-text-tertiary);font-size:.8rem}:host(.m-section-chart--minimal) .m-section-chart__svg{cursor:default}:host(.m-section-chart--minimal) .m-section-chart__line{stroke-width:2.25}.m-section-chart__area{stroke:none}.m-section-chart__plot{position:relative}.m-section-chart__svg{display:block;overflow:visible}.m-section-chart__svg:focus{outline:none}.m-section-chart__svg:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__svg.is-measurable{cursor:crosshair;touch-action:none;-webkit-user-select:none;user-select:none}.m-section-chart__band{fill:var(--m-text);opacity:.06}.m-section-chart__band-edge{stroke:var(--m-text-secondary);stroke-width:1}.m-section-chart__grid{stroke:var(--m-text-septenary);stroke-width:1}.m-section-chart__grid--zero{stroke:var(--m-text-quinary);stroke-width:1.5}.m-section-chart__axis{stroke:var(--m-text-quinary);stroke-width:1}.m-section-chart__tick{fill:var(--m-text-tertiary);font-size:11px;font-variant-numeric:tabular-nums}.m-section-chart__line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}.m-section-chart__dot{stroke:var(--m-background);stroke-width:2}.m-section-chart__cross{stroke:var(--m-text-secondary);stroke-width:1;opacity:.55}.m-section-chart__hover-band{fill:var(--m-text);opacity:.05}.m-section-chart__column{stroke:none}.m-section-chart__value{fill:var(--m-text-secondary);font-size:11px;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__tip,.m-section-chart__measure{position:absolute;z-index:2;display:grid;gap:.25rem;min-width:10rem;padding:.5rem .625rem;border:1px solid var(--m-backdrop-border);border-radius:.5rem;background:var(--m-background);box-shadow:0 6px 20px var(--m-backdrop-shadow);font-size:.75rem;pointer-events:none}.m-section-chart__tip{top:0;margin-left:.875rem}.m-section-chart__tip--flip{transform:translate(calc(-100% - 1.75rem))}.m-section-chart__measure{bottom:2.25rem}.m-section-chart__measure--flip{transform:translate(-100%)}.m-section-chart__tip-title{color:var(--m-text-secondary);font-weight:600}.m-section-chart__tip-row{display:grid;grid-template-columns:.75rem auto 1fr auto;align-items:center;gap:.5rem}.m-section-chart__tip-value{color:var(--m-text);font-weight:650;font-variant-numeric:tabular-nums}.m-section-chart__tip-label{color:var(--m-text-secondary);white-space:nowrap}.m-section-chart__tip-sub{color:var(--m-text-tertiary);font-variant-numeric:tabular-nums}.m-section-chart__presets{--section-px: 0;margin-top:.5rem}.m-section-chart__preset{font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__navigator{display:block;margin-top:.25rem;overflow:visible;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}.m-section-chart__navigator:focus{outline:none}.m-section-chart__navigator:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__nav-area{fill:var(--m-text-tertiary);opacity:.12}.m-section-chart__nav-line{fill:none;stroke:var(--m-text-tertiary);stroke-width:1.25}.m-section-chart__nav-dim{fill:var(--m-background);opacity:.6}.m-section-chart__nav-window{fill:transparent;stroke:var(--m-text-secondary);stroke-width:1;cursor:grab}.m-section-chart__nav-handle{fill:var(--m-text-secondary);cursor:ew-resize}.m-section-chart__table{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"],
18989
19361
  dependencies: [
18990
19362
  {
18991
19363
  kind: "component",
@@ -19045,8 +19417,8 @@ i0.ɵɵngDeclareClassMetadata({
19045
19417
  };
19046
19418
  }
19047
19419
  }],
19048
- template: "<div class=\"m-section-chart__top\">\n <!-- Each series draws its own legend row: the row is the series' element,\n which is what the editor's Canvas selects it by. -->\n <div class=\"m-section-chart__legend\" role=\"list\">\n <ng-content />\n </div>\n @if (periodLabel(); as label) {\n <span class=\"m-section-chart__window\">{{ label }}</span>\n }\n</div>\n\n<div class=\"m-section-chart__plot\">\n <svg\n class=\"m-section-chart__svg\"\n role=\"img\"\n tabindex=\"0\"\n [class.is-measurable]=\"canMeasure()\"\n [attr.width]=\"width()\"\n [attr.height]=\"resolvedHeight()\"\n [attr.viewBox]=\"viewBox()\"\n [attr.aria-label]=\"windowLabel()\"\n [attr.aria-describedby]=\"tableId\"\n (pointerdown)=\"onPlotDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPlotUp()\"\n (pointercancel)=\"onPlotUp()\"\n (pointerleave)=\"clearHover()\"\n (blur)=\"clearHover()\"\n (keydown)=\"onKeydown($event)\"\n >\n @for (tick of yTicks(); track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [class.m-section-chart__grid--zero]=\"tick.zero\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (!minimal()) {\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"bottom()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (tick of xTicks(); track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"bottom() + 18\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (measureView(); as band) {\n <svg:rect\n class=\"m-section-chart__band\"\n [attr.x]=\"band.start\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"bottom() - top()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start\"\n [attr.x2]=\"band.start\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start + band.width\"\n [attr.x2]=\"band.start + band.width\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (path of paths(); track $index) {\n @if (path.area; as area) {\n <svg:defs>\n <svg:linearGradient [attr.id]=\"path.fillId\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <svg:stop offset=\"0\" stop-opacity=\"0.22\" [attr.stop-color]=\"path.color\" />\n <svg:stop offset=\"1\" stop-opacity=\"0\" [attr.stop-color]=\"path.color\" />\n </svg:linearGradient>\n </svg:defs>\n <svg:path class=\"m-section-chart__area\" [attr.d]=\"area\" [attr.fill]=\"path.fill\" />\n }\n }\n @for (path of paths(); track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"path.d\"\n [style.stroke]=\"path.color\"\n />\n }\n @if (!minimal()) {\n @for (path of paths(); track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"path.endX\"\n [attr.cy]=\"path.endY\"\n [style.fill]=\"path.color\"\n />\n }\n }\n @if (hover(); as h) {\n <svg:line\n class=\"m-section-chart__cross\"\n [attr.x1]=\"h.x\"\n [attr.x2]=\"h.x\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n @for (row of h.rows; track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"row.cx\"\n [attr.cy]=\"row.cy\"\n [style.fill]=\"row.color\"\n />\n }\n }\n </svg>\n\n @if (hover(); as h) {\n <div\n class=\"m-section-chart__tip\"\n role=\"status\"\n [class.m-section-chart__tip--flip]=\"h.flip\"\n [style.left.px]=\"h.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ h.title }}</span>\n @for (row of h.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n\n @if (measureView()?.card; as card) {\n <div\n class=\"m-section-chart__measure\"\n role=\"status\"\n [class.m-section-chart__measure--flip]=\"card.flip\"\n [style.left.px]=\"card.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ card.title }}</span>\n @for (row of card.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n</div>\n\n@if (presets().length > 1 && !minimal()) {\n <div class=\"m-section-chart__presets\">\n <m-section-toggle\n [items]=\"presets()\"\n [selectedIndex]=\"presetIndex()\"\n [border]=\"false\"\n (action)=\"selectPreset($event)\"\n >\n <ng-template [mSectionToggleItem]=\"presets()\" let-preset>\n <span class=\"m-section-chart__preset\">{{ preset.label }}</span>\n </ng-template>\n </m-section-toggle>\n </div>\n}\n\n@if (navigatorView(); as nav) {\n <svg\n class=\"m-section-chart__navigator\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'zoom' | translate\"\n [attr.aria-valuenow]=\"nav.position\"\n [attr.aria-valuetext]=\"windowLabel()\"\n [attr.width]=\"width()\"\n [attr.height]=\"navHeight\"\n [attr.viewBox]=\"navViewBox()\"\n (pointerdown)=\"onNavigatorDown($event)\"\n (pointermove)=\"onNavigatorMove($event)\"\n (pointerup)=\"onNavigatorUp()\"\n (pointercancel)=\"onNavigatorUp()\"\n (keydown)=\"onNavigatorKeydown($event)\"\n >\n <svg:path class=\"m-section-chart__nav-area\" [attr.d]=\"nav.area\" />\n <svg:path class=\"m-section-chart__nav-line\" [attr.d]=\"nav.d\" />\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"nav.base\"\n [attr.y2]=\"nav.base\"\n />\n @for (tick of nav.ticks; track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"nav.base + 15\"\n >\n {{ tick.label }}\n </svg:text>\n }\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"left()\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.start - left()\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"nav.end\"\n [attr.y]=\"navTop\"\n [attr.width]=\"right() - nav.end\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-window\"\n [attr.x]=\"nav.start\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.end - nav.start\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.start - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.end - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n </svg>\n}\n\n<table class=\"m-section-chart__table\" [id]=\"tableId\">\n <thead>\n <tr>\n <th scope=\"col\">{{ 'date' | translate }}</th>\n @for (column of table().columns; track $index) {\n <th scope=\"col\">\n {{ column.noTranslate ? column.label : (column.label | translate: column.params) }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table().rows; track $index) {\n <tr>\n <td>{{ row.date }}</td>\n @for (cell of row.cells; track $index) {\n <td>{{ cell }}</td>\n }\n </tr>\n }\n </tbody>\n</table>\n",
19049
- styles: ["@keyframes toggle-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.02)}}@keyframes thumb-slide{0%{transform:translate(0) scale(1)}50%{transform:translate(.3em) scale(.9)}to{transform:translate(.6em) scale(1)}}:host{display:block;position:relative;width:100%;min-width:0}.m-section-chart__top{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:.5rem 1rem;margin-bottom:.5rem}.m-section-chart__legend{display:grid;gap:.15rem;min-width:0}.m-section-chart__tip-key{display:inline-block;width:.75rem;height:2px;border-radius:1px}.m-section-chart__window{color:var(--m-text-tertiary);font-size:.8rem}:host(.m-section-chart--minimal) .m-section-chart__svg{cursor:default}:host(.m-section-chart--minimal) .m-section-chart__line{stroke-width:2.25}.m-section-chart__area{stroke:none}.m-section-chart__plot{position:relative}.m-section-chart__svg{display:block;overflow:visible}.m-section-chart__svg:focus{outline:none}.m-section-chart__svg:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__svg.is-measurable{cursor:crosshair;touch-action:none;-webkit-user-select:none;user-select:none}.m-section-chart__band{fill:var(--m-text);opacity:.06}.m-section-chart__band-edge{stroke:var(--m-text-secondary);stroke-width:1}.m-section-chart__grid{stroke:var(--m-text-septenary);stroke-width:1}.m-section-chart__grid--zero{stroke:var(--m-text-quinary);stroke-width:1.5}.m-section-chart__axis{stroke:var(--m-text-quinary);stroke-width:1}.m-section-chart__tick{fill:var(--m-text-tertiary);font-size:11px;font-variant-numeric:tabular-nums}.m-section-chart__line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}.m-section-chart__dot{stroke:var(--m-background);stroke-width:2}.m-section-chart__cross{stroke:var(--m-text-secondary);stroke-width:1;opacity:.55}.m-section-chart__tip,.m-section-chart__measure{position:absolute;z-index:2;display:grid;gap:.25rem;min-width:10rem;padding:.5rem .625rem;border:1px solid var(--m-backdrop-border);border-radius:.5rem;background:var(--m-background);box-shadow:0 6px 20px var(--m-backdrop-shadow);font-size:.75rem;pointer-events:none}.m-section-chart__tip{top:0;margin-left:.875rem}.m-section-chart__tip--flip{transform:translate(calc(-100% - 1.75rem))}.m-section-chart__measure{bottom:2.25rem}.m-section-chart__measure--flip{transform:translate(-100%)}.m-section-chart__tip-title{color:var(--m-text-secondary);font-weight:600}.m-section-chart__tip-row{display:grid;grid-template-columns:.75rem auto 1fr auto;align-items:center;gap:.5rem}.m-section-chart__tip-value{color:var(--m-text);font-weight:650;font-variant-numeric:tabular-nums}.m-section-chart__tip-label{color:var(--m-text-secondary);white-space:nowrap}.m-section-chart__tip-sub{color:var(--m-text-tertiary);font-variant-numeric:tabular-nums}.m-section-chart__presets{--section-px: 0;margin-top:.5rem}.m-section-chart__preset{font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__navigator{display:block;margin-top:.25rem;overflow:visible;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}.m-section-chart__navigator:focus{outline:none}.m-section-chart__navigator:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__nav-area{fill:var(--m-text-tertiary);opacity:.12}.m-section-chart__nav-line{fill:none;stroke:var(--m-text-tertiary);stroke-width:1.25}.m-section-chart__nav-dim{fill:var(--m-background);opacity:.6}.m-section-chart__nav-window{fill:transparent;stroke:var(--m-text-secondary);stroke-width:1;cursor:grab}.m-section-chart__nav-handle{fill:var(--m-text-secondary);cursor:ew-resize}.m-section-chart__table{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"]
19420
+ template: "<div class=\"m-section-chart__top\">\n <!-- Each series draws its own legend row: the row is the series' element,\n which is what the editor's Canvas selects it by. -->\n <div class=\"m-section-chart__legend\" role=\"list\">\n <ng-content />\n </div>\n @if (periodLabel(); as label) {\n <span class=\"m-section-chart__window\">{{ label }}</span>\n }\n</div>\n\n<div class=\"m-section-chart__plot\">\n <svg\n class=\"m-section-chart__svg\"\n role=\"img\"\n tabindex=\"0\"\n [class.is-measurable]=\"canMeasure()\"\n [attr.width]=\"width()\"\n [attr.height]=\"svgHeight()\"\n [attr.viewBox]=\"viewBox()\"\n [attr.aria-label]=\"windowLabel()\"\n [attr.aria-describedby]=\"tableId\"\n (pointerdown)=\"onPlotDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPlotUp()\"\n (pointercancel)=\"onPlotUp()\"\n (pointerleave)=\"clearHover()\"\n (blur)=\"clearHover()\"\n (keydown)=\"onKeydown($event)\"\n >\n @for (tick of yTicks(); track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [class.m-section-chart__grid--zero]=\"tick.zero\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (!minimal()) {\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"bottom()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (tick of xTicks(); track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"bottom() + 18\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @if (measureView(); as band) {\n <svg:rect\n class=\"m-section-chart__band\"\n [attr.x]=\"band.start\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"bottom() - top()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start\"\n [attr.x2]=\"band.start\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n <svg:line\n class=\"m-section-chart__band-edge\"\n [attr.x1]=\"band.start + band.width\"\n [attr.x2]=\"band.start + band.width\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @if (hover()?.band; as band) {\n <svg:rect\n class=\"m-section-chart__hover-band\"\n [attr.x]=\"band.x\"\n [attr.y]=\"top()\"\n [attr.width]=\"band.width\"\n [attr.height]=\"band.bottom - top()\"\n />\n }\n @if (categoryView(); as cat) {\n @for (column of cat.columns; track $index) {\n <svg:path\n class=\"m-section-chart__column\"\n [attr.d]=\"column.d\"\n [style.fill]=\"column.color\"\n />\n }\n @for (line of cat.lines; track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"line.d\"\n [style.stroke]=\"line.color\"\n />\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"line.endX\"\n [attr.cy]=\"line.endY\"\n [style.fill]=\"line.color\"\n />\n }\n @for (label of cat.labels; track $index) {\n <svg:text\n class=\"m-section-chart__value\"\n text-anchor=\"middle\"\n [attr.x]=\"label.x\"\n [attr.y]=\"label.y\"\n >\n {{ label.text }}\n </svg:text>\n }\n @if (cat.strip; as strip) {\n @for (tick of strip.ticks; track $index) {\n <svg:line\n class=\"m-section-chart__grid\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"end\"\n [attr.x]=\"left() - 8\"\n [attr.y]=\"tick.y + 4\"\n >\n {{ tick.label }}\n </svg:text>\n }\n @for (line of strip.lines; track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"line.d\"\n [style.stroke]=\"line.color\"\n />\n @for (dot of line.dots; track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"dot.cx\"\n [attr.cy]=\"dot.cy\"\n [style.fill]=\"line.color\"\n />\n <svg:text\n class=\"m-section-chart__value\"\n text-anchor=\"middle\"\n [attr.x]=\"dot.cx\"\n [attr.y]=\"dot.cy - 9\"\n >\n {{ dot.text }}\n </svg:text>\n }\n }\n }\n }\n @for (path of paths(); track $index) {\n @if (path.area; as area) {\n <svg:defs>\n <svg:linearGradient [attr.id]=\"path.fillId\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <svg:stop offset=\"0\" stop-opacity=\"0.22\" [attr.stop-color]=\"path.color\" />\n <svg:stop offset=\"1\" stop-opacity=\"0\" [attr.stop-color]=\"path.color\" />\n </svg:linearGradient>\n </svg:defs>\n <svg:path class=\"m-section-chart__area\" [attr.d]=\"area\" [attr.fill]=\"path.fill\" />\n }\n }\n @for (path of paths(); track $index) {\n <svg:path\n class=\"m-section-chart__line\"\n [attr.d]=\"path.d\"\n [style.stroke]=\"path.color\"\n />\n }\n @if (!minimal()) {\n @for (path of paths(); track $index) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"path.endX\"\n [attr.cy]=\"path.endY\"\n [style.fill]=\"path.color\"\n />\n }\n }\n @if (hover(); as h) {\n @if (!h.band) {\n <svg:line\n class=\"m-section-chart__cross\"\n [attr.x1]=\"h.x\"\n [attr.x2]=\"h.x\"\n [attr.y1]=\"top()\"\n [attr.y2]=\"bottom()\"\n />\n }\n @for (row of h.rows; track $index) {\n @if (row.cx !== null) {\n <svg:circle\n class=\"m-section-chart__dot\"\n r=\"4\"\n [attr.cx]=\"row.cx\"\n [attr.cy]=\"row.cy\"\n [style.fill]=\"row.color\"\n />\n }\n }\n }\n </svg>\n\n @if (hover(); as h) {\n <div\n class=\"m-section-chart__tip\"\n role=\"status\"\n [class.m-section-chart__tip--flip]=\"h.flip\"\n [style.left.px]=\"h.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ h.title }}</span>\n @for (row of h.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n\n @if (measureView()?.card; as card) {\n <div\n class=\"m-section-chart__measure\"\n role=\"status\"\n [class.m-section-chart__measure--flip]=\"card.flip\"\n [style.left.px]=\"card.x\"\n >\n <span class=\"m-section-chart__tip-title\">{{ card.title }}</span>\n @for (row of card.rows; track $index) {\n <span class=\"m-section-chart__tip-row\">\n <span class=\"m-section-chart__tip-key\" [style.background]=\"row.color\"></span>\n <span class=\"m-section-chart__tip-value\">{{ row.value }}</span>\n <span class=\"m-section-chart__tip-label\">{{\n row.noTranslate ? row.label : (row.label | translate: row.params)\n }}</span>\n <span class=\"m-section-chart__tip-sub\">{{ row.sub }}</span>\n </span>\n }\n </div>\n }\n</div>\n\n@if (presets().length > 1 && !minimal() && !categorical()) {\n <div class=\"m-section-chart__presets\">\n <m-section-toggle\n [items]=\"presets()\"\n [selectedIndex]=\"presetIndex()\"\n [border]=\"false\"\n (action)=\"selectPreset($event)\"\n >\n <ng-template [mSectionToggleItem]=\"presets()\" let-preset>\n <span class=\"m-section-chart__preset\">{{ preset.label }}</span>\n </ng-template>\n </m-section-toggle>\n </div>\n}\n\n@if (navigatorView(); as nav) {\n <svg\n class=\"m-section-chart__navigator\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"'zoom' | translate\"\n [attr.aria-valuenow]=\"nav.position\"\n [attr.aria-valuetext]=\"windowLabel()\"\n [attr.width]=\"width()\"\n [attr.height]=\"navHeight\"\n [attr.viewBox]=\"navViewBox()\"\n (pointerdown)=\"onNavigatorDown($event)\"\n (pointermove)=\"onNavigatorMove($event)\"\n (pointerup)=\"onNavigatorUp()\"\n (pointercancel)=\"onNavigatorUp()\"\n (keydown)=\"onNavigatorKeydown($event)\"\n >\n <svg:path class=\"m-section-chart__nav-area\" [attr.d]=\"nav.area\" />\n <svg:path class=\"m-section-chart__nav-line\" [attr.d]=\"nav.d\" />\n <svg:line\n class=\"m-section-chart__axis\"\n [attr.x1]=\"left()\"\n [attr.x2]=\"right()\"\n [attr.y1]=\"nav.base\"\n [attr.y2]=\"nav.base\"\n />\n @for (tick of nav.ticks; track $index) {\n <svg:text\n class=\"m-section-chart__tick\"\n text-anchor=\"middle\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"nav.base + 15\"\n >\n {{ tick.label }}\n </svg:text>\n }\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"left()\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.start - left()\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-dim\"\n [attr.x]=\"nav.end\"\n [attr.y]=\"navTop\"\n [attr.width]=\"right() - nav.end\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-window\"\n [attr.x]=\"nav.start\"\n [attr.y]=\"navTop\"\n [attr.width]=\"nav.end - nav.start\"\n [attr.height]=\"nav.base - navTop\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.start - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n <svg:rect\n class=\"m-section-chart__nav-handle\"\n rx=\"2\"\n width=\"6\"\n height=\"20\"\n [attr.x]=\"nav.end - 3\"\n [attr.y]=\"(nav.base + navTop) / 2 - 10\"\n />\n </svg>\n}\n\n<table class=\"m-section-chart__table\" [id]=\"tableId\">\n <thead>\n <tr>\n <th scope=\"col\">{{ 'date' | translate }}</th>\n @for (column of table().columns; track $index) {\n <th scope=\"col\">\n {{ column.noTranslate ? column.label : (column.label | translate: column.params) }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table().rows; track $index) {\n <tr>\n <td>{{ row.date }}</td>\n @for (cell of row.cells; track $index) {\n <td>{{ cell }}</td>\n }\n </tr>\n }\n </tbody>\n</table>\n",
19421
+ styles: ["@keyframes toggle-pulse{0%,to{transform:scale(1)}50%{transform:scale(1.02)}}@keyframes thumb-slide{0%{transform:translate(0) scale(1)}50%{transform:translate(.3em) scale(.9)}to{transform:translate(.6em) scale(1)}}:host{display:block;position:relative;width:100%;min-width:0}.m-section-chart__top{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:.5rem 1rem;margin-bottom:.5rem}.m-section-chart__legend{display:grid;gap:.15rem;min-width:0}.m-section-chart__tip-key{display:inline-block;width:.75rem;height:2px;border-radius:1px}.m-section-chart__window{color:var(--m-text-tertiary);font-size:.8rem}:host(.m-section-chart--minimal) .m-section-chart__svg{cursor:default}:host(.m-section-chart--minimal) .m-section-chart__line{stroke-width:2.25}.m-section-chart__area{stroke:none}.m-section-chart__plot{position:relative}.m-section-chart__svg{display:block;overflow:visible}.m-section-chart__svg:focus{outline:none}.m-section-chart__svg:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__svg.is-measurable{cursor:crosshair;touch-action:none;-webkit-user-select:none;user-select:none}.m-section-chart__band{fill:var(--m-text);opacity:.06}.m-section-chart__band-edge{stroke:var(--m-text-secondary);stroke-width:1}.m-section-chart__grid{stroke:var(--m-text-septenary);stroke-width:1}.m-section-chart__grid--zero{stroke:var(--m-text-quinary);stroke-width:1.5}.m-section-chart__axis{stroke:var(--m-text-quinary);stroke-width:1}.m-section-chart__tick{fill:var(--m-text-tertiary);font-size:11px;font-variant-numeric:tabular-nums}.m-section-chart__line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}.m-section-chart__dot{stroke:var(--m-background);stroke-width:2}.m-section-chart__cross{stroke:var(--m-text-secondary);stroke-width:1;opacity:.55}.m-section-chart__hover-band{fill:var(--m-text);opacity:.05}.m-section-chart__column{stroke:none}.m-section-chart__value{fill:var(--m-text-secondary);font-size:11px;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__tip,.m-section-chart__measure{position:absolute;z-index:2;display:grid;gap:.25rem;min-width:10rem;padding:.5rem .625rem;border:1px solid var(--m-backdrop-border);border-radius:.5rem;background:var(--m-background);box-shadow:0 6px 20px var(--m-backdrop-shadow);font-size:.75rem;pointer-events:none}.m-section-chart__tip{top:0;margin-left:.875rem}.m-section-chart__tip--flip{transform:translate(calc(-100% - 1.75rem))}.m-section-chart__measure{bottom:2.25rem}.m-section-chart__measure--flip{transform:translate(-100%)}.m-section-chart__tip-title{color:var(--m-text-secondary);font-weight:600}.m-section-chart__tip-row{display:grid;grid-template-columns:.75rem auto 1fr auto;align-items:center;gap:.5rem}.m-section-chart__tip-value{color:var(--m-text);font-weight:650;font-variant-numeric:tabular-nums}.m-section-chart__tip-label{color:var(--m-text-secondary);white-space:nowrap}.m-section-chart__tip-sub{color:var(--m-text-tertiary);font-variant-numeric:tabular-nums}.m-section-chart__presets{--section-px: 0;margin-top:.5rem}.m-section-chart__preset{font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums}.m-section-chart__navigator{display:block;margin-top:.25rem;overflow:visible;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}.m-section-chart__navigator:focus{outline:none}.m-section-chart__navigator:focus-visible{outline:2px solid var(--m-focus);outline-offset:4px;border-radius:4px}.m-section-chart__nav-area{fill:var(--m-text-tertiary);opacity:.12}.m-section-chart__nav-line{fill:none;stroke:var(--m-text-tertiary);stroke-width:1.25}.m-section-chart__nav-dim{fill:var(--m-background);opacity:.6}.m-section-chart__nav-window{fill:transparent;stroke:var(--m-text-secondary);stroke-width:1;cursor:grab}.m-section-chart__nav-handle{fill:var(--m-text-secondary);cursor:ew-resize}.m-section-chart__table{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"]
19050
19422
  }]
19051
19423
  }],
19052
19424
  ctorParameters: () => [],
@@ -19131,7 +19503,12 @@ var SectionChartSeriesComponent = class SectionChartSeriesComponent {
19131
19503
  noTranslate = input(false, ...ngDevMode ? [{ debugName: "noTranslate" }] : /* istanbul ignore next */ []);
19132
19504
  params = input(void 0, ...ngDevMode ? [{ debugName: "params" }] : /* istanbul ignore next */ []);
19133
19505
  color = input(void 0, ...ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []);
19134
- points = computed(() => readChartPoints(this.data(), this.x(), this.y()), ...ngDevMode ? [{ debugName: "points" }] : /* istanbul ignore next */ []);
19506
+ mark = input("line", ...ngDevMode ? [{ debugName: "mark" }] : /* istanbul ignore next */ []);
19507
+ per = input(void 0, ...ngDevMode ? [{ debugName: "per" }] : /* istanbul ignore next */ []);
19508
+ panel = input("main", ...ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []);
19509
+ points = computed(() => readChartPoints(this.data(), this.x(), this.y(), this.per()), ...ngDevMode ? [{ debugName: "points" }] : /* istanbul ignore next */ []);
19510
+ categories = computed(() => readChartCategories(this.data(), this.x(), this.y(), this.per()), ...ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []);
19511
+ ratio = computed(() => !!this.per(), ...ngDevMode ? [{ debugName: "ratio" }] : /* istanbul ignore next */ []);
19135
19512
  row;
19136
19513
  constructor() {
19137
19514
  const chart = inject(SECTION_CHART_CONTEXT, { optional: true });
@@ -19141,6 +19518,10 @@ var SectionChartSeriesComponent = class SectionChartSeriesComponent {
19141
19518
  }
19142
19519
  const member = {
19143
19520
  points: this.points,
19521
+ categories: this.categories,
19522
+ mark: this.mark,
19523
+ panel: this.panel,
19524
+ ratio: this.ratio,
19144
19525
  label: this.label,
19145
19526
  noTranslate: this.noTranslate,
19146
19527
  params: this.params,
@@ -19213,6 +19594,27 @@ var SectionChartSeriesComponent = class SectionChartSeriesComponent {
19213
19594
  isSignal: true,
19214
19595
  isRequired: false,
19215
19596
  transformFunction: null
19597
+ },
19598
+ mark: {
19599
+ classPropertyName: "mark",
19600
+ publicName: "mark",
19601
+ isSignal: true,
19602
+ isRequired: false,
19603
+ transformFunction: null
19604
+ },
19605
+ per: {
19606
+ classPropertyName: "per",
19607
+ publicName: "per",
19608
+ isSignal: true,
19609
+ isRequired: false,
19610
+ transformFunction: null
19611
+ },
19612
+ panel: {
19613
+ classPropertyName: "panel",
19614
+ publicName: "panel",
19615
+ isSignal: true,
19616
+ isRequired: false,
19617
+ transformFunction: null
19216
19618
  }
19217
19619
  },
19218
19620
  host: {
@@ -19341,6 +19743,30 @@ i0.ɵɵngDeclareClassMetadata({
19341
19743
  alias: "color",
19342
19744
  required: false
19343
19745
  }]
19746
+ }],
19747
+ mark: [{
19748
+ type: i0.Input,
19749
+ args: [{
19750
+ isSignal: true,
19751
+ alias: "mark",
19752
+ required: false
19753
+ }]
19754
+ }],
19755
+ per: [{
19756
+ type: i0.Input,
19757
+ args: [{
19758
+ isSignal: true,
19759
+ alias: "per",
19760
+ required: false
19761
+ }]
19762
+ }],
19763
+ panel: [{
19764
+ type: i0.Input,
19765
+ args: [{
19766
+ isSignal: true,
19767
+ alias: "panel",
19768
+ required: false
19769
+ }]
19344
19770
  }]
19345
19771
  }
19346
19772
  });