pptx-angular-viewer 3.19.1 → 3.19.2

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.
@@ -4974,6 +4974,78 @@ function resolveGroupChildFill(child, parentGroupFill) {
4974
4974
  return getComputedFillStyle(child, parentGroupFill);
4975
4975
  }
4976
4976
 
4977
+ /**
4978
+ * The exact algebraic inverse of {@link getElementTransform} (from
4979
+ * `element-style-transform.ts`), restricted to rotation + flip (no skew: a
4980
+ * skewed image fill with `rotWithShape="0"` is rare enough that an exact
4981
+ * shear inverse is not worth the added complexity yet).
4982
+ *
4983
+ * Derivation: `getElementTransform` emits the CSS list
4984
+ * `rotate(θ) scaleX(fx) scaleY(fy)`, i.e. the matrix product `R * Sx * Sy`
4985
+ * (CSS applies the RIGHTMOST function to the point first). Its inverse is
4986
+ * `Sy⁻¹ * Sx⁻¹ * R⁻¹ = Sy * Sx * R(-θ)` (flips are self-inverse), which as a
4987
+ * CSS list is `scaleY(fy) scaleX(fx) rotate(-θ deg)` - order matters, and
4988
+ * differs from the forward transform's order.
4989
+ *
4990
+ * @param element - The element whose `rotation`/`flipHorizontal`/`flipVertical` are read.
4991
+ * @returns A CSS transform string, or `undefined` if no counter-transform is needed.
4992
+ */
4993
+ function getFrameInverseTransform(element) {
4994
+ const transforms = [];
4995
+ if (element.flipVertical) {
4996
+ transforms.push('scaleY(-1)');
4997
+ }
4998
+ if (element.flipHorizontal) {
4999
+ transforms.push('scaleX(-1)');
5000
+ }
5001
+ if (element.rotation) {
5002
+ transforms.push(`rotate(${-element.rotation}deg)`);
5003
+ }
5004
+ return transforms.length > 0 ? transforms.join(' ') : undefined;
5005
+ }
5006
+ /**
5007
+ * CSS `transform` to apply to a picture's / image fill's CONTENT layer (the
5008
+ * `<img>`, or a `background-image` layer) so it renders upright/unmirrored,
5009
+ * fixed to the page frame, when the owning element's image fill explicitly
5010
+ * disables `rotWithShape` (`ShapeStyle.fillImageRotWithShape === false`).
5011
+ *
5012
+ * `undefined` (apply nothing; keep today's behaviour) when:
5013
+ * - the element has no shape styling, or its fill is not an image fill with
5014
+ * `rotWithShape` explicitly false (the default, `true`/unset, means the
5015
+ * fill rotates/flips WITH the shape, which is what already happens when
5016
+ * the content layer has no transform of its own), or
5017
+ * - the shape has no rotation/flip to counteract in the first place.
5018
+ *
5019
+ * Callers MUST keep the shape's own geometry mask (clip-path/border-radius)
5020
+ * on the STATIONARY frame container (never on this same content layer): the
5021
+ * container inherits the shape's rotate/flip so the visible clipped silhouette
5022
+ * still matches PowerPoint, while the content layer's own counter-transform
5023
+ * only affects its pixels, not the ancestor's clip region. A binding whose
5024
+ * content layer sometimes also carries its own copy of that clip-path (as a
5025
+ * micro-optimisation for the untransformed case) must suppress that copy
5026
+ * whenever this function returns a value, or the clip-path would double-flip
5027
+ * along with the content.
5028
+ *
5029
+ * Not applied when the content layer already carries a competing transform
5030
+ * (an `a:srcRect` source-crop translate/scale, see `getImageFitStyle`): the
5031
+ * two transforms' origins conflict (crop uses `top left`, this uses the
5032
+ * element's own `center`), so combining them is left as a follow-up; the far
5033
+ * more common crop takes priority. Pass `hasCompetingTransform: true` to skip
5034
+ * in that case.
5035
+ *
5036
+ * @param element - The element to inspect (reads `element.shapeStyle.fillImageRotWithShape`).
5037
+ * @param hasCompetingTransform - True when the content layer already has its own transform for an `a:srcRect` crop.
5038
+ */
5039
+ function getImageFillCounterTransform(element, hasCompetingTransform = false) {
5040
+ if (hasCompetingTransform || !hasShapeProperties(element)) {
5041
+ return undefined;
5042
+ }
5043
+ if (element.shapeStyle?.fillImageRotWithShape !== false) {
5044
+ return undefined;
5045
+ }
5046
+ return getFrameInverseTransform(element);
5047
+ }
5048
+
4977
5049
  /**
4978
5050
  * OOXML drawing-colour resolution: colour-choice parsing (srgb/scrgb/sys/scheme/
4979
5051
  * hsl/preset), the 26 colour transforms, scheme inheritance, and alpha
@@ -14195,13 +14267,23 @@ function resolveCategoryLabels(chartData) {
14195
14267
  * SVG. PowerPoint decks routinely write `<c:spPr><a:noFill/></c:spPr>` on
14196
14268
  * `c:chartSpace` and `c:plotArea` precisely so the chart floats on the slide;
14197
14269
  * the wash boxed every such chart into a visible grey panel that is not in the
14198
- * source. Honouring the authored fill is the fix, and keeping the wash as the
14199
- * fallback leaves charts that say nothing looking exactly as they did.
14200
- */
14201
- /**
14202
- * The wash the bindings have always painted when a chart declares no fill of
14203
- * its own. Kept as the default so an unstyled chart still reads as a distinct
14204
- * surface against the slide.
14270
+ * source. Honouring the authored fill (an explicit `<a:noFill/>`) was the
14271
+ * first fix, but a chart with NO `c:spPr` at all (the common case: only a
14272
+ * deliberately-styled chart writes one) still fell back to the same synthetic
14273
+ * wash, which is just as wrong: real PowerPoint never paints a highlight box
14274
+ * behind an unstyled chart, it is fully transparent like the `noFill` case.
14275
+ * Measured against a real-world deck (a plain single-series bar chart with no
14276
+ * `c:chartSpace/c:spPr` at all) PowerPoint's own export shows no grey
14277
+ * anywhere; this module now treats "no fill recorded" the same whether the
14278
+ * source said `noFill` explicitly or said nothing, matching `plotAreaFill`
14279
+ * below, which never had a synthetic default in the first place.
14280
+ */
14281
+ /**
14282
+ * The wash the bindings used to paint whenever a chart declared no fill of
14283
+ * its own. No longer used as an automatic default for real chart data (see
14284
+ * the module doc comment); kept only for `buildFallbackViewModel`'s
14285
+ * unsupported/empty-chart placeholder, which has no chart data to read a fill
14286
+ * from and still wants a visible box to represent "a chart goes here".
14205
14287
  */
14206
14288
  const DEFAULT_CHART_AREA_FILL = '#0f172a11';
14207
14289
  /** Resolve one recorded fill value to an SVG `fill`, or `undefined` to skip. */
@@ -14213,10 +14295,11 @@ function resolve(fill, fallback) {
14213
14295
  }
14214
14296
  /**
14215
14297
  * SVG `fill` for the chart-area rect, or `undefined` when nothing should be
14216
- * painted (the source declared `a:noFill`).
14298
+ * painted: the source declared `a:noFill`, or (matching real PowerPoint)
14299
+ * simply never wrote a `c:chartSpace/c:spPr` at all.
14217
14300
  */
14218
14301
  function chartAreaFill(chartData) {
14219
- return resolve(chartData?.style?.chartAreaFill, DEFAULT_CHART_AREA_FILL);
14302
+ return resolve(chartData?.style?.chartAreaFill, undefined);
14220
14303
  }
14221
14304
  /**
14222
14305
  * SVG `fill` for the plot-area rect, or `undefined` when nothing should be
@@ -14797,12 +14880,34 @@ function hasSecondaryValueAxis(axes) {
14797
14880
  }
14798
14881
  return axes.some((a) => a.axisType === 'valAx' && a.axPos === 'r');
14799
14882
  }
14800
- /** Check whether any axis in the list is a secondary category axis (position "t"). */
14883
+ function categoryAxes(axes) {
14884
+ return axes?.filter((a) => a.axisType === 'catAx' || a.axisType === 'dateAx') ?? [];
14885
+ }
14886
+ /**
14887
+ * Check whether the chart has a genuine SECOND category axis positioned at the
14888
+ * top (a combo chart with one bottom + one top category axis). A single
14889
+ * category axis that itself carries `axPos="t"` (the only axis, just
14890
+ * relocated) is NOT a secondary axis: see `isPrimaryCategoryAxisAtTop`.
14891
+ */
14801
14892
  function hasSecondaryCategoryAxis(axes) {
14802
- if (!axes) {
14893
+ const cats = categoryAxes(axes);
14894
+ return cats.length > 1 && cats.some((a) => a.axPos === 't');
14895
+ }
14896
+ /**
14897
+ * Check whether the chart's PRIMARY (and, in the common case, only) category
14898
+ * axis is positioned at the top of the plot area (`c:catAx/c:axPos val="t"`).
14899
+ * Mirrors the axis selection in `chart-category-axis.ts`'s
14900
+ * `primaryCategoryAxis`: prefer a non-top axis when one exists (the top one is
14901
+ * then the genuine secondary axis, handled separately), otherwise fall back to
14902
+ * the first category axis, which is the only one there is.
14903
+ */
14904
+ function isPrimaryCategoryAxisAtTop(axes) {
14905
+ const cats = categoryAxes(axes);
14906
+ if (cats.length === 0) {
14803
14907
  return false;
14804
14908
  }
14805
- return axes.some((a) => (a.axisType === 'catAx' || a.axisType === 'dateAx') && a.axPos === 't');
14909
+ const primary = cats.find((a) => a.axPos !== 't') ?? cats[0];
14910
+ return primary.axPos === 't';
14806
14911
  }
14807
14912
  /** Get the secondary value axis formatting, if present. */
14808
14913
  function getSecondaryValueAxis(axes) {
@@ -14823,6 +14928,7 @@ function computeLayoutOptions(axes, dataTable, seriesCount) {
14823
14928
  return {
14824
14929
  hasSecondaryValueAxis: hasSecondaryValueAxis(axes),
14825
14930
  hasSecondaryCategoryAxis: hasSecondaryCategoryAxis(axes),
14931
+ categoryAxisAtTop: isPrimaryCategoryAxisAtTop(axes),
14826
14932
  hasDataTable: Boolean(dataTable),
14827
14933
  dataTableRowCount: dataTable ? seriesCount : undefined,
14828
14934
  };
@@ -15028,6 +15134,26 @@ function upsertDataPoint(dataPoints, point) {
15028
15134
  }
15029
15135
  return next;
15030
15136
  }
15137
+ // Picture-fill resolution (c:pictureOptions, the bare-a:blipFill
15138
+ // impliedPicture case, and bar3D face targeting) lives in
15139
+ // chart-datapoint-picture-resolve.ts, split out to keep this file within the
15140
+ // repo's ~300-LOC limit: `resolveActiveDataPointPicture`,
15141
+ // `resolveDataPointPictureFill`, `resolveBarFaceTargets`, `DataPointPictureFill`,
15142
+ // `BarPictureFace`, `BarFaceTargets`.
15143
+
15144
+ /**
15145
+ * chart-datapoint-picture-resolve.ts: framework-agnostic resolution of a
15146
+ * data point's (or its series') picture fill into a paintable descriptor.
15147
+ *
15148
+ * Split out of `chart-datapoint-style.ts` to keep that file within the
15149
+ * repo's ~300-LOC limit: that file resolves per-point formatting in
15150
+ * general (fill colour, marker, explosion); this one owns specifically the
15151
+ * picture-fill half (`c:pictureOptions` AND the bare-`a:blipFill`
15152
+ * `impliedPicture` case, plus `bar3D` face targeting), which had grown into
15153
+ * its own coherent concern.
15154
+ *
15155
+ * @module chart-datapoint-picture-resolve
15156
+ */
15031
15157
  /** PowerPoint's own default picture-fill format when `c:pictureFormat` is absent. */
15032
15158
  const DEFAULT_PICTURE_FORMAT = 'stretch';
15033
15159
  /**
@@ -15036,14 +15162,28 @@ const DEFAULT_PICTURE_FORMAT = 'stretch';
15036
15162
  * `c:ser/c:pictureOptions` (C2-G9 series-level half). A point with its own
15037
15163
  * picture wins OUTRIGHT (not merged field-by-field with the series' flags),
15038
15164
  * matching how a `c:dPt/c:spPr` fully replaces the series' formatting
15039
- * elsewhere in this resolver ({@link resolveDataPointFill}).
15165
+ * elsewhere in this resolver (`resolveDataPointFill`, `chart-datapoint-style.ts`).
15166
+ *
15167
+ * `impliedPicture` (a bare `a:blipFill` with no `c:pictureOptions` sibling,
15168
+ * see `PptxChartDataPoint.impliedPicture`'s doc comment) is checked at the
15169
+ * SAME tier as `picture`, once `picture` itself did not resolve an image: a
15170
+ * point's own fill (explicit flags or implied) still wins outright over the
15171
+ * series', and vice versa.
15040
15172
  */
15041
15173
  function resolveActiveDataPointPicture(series, pointIndex) {
15042
- const pointPicture = findDataPoint(series, pointIndex)?.picture;
15043
- if (pointPicture?.imageUrl) {
15174
+ const point = findDataPoint(series, pointIndex);
15175
+ const pointPicture = point?.picture?.imageUrl
15176
+ ? point.picture
15177
+ : point?.impliedPicture?.imageUrl
15178
+ ? point.impliedPicture
15179
+ : undefined;
15180
+ if (pointPicture) {
15044
15181
  return pointPicture;
15045
15182
  }
15046
- return series.picture?.imageUrl ? series.picture : undefined;
15183
+ if (series.picture?.imageUrl) {
15184
+ return series.picture;
15185
+ }
15186
+ return series.impliedPicture?.imageUrl ? series.impliedPicture : undefined;
15047
15187
  }
15048
15188
  /**
15049
15189
  * Resolve which 3-D bar/column faces a picture fill paints
@@ -15101,6 +15241,7 @@ function resolveDataPointPictureFill(series, pointIndex, seriesIndex, face) {
15101
15241
  ...(format !== 'stretch' && picture.pictureStackUnit !== undefined
15102
15242
  ? { tileHeightPx: chartFontPx(picture.pictureStackUnit) }
15103
15243
  : {}),
15244
+ ...(picture.opacity !== undefined ? { opacity: picture.opacity } : {}),
15104
15245
  };
15105
15246
  }
15106
15247
 
@@ -15187,7 +15328,11 @@ function applyDataPointPictureFills(chartData, elementId, primitives) {
15187
15328
  }
15188
15329
  const patternId = `${elementId}-${resolved.patternId}`;
15189
15330
  defs.push(buildPictureFillPatternDef(patternId, resolved.imageUrl, resolved.format, primitive, resolved.tileHeightPx));
15190
- return { ...primitive, fill: `url(#${patternId})` };
15331
+ return {
15332
+ ...primitive,
15333
+ fill: `url(#${patternId})`,
15334
+ ...(resolved.opacity !== undefined ? { opacity: resolved.opacity } : {}),
15335
+ };
15191
15336
  });
15192
15337
  return { primitives: next, defs };
15193
15338
  }
@@ -15687,10 +15832,183 @@ function computeChartLegendLayout(vm) {
15687
15832
  fontWeight: textStyle?.bold ? 'bold' : 'normal',
15688
15833
  fontStyle: textStyle?.italic ? 'italic' : 'normal',
15689
15834
  fontFamily: textStyle?.fontFamily,
15835
+ ...(entry.lineSwatch ? { lineSwatch: entry.lineSwatch } : {}),
15690
15836
  };
15691
15837
  });
15692
15838
  }
15693
15839
 
15840
+ /**
15841
+ * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for
15842
+ * line / scatter / area chart data points.
15843
+ *
15844
+ * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,
15845
+ * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an
15846
+ * optional `c:size` (2-72 points). The base view-model historically drew every
15847
+ * data point as a fixed-radius circle, ignoring both. This helper resolves the
15848
+ * parsed marker into the correct `SvgPrimitive` at the requested size, and
15849
+ * returns `null` for `symbol === 'none'` so no dot is drawn.
15850
+ *
15851
+ * @module chart-marker-shape
15852
+ */
15853
+ /** Resolve the drawn radius (px) from the parsed point size or the default. */
15854
+ function markerRadius(size, defaultRadius) {
15855
+ if (size === undefined || !Number.isFinite(size) || size <= 0) {
15856
+ return defaultRadius;
15857
+ }
15858
+ // OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.
15859
+ return size / 2;
15860
+ }
15861
+ /** Build the SVG points string for a regular/irregular polygon vertex list. */
15862
+ function polygonPoints(vertices) {
15863
+ return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');
15864
+ }
15865
+ function starVertices(cx, cy, r) {
15866
+ const inner = r * 0.5;
15867
+ const out = [];
15868
+ for (let i = 0; i < 10; i++) {
15869
+ const radius = i % 2 === 0 ? r : inner;
15870
+ const angle = -Math.PI / 2 + (Math.PI * i) / 5;
15871
+ out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
15872
+ }
15873
+ return out;
15874
+ }
15875
+ /**
15876
+ * Build the marker primitive for one data point, honouring `symbol` and `size`.
15877
+ * Returns `null` when `symbol === 'none'` (draw nothing).
15878
+ */
15879
+ function buildMarkerPrimitive(input) {
15880
+ const { symbol, cx, cy, fill, part } = input;
15881
+ if (symbol === 'none') {
15882
+ return null;
15883
+ }
15884
+ const r = markerRadius(input.size, input.defaultRadius);
15885
+ const stroke = fill;
15886
+ switch (symbol) {
15887
+ case 'square':
15888
+ return { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };
15889
+ case 'dash':
15890
+ return { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };
15891
+ case 'diamond':
15892
+ return {
15893
+ kind: 'polygon',
15894
+ points: polygonPoints([
15895
+ [cx, cy - r],
15896
+ [cx + r, cy],
15897
+ [cx, cy + r],
15898
+ [cx - r, cy],
15899
+ ]),
15900
+ fill,
15901
+ stroke,
15902
+ strokeWidth: 0,
15903
+ part,
15904
+ };
15905
+ case 'triangle':
15906
+ return {
15907
+ kind: 'polygon',
15908
+ points: polygonPoints([
15909
+ [cx, cy - r],
15910
+ [cx + r * 0.9, cy + r * 0.75],
15911
+ [cx - r * 0.9, cy + r * 0.75],
15912
+ ]),
15913
+ fill,
15914
+ stroke,
15915
+ strokeWidth: 0,
15916
+ part,
15917
+ };
15918
+ case 'star':
15919
+ return {
15920
+ kind: 'polygon',
15921
+ points: polygonPoints(starVertices(cx, cy, r)),
15922
+ fill,
15923
+ stroke,
15924
+ strokeWidth: 0,
15925
+ part,
15926
+ };
15927
+ case 'plus':
15928
+ return {
15929
+ kind: 'path',
15930
+ d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
15931
+ fill: 'none',
15932
+ stroke,
15933
+ strokeWidth: Math.max(1, r * 0.4),
15934
+ part,
15935
+ };
15936
+ case 'x':
15937
+ return {
15938
+ kind: 'path',
15939
+ d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
15940
+ fill: 'none',
15941
+ stroke,
15942
+ strokeWidth: Math.max(1, r * 0.4),
15943
+ part,
15944
+ };
15945
+ case 'dot':
15946
+ return { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };
15947
+ default:
15948
+ // circle / auto / picture / undefined -> filled circle.
15949
+ return { kind: 'circle', cx, cy, r, fill, part };
15950
+ }
15951
+ }
15952
+
15953
+ /** Legend swatch line width in px: a fixed icon size, independent of the plotted series' own stroke width. */
15954
+ const LEGEND_LINE_SWATCH_WIDTH = 2;
15955
+ /** Legend swatch marker radius in px: a fixed icon size, independent of the series' own `c:marker/c:size`. */
15956
+ const LEGEND_MARKER_RADIUS = 3;
15957
+ /** Vertical centre of the swatch box (matches the rect swatch's `y: -7, height: 10`). */
15958
+ const SWATCH_CENTER_Y = -2;
15959
+ /** Swatch box width in px (matches the rect swatch's `width: 10`). */
15960
+ const SWATCH_WIDTH = 10;
15961
+ /**
15962
+ * Which chart kinds get a line-style legend swatch instead of a filled rect.
15963
+ *
15964
+ * Deliberately narrow: only kinds whose whole plot is a drawn line/marker
15965
+ * (line, scatter). A filled radar or an area chart still reads as a filled
15966
+ * region in PowerPoint's own legend, so they keep the rect swatch; a
15967
+ * bar+line combo resolves its line series individually (see
15968
+ * `chart-combo.ts`), not through this whole-chart check.
15969
+ */
15970
+ function resolveLegendSwatchKind(kind) {
15971
+ return kind === 'line' || kind === 'scatter' ? 'line' : 'rect';
15972
+ }
15973
+ /**
15974
+ * Build the line-style legend swatch primitives for one series.
15975
+ *
15976
+ * The marker uses the series' OWN marker (`c:ser/c:marker`), never a `c:dPt`
15977
+ * per-point override: a legend sample represents the whole series, matching
15978
+ * PowerPoint. `pointIndex: -1` is not a real data point, so
15979
+ * {@link resolveDataPointMarker}'s `c:dPt` lookup never matches it. The marker
15980
+ * is always drawn at {@link LEGEND_MARKER_RADIUS}, ignoring the series' own
15981
+ * `c:marker/c:size`, so the legend icon stays a consistent small size
15982
+ * regardless of how large the plotted markers are.
15983
+ */
15984
+ function buildLineLegendSwatch(series, color) {
15985
+ const resolved = resolveDataPointMarker(series, -1), primitives = [];
15986
+ if (!series.lineNoFill) {
15987
+ primitives.push({
15988
+ kind: 'line',
15989
+ x1: 0,
15990
+ y1: SWATCH_CENTER_Y,
15991
+ x2: SWATCH_WIDTH,
15992
+ y2: SWATCH_CENTER_Y,
15993
+ stroke: color,
15994
+ strokeWidth: LEGEND_LINE_SWATCH_WIDTH,
15995
+ });
15996
+ }
15997
+ const marker = buildMarkerPrimitive({
15998
+ symbol: resolved.symbol,
15999
+ // Deliberately ignore the series' authored size (see doc comment above).
16000
+ size: undefined,
16001
+ cx: SWATCH_WIDTH / 2,
16002
+ cy: SWATCH_CENTER_Y,
16003
+ fill: resolved.fill ?? color,
16004
+ defaultRadius: LEGEND_MARKER_RADIUS,
16005
+ });
16006
+ if (marker) {
16007
+ primitives.push(marker);
16008
+ }
16009
+ return { primitives };
16010
+ }
16011
+
15694
16012
  const DEFAULT_COLOR$3 = '#64748b';
15695
16013
  function dashArray(style, width) {
15696
16014
  if (!style || style === 'solid') {
@@ -15937,6 +16255,46 @@ function buildMarkTooltip(seriesName, categoryLabel, value, numberFormat) {
15937
16255
  return label.length > 0 ? `${label}: ${formatted}` : formatted;
15938
16256
  }
15939
16257
 
16258
+ /**
16259
+ * Build the base legend entries + anchor position for a chart view model.
16260
+ *
16261
+ * @param swatchKind Which legend entries draw a line + marker sample instead
16262
+ * of the default filled rect (see `chart-legend-swatch.ts`). A single value
16263
+ * applies to every entry (the whole-chart line/scatter case); an array
16264
+ * resolves per series index (a bar+line combo, where only the line series
16265
+ * get the line sample). Defaults to `'rect'` for every existing caller that
16266
+ * predates line-aware legends.
16267
+ */
16268
+ function buildLegend(series, colorPalette, svgWidth, legendPos, svgHeight, plotTop, swatchKind = 'rect') {
16269
+ const legend = series.map((s, i) => {
16270
+ const color = seriesColor(s, i, colorPalette), kind = Array.isArray(swatchKind) ? (swatchKind[i] ?? 'rect') : swatchKind;
16271
+ return {
16272
+ color,
16273
+ label: s.name,
16274
+ ...(kind === 'line' ? { lineSwatch: buildLineLegendSwatch(s, color) } : {}),
16275
+ };
16276
+ });
16277
+ let legendX = svgWidth / 2, legendY = svgHeight - 8, legendAnchor = 'middle';
16278
+ // `tr` shares `'r'`'s coordinates (a right-aligned column starting at
16279
+ // plotTop): that is already "top-right corner"; it just does not reserve
16280
+ // plot-area space the way a reserved `'r'` legend does (see computePlotLayout).
16281
+ const side = resolveLegendPlacement(legendPos).side;
16282
+ if (side === 'r') {
16283
+ legendX = svgWidth - 75;
16284
+ legendY = plotTop;
16285
+ legendAnchor = 'start';
16286
+ }
16287
+ else if (side === 'l') {
16288
+ legendX = 4;
16289
+ legendY = plotTop;
16290
+ legendAnchor = 'start';
16291
+ }
16292
+ else if (side === 't') {
16293
+ legendY = 28;
16294
+ }
16295
+ return { legend, legendX, legendY, legendAnchor };
16296
+ }
16297
+
15940
16298
  /**
15941
16299
  * chart-view-model-bars.ts: bar / column rectangle and line-point geometry of
15942
16300
  * the chart engine. Split out of `chart-view-model.ts`, which re-exports
@@ -16933,119 +17291,6 @@ function smoothLinePath(points) {
16933
17291
  return d;
16934
17292
  }
16935
17293
 
16936
- /**
16937
- * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for
16938
- * line / scatter / area chart data points.
16939
- *
16940
- * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,
16941
- * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an
16942
- * optional `c:size` (2-72 points). The base view-model historically drew every
16943
- * data point as a fixed-radius circle, ignoring both. This helper resolves the
16944
- * parsed marker into the correct `SvgPrimitive` at the requested size, and
16945
- * returns `null` for `symbol === 'none'` so no dot is drawn.
16946
- *
16947
- * @module chart-marker-shape
16948
- */
16949
- /** Resolve the drawn radius (px) from the parsed point size or the default. */
16950
- function markerRadius(size, defaultRadius) {
16951
- if (size === undefined || !Number.isFinite(size) || size <= 0) {
16952
- return defaultRadius;
16953
- }
16954
- // OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.
16955
- return size / 2;
16956
- }
16957
- /** Build the SVG points string for a regular/irregular polygon vertex list. */
16958
- function polygonPoints(vertices) {
16959
- return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');
16960
- }
16961
- function starVertices(cx, cy, r) {
16962
- const inner = r * 0.5;
16963
- const out = [];
16964
- for (let i = 0; i < 10; i++) {
16965
- const radius = i % 2 === 0 ? r : inner;
16966
- const angle = -Math.PI / 2 + (Math.PI * i) / 5;
16967
- out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
16968
- }
16969
- return out;
16970
- }
16971
- /**
16972
- * Build the marker primitive for one data point, honouring `symbol` and `size`.
16973
- * Returns `null` when `symbol === 'none'` (draw nothing).
16974
- */
16975
- function buildMarkerPrimitive(input) {
16976
- const { symbol, cx, cy, fill, part } = input;
16977
- if (symbol === 'none') {
16978
- return null;
16979
- }
16980
- const r = markerRadius(input.size, input.defaultRadius);
16981
- const stroke = fill;
16982
- switch (symbol) {
16983
- case 'square':
16984
- return { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };
16985
- case 'dash':
16986
- return { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };
16987
- case 'diamond':
16988
- return {
16989
- kind: 'polygon',
16990
- points: polygonPoints([
16991
- [cx, cy - r],
16992
- [cx + r, cy],
16993
- [cx, cy + r],
16994
- [cx - r, cy],
16995
- ]),
16996
- fill,
16997
- stroke,
16998
- strokeWidth: 0,
16999
- part,
17000
- };
17001
- case 'triangle':
17002
- return {
17003
- kind: 'polygon',
17004
- points: polygonPoints([
17005
- [cx, cy - r],
17006
- [cx + r * 0.9, cy + r * 0.75],
17007
- [cx - r * 0.9, cy + r * 0.75],
17008
- ]),
17009
- fill,
17010
- stroke,
17011
- strokeWidth: 0,
17012
- part,
17013
- };
17014
- case 'star':
17015
- return {
17016
- kind: 'polygon',
17017
- points: polygonPoints(starVertices(cx, cy, r)),
17018
- fill,
17019
- stroke,
17020
- strokeWidth: 0,
17021
- part,
17022
- };
17023
- case 'plus':
17024
- return {
17025
- kind: 'path',
17026
- d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
17027
- fill: 'none',
17028
- stroke,
17029
- strokeWidth: Math.max(1, r * 0.4),
17030
- part,
17031
- };
17032
- case 'x':
17033
- return {
17034
- kind: 'path',
17035
- d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
17036
- fill: 'none',
17037
- stroke,
17038
- strokeWidth: Math.max(1, r * 0.4),
17039
- part,
17040
- };
17041
- case 'dot':
17042
- return { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };
17043
- default:
17044
- // circle / auto / picture / undefined -> filled circle.
17045
- return { kind: 'circle', cx, cy, r, fill, part };
17046
- }
17047
- }
17048
-
17049
17294
  /**
17050
17295
  * Chart-element pixel box a manual `c:dLbl/c:layout` drag is measured
17051
17296
  * against. Exported for `chart-cartesian-bubbles.ts`, which shares this
@@ -17635,14 +17880,31 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
17635
17880
  varyColorsSingle = chartData.varyColors === true && series.length === 1;
17636
17881
  if (grouping === 'clustered') {
17637
17882
  const seriesCount = Math.max(series.length, 1), barGroupWidth = layout.plotWidth / Math.max(catCount, 1),
17883
+ // Honour c:overlap (% overlap between adjacent series). overlap=0 reproduces
17884
+ // the original side-by-side layout exactly. Read before singleBarWidth: a
17885
+ // gapWidth-based bar width must size itself so the OVERLAPPED cluster (not
17886
+ // seriesCount side-by-side bars) fills the gap-reduced group width; see the
17887
+ // comment below.
17888
+ overlap = chartData.barOverlap ?? 0,
17638
17889
  // Honour c:gapWidth (gap between clusters, % of a bar width) when parsed;
17639
17890
  // otherwise keep the legacy 0.7-of-group heuristic byte-for-byte.
17640
- singleBarWidth = chartData.barGapWidth !== undefined
17641
- ? barGroupWidth / (seriesCount + Math.max(chartData.barGapWidth, 0) / 100)
17642
- : (barGroupWidth * 0.7) / seriesCount,
17643
- // Honour c:overlap (% overlap between adjacent series). overlap=0 reproduces
17644
- // the original side-by-side layout exactly.
17645
- overlap = chartData.barOverlap ?? 0, step = singleBarWidth * (1 - overlap / 100), clusterWidth = singleBarWidth + step * (seriesCount - 1), groupOffset = (barGroupWidth - clusterWidth) / 2;
17891
+ //
17892
+ // COM-verified ground truth (PowerPoint Object 16, single category, six
17893
+ // series, gapWidth=5, overlap=23): dividing by seriesCount alone (the
17894
+ // pre-existing formula) sizes every bar as if the cluster were laid out
17895
+ // SIDE BY SIDE, then shrinks it further by overlap when computing `step`
17896
+ // below - so at high overlap the bars render far too NARROW (in the
17897
+ // limit, overlap=100 should make every bar in a cluster the same width
17898
+ // as a single-series bar, independent of seriesCount, since they fully
17899
+ // coincide; the old formula kept shrinking by 1/seriesCount regardless).
17900
+ // The fix: first shrink the group width by the gap (exactly as before),
17901
+ // then divide by how many bar-widths the OVERLAPPED cluster actually
17902
+ // spans (`1 + (seriesCount - 1) * (1 - overlap / 100)`, the same
17903
+ // relationship `clusterWidth` below re-derives from `step`), not by the
17904
+ // raw series count.
17905
+ overlapSpan = 1 + (seriesCount - 1) * (1 - overlap / 100), singleBarWidth = chartData.barGapWidth !== undefined
17906
+ ? barGroupWidth / ((1 + Math.max(chartData.barGapWidth, 0) / 100) * overlapSpan)
17907
+ : (barGroupWidth * 0.7) / seriesCount, step = singleBarWidth * (1 - overlap / 100), clusterWidth = singleBarWidth + step * (seriesCount - 1), groupOffset = (barGroupWidth - clusterWidth) / 2;
17646
17908
  for (let displayIndex = 0; displayIndex < catCount; displayIndex++) {
17647
17909
  const sourceIndex = sourceIndices[displayIndex] ?? displayIndex;
17648
17910
  for (let si = 0; si < series.length; si++) {
@@ -19090,9 +19352,14 @@ function buildHorizontalBarViewModel(element, chartData, categoryLabels) {
19090
19352
  }
19091
19353
  : undefined, primitives = [], dataLabels = [], showLabels = chartData.style?.hasDataLabels, band = layout.plotHeight / catCount;
19092
19354
  if (!isStacked) {
19093
- const seriesCount = Math.max(series.length, 1), singleBarHeight = chartData.barGapWidth !== undefined
19094
- ? band / (seriesCount + Math.max(chartData.barGapWidth, 0) / 100)
19095
- : (band * 0.7) / seriesCount, overlap = chartData.barOverlap ?? 0, step = singleBarHeight * (1 - overlap / 100), clusterHeight = singleBarHeight + step * (seriesCount - 1), groupOffset = (band - clusterHeight) / 2;
19355
+ const seriesCount = Math.max(series.length, 1),
19356
+ // See chart-cartesian-bars.ts's `buildBars` (clustered branch) for the
19357
+ // COM-verified reasoning: the bar's own size must divide the gap-reduced
19358
+ // band by how many bar-heights the OVERLAPPED cluster spans, not by the
19359
+ // raw series count, or a high-overlap cluster renders far too thin.
19360
+ overlap = chartData.barOverlap ?? 0, overlapSpan = 1 + (seriesCount - 1) * (1 - overlap / 100), singleBarHeight = chartData.barGapWidth !== undefined
19361
+ ? band / ((1 + Math.max(chartData.barGapWidth, 0) / 100) * overlapSpan)
19362
+ : (band * 0.7) / seriesCount, step = singleBarHeight * (1 - overlap / 100), clusterHeight = singleBarHeight + step * (seriesCount - 1), groupOffset = (band - clusterHeight) / 2;
19096
19363
  for (let ci = 0; ci < catCount; ci++) {
19097
19364
  for (let si = 0; si < series.length; si++) {
19098
19365
  const val = series[si].values[ci] ?? 0, y = layout.plotTop + band * ci + groupOffset + step * si, valX = valueToX(val, range, layout.plotLeft, layout.plotRight), x = Math.min(zeroX, valX), w = Math.max(Math.abs(valX - zeroX), 1);
@@ -19863,7 +20130,7 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
19863
20130
  // eslint-disable-next-line one-var -- pre-existing, unrelated to this change
19864
20131
  const legendPos = chartData.style?.legendPosition ?? 'b';
19865
20132
  // eslint-disable-next-line one-var -- pre-existing, unrelated to this change
19866
- const { legend, legendX, legendY, legendAnchor } = buildLegend(chartData.series, chartData.colorPalette, layout.svgWidth, legendPos, layout.svgHeight, layout.plotTop);
20133
+ const { legend, legendX, legendY, legendAnchor } = buildLegend(chartData.series, chartData.colorPalette, layout.svgWidth, legendPos, layout.svgHeight, layout.plotTop, resolveLegendSwatchKind(kind));
19867
20134
  let plot;
19868
20135
  if (kind === 'bar') {
19869
20136
  plot = buildBars(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx, isStacked ? (isPercent ? 'percentStacked' : 'stacked') : 'clustered', sourceIndices);
@@ -20096,7 +20363,11 @@ function buildComboViewModel(element, chartData, categoryLabels) {
20096
20363
  const horizontalAxis = buildCartesianHorizontalAxis(chartData, categoryLabels, layout, 'combo', primaryRange, secondaryRange);
20097
20364
  const sourceIndices = horizontalAxis.sourceIndices;
20098
20365
  const legendPos = chartData.style?.legendPosition ?? 'b';
20099
- const { legend, legendX, legendY, legendAnchor } = buildLegend(chartData.series, chartData.colorPalette, layout.svgWidth, legendPos, layout.svgHeight, layout.plotTop);
20366
+ // The combo layout below is fixed: series 0 is the bar, every other series
20367
+ // is a line (see `barSeries`/`lineSeries` just below), so the legend swatch
20368
+ // follows the same split (bar -> rect, line -> line+marker sample).
20369
+ const comboSwatchKinds = chartData.series.map((_s, i) => i === 0 ? 'rect' : 'line');
20370
+ const { legend, legendX, legendY, legendAnchor } = buildLegend(chartData.series, chartData.colorPalette, layout.svgWidth, legendPos, layout.svgHeight, layout.plotTop, comboSwatchKinds);
20100
20371
  const primitives = [];
20101
20372
  const dataLabels = [];
20102
20373
  // Drop / hi-low / up-down helper lines, drawn behind the combo marks.
@@ -22712,9 +22983,12 @@ function buildPieViewModel(element, chartData, categoryLabels, isDoughnut) {
22712
22983
  }
22713
22984
 
22714
22985
  /**
22715
- * chart-view-model-layout.ts: plot-area layout and chart chrome (gridlines,
22716
- * axis / category labels, legend placement) of the chart engine. Split out of
22717
- * `chart-view-model.ts`, which re-exports everything here.
22986
+ * chart-view-model-layout.ts: plot-area layout math for the chart engine
22987
+ * (the plot inset, legend/title/data-table/secondary-axis reservations, and
22988
+ * `c:plotArea/c:layout/c:manualLayout` overrides). Chart chrome (gridlines,
22989
+ * axis / category labels) lives in `chart-view-model-chrome.ts`; legend
22990
+ * building lives in `chart-legend-build.ts`. All three are re-exported by
22991
+ * `chart-view-model.ts`.
22718
22992
  *
22719
22993
  * @module chart-view-model-layout
22720
22994
  */
@@ -22753,6 +23027,16 @@ function computePlotLayout(elementWidth, elementHeight, chartData, hasAxes, opti
22753
23027
  // a 475x174 frame got a 475x180 viewBox, squeezing y by 0.967).
22754
23028
  const svgWidth = Math.max(1, elementWidth), svgHeight = Math.max(1, elementHeight);
22755
23029
  let plotLeft = hasAxes ? 48 : 8, plotTop = 8, plotRight = svgWidth - 8, plotBottom = svgHeight - (hasAxes ? categoryAxisBand(chartData) : 8);
23030
+ // `c:catAx/c:axPos val="t"` on the PRIMARY (and, in the common case, only)
23031
+ // category axis: PowerPoint draws that axis's tick labels above the plot,
23032
+ // not below it. Reserving the label band at the bottom regardless of
23033
+ // `axPos` (the historical behaviour here) leaves no room at the top, so the
23034
+ // labels get drawn outside the chart's own SVG bounds and clip against its
23035
+ // edge. Move the reservation to match where the labels actually land.
23036
+ if (hasAxes && options?.categoryAxisAtTop) {
23037
+ plotBottom = svgHeight - 8;
23038
+ plotTop += categoryAxisBand(chartData);
23039
+ }
22756
23040
  const style = chartData.style, legendPos = style?.legendPosition ?? 'b';
22757
23041
  if (style?.hasTitle) {
22758
23042
  plotTop += 20;
@@ -22808,121 +23092,6 @@ function computePlotLayout(elementWidth, elementHeight, chartData, hasAxes, opti
22808
23092
  plotHeight,
22809
23093
  };
22810
23094
  }
22811
- // ─────────────────────────────────────────────────────────────────────────────
22812
- // Chrome helpers
22813
- // ─────────────────────────────────────────────────────────────────────────────
22814
- const GRIDLINE_COLOR$1 = '#e2e8f0';
22815
- const AXIS_LABEL_COLOR = '#64748b';
22816
- const ZERO_LINE_COLOR = '#94a3b8';
22817
- const TICK_COUNT$1 = 5;
22818
- /**
22819
- * Tick values for a range: one per major unit when the automatic scale supplied
22820
- * one (it snapped the bounds to whole multiples, so this lands on round numbers
22821
- * exactly as PowerPoint does), otherwise an even division of the span.
22822
- * Exported for the transposed (horizontal-bar) axis builder.
22823
- */
22824
- function axisTickValues(range) {
22825
- const unit = range.majorUnit;
22826
- if (unit !== undefined && Number.isFinite(unit) && unit > 0 && !range.logScale) {
22827
- const steps = Math.round((range.max - range.min) / unit);
22828
- if (steps >= 1 && steps <= 100) {
22829
- return Array.from({ length: steps + 1 }, (_unused, index) => range.min + unit * index);
22830
- }
22831
- }
22832
- return Array.from({ length: TICK_COUNT$1 + 1 }, (_unused, index) => range.min + (range.span / TICK_COUNT$1) * index);
22833
- }
22834
- function buildGridlinesAndLabels(range, layout,
22835
- /**
22836
- * `false` keeps the tick labels but draws no gridlines: a value axis whose
22837
- * `c:majorGridlines` is absent (see `shouldRenderMajorGridlines`).
22838
- */
22839
- showMajorGridlines = true) {
22840
- const gridlines = [], axisLabels = [];
22841
- for (const val of axisTickValues(range)) {
22842
- const y = valueToY(val, range, layout.plotTop, layout.plotBottom);
22843
- if (showMajorGridlines) {
22844
- gridlines.push({
22845
- kind: 'line',
22846
- x1: layout.plotLeft,
22847
- y1: y,
22848
- x2: layout.plotRight,
22849
- y2: y,
22850
- stroke: GRIDLINE_COLOR$1,
22851
- strokeWidth: 1,
22852
- });
22853
- }
22854
- axisLabels.push({
22855
- kind: 'text',
22856
- x: layout.plotLeft - 4,
22857
- y,
22858
- text: formatAxisValue(val),
22859
- fontSize: DEFAULT_CHART_TEXT_PX,
22860
- fill: AXIS_LABEL_COLOR,
22861
- textAnchor: 'end',
22862
- dominantBaseline: 'central',
22863
- });
22864
- }
22865
- return { gridlines, axisLabels };
22866
- }
22867
- function buildZeroLine(range, layout) {
22868
- if (range.min >= 0 || range.max <= 0) {
22869
- return undefined;
22870
- }
22871
- const y = valueToY(0, range, layout.plotTop, layout.plotBottom);
22872
- return {
22873
- kind: 'line',
22874
- x1: layout.plotLeft,
22875
- y1: y,
22876
- x2: layout.plotRight,
22877
- y2: y,
22878
- stroke: ZERO_LINE_COLOR,
22879
- strokeWidth: 1,
22880
- };
22881
- }
22882
- function buildCategoryLabels(categoryLabels, layout, catSpacing) {
22883
- const catCount = Math.max(categoryLabels.length, 1);
22884
- return categoryLabels.map((label, i) => {
22885
- const x = catSpacing === 'bar'
22886
- ? layout.plotLeft + (layout.plotWidth / catCount) * (i + 0.5)
22887
- : catCount > 1
22888
- ? layout.plotLeft + (layout.plotWidth / (catCount - 1)) * i
22889
- : layout.plotLeft + layout.plotWidth / 2;
22890
- return {
22891
- kind: 'text',
22892
- x,
22893
- y: layout.plotBottom + 12,
22894
- text: label,
22895
- fontSize: DEFAULT_CHART_TEXT_PX,
22896
- fill: AXIS_LABEL_COLOR,
22897
- textAnchor: 'middle',
22898
- };
22899
- });
22900
- }
22901
- function buildLegend(series, colorPalette, svgWidth, legendPos, svgHeight, plotTop) {
22902
- const legend = series.map((s, i) => ({
22903
- color: seriesColor(s, i, colorPalette),
22904
- label: s.name,
22905
- }));
22906
- let legendX = svgWidth / 2, legendY = svgHeight - 8, legendAnchor = 'middle';
22907
- // `tr` shares `'r'`'s coordinates (a right-aligned column starting at
22908
- // plotTop): that is already "top-right corner"; it just does not reserve
22909
- // plot-area space the way a reserved `'r'` legend does (see computePlotLayout).
22910
- const side = resolveLegendPlacement(legendPos).side;
22911
- if (side === 'r') {
22912
- legendX = svgWidth - 75;
22913
- legendY = plotTop;
22914
- legendAnchor = 'start';
22915
- }
22916
- else if (side === 'l') {
22917
- legendX = 4;
22918
- legendY = plotTop;
22919
- legendAnchor = 'start';
22920
- }
22921
- else if (side === 't') {
22922
- legendY = 28;
22923
- }
22924
- return { legend, legendX, legendY, legendAnchor };
22925
- }
22926
23095
 
22927
23096
  /**
22928
23097
  * chart-view-model-radar.ts: the radar / spider view-model builder. Split out
@@ -24258,6 +24427,107 @@ function buildFlatViewModel(element, chartData, categoryLabels, kind) {
24258
24427
  return buildCartesianViewModel(element, chartData, categoryLabels, kind);
24259
24428
  }
24260
24429
 
24430
+ /**
24431
+ * chart-view-model-chrome.ts: chart chrome (value-axis gridlines/labels, zero
24432
+ * line, category labels) shared by the cartesian chart kinds. Split out of
24433
+ * `chart-view-model-layout.ts` to keep that module's plot layout math under
24434
+ * the repo's 300-LOC file guideline; re-exported by `chart-view-model.ts`.
24435
+ * Legend building (`buildLegend`) lives in `chart-legend-build.ts`, not here.
24436
+ *
24437
+ * @module chart-view-model-chrome
24438
+ */
24439
+ /* eslint-disable one-var -- this module predates the rule and combining every
24440
+ sibling `const`/`let` in a function into one comma-list (oxlint's own
24441
+ `--fix` cannot do this safely once a non-declaration statement sits between
24442
+ them) would churn geometry code far beyond this change's scope. */
24443
+ const GRIDLINE_COLOR$1 = '#e2e8f0';
24444
+ const AXIS_LABEL_COLOR = '#64748b';
24445
+ const ZERO_LINE_COLOR = '#94a3b8';
24446
+ const TICK_COUNT$1 = 5;
24447
+ /**
24448
+ * Tick values for a range: one per major unit when the automatic scale supplied
24449
+ * one (it snapped the bounds to whole multiples, so this lands on round numbers
24450
+ * exactly as PowerPoint does), otherwise an even division of the span.
24451
+ * Exported for the transposed (horizontal-bar) axis builder.
24452
+ */
24453
+ function axisTickValues(range) {
24454
+ const unit = range.majorUnit;
24455
+ if (unit !== undefined && Number.isFinite(unit) && unit > 0 && !range.logScale) {
24456
+ const steps = Math.round((range.max - range.min) / unit);
24457
+ if (steps >= 1 && steps <= 100) {
24458
+ return Array.from({ length: steps + 1 }, (_unused, index) => range.min + unit * index);
24459
+ }
24460
+ }
24461
+ return Array.from({ length: TICK_COUNT$1 + 1 }, (_unused, index) => range.min + (range.span / TICK_COUNT$1) * index);
24462
+ }
24463
+ function buildGridlinesAndLabels(range, layout,
24464
+ /**
24465
+ * `false` keeps the tick labels but draws no gridlines: a value axis whose
24466
+ * `c:majorGridlines` is absent (see `shouldRenderMajorGridlines`).
24467
+ */
24468
+ showMajorGridlines = true) {
24469
+ const gridlines = [], axisLabels = [];
24470
+ for (const val of axisTickValues(range)) {
24471
+ const y = valueToY(val, range, layout.plotTop, layout.plotBottom);
24472
+ if (showMajorGridlines) {
24473
+ gridlines.push({
24474
+ kind: 'line',
24475
+ x1: layout.plotLeft,
24476
+ y1: y,
24477
+ x2: layout.plotRight,
24478
+ y2: y,
24479
+ stroke: GRIDLINE_COLOR$1,
24480
+ strokeWidth: 1,
24481
+ });
24482
+ }
24483
+ axisLabels.push({
24484
+ kind: 'text',
24485
+ x: layout.plotLeft - 4,
24486
+ y,
24487
+ text: formatAxisValue(val),
24488
+ fontSize: DEFAULT_CHART_TEXT_PX,
24489
+ fill: AXIS_LABEL_COLOR,
24490
+ textAnchor: 'end',
24491
+ dominantBaseline: 'central',
24492
+ });
24493
+ }
24494
+ return { gridlines, axisLabels };
24495
+ }
24496
+ function buildZeroLine(range, layout) {
24497
+ if (range.min >= 0 || range.max <= 0) {
24498
+ return undefined;
24499
+ }
24500
+ const y = valueToY(0, range, layout.plotTop, layout.plotBottom);
24501
+ return {
24502
+ kind: 'line',
24503
+ x1: layout.plotLeft,
24504
+ y1: y,
24505
+ x2: layout.plotRight,
24506
+ y2: y,
24507
+ stroke: ZERO_LINE_COLOR,
24508
+ strokeWidth: 1,
24509
+ };
24510
+ }
24511
+ function buildCategoryLabels(categoryLabels, layout, catSpacing) {
24512
+ const catCount = Math.max(categoryLabels.length, 1);
24513
+ return categoryLabels.map((label, i) => {
24514
+ const x = catSpacing === 'bar'
24515
+ ? layout.plotLeft + (layout.plotWidth / catCount) * (i + 0.5)
24516
+ : catCount > 1
24517
+ ? layout.plotLeft + (layout.plotWidth / (catCount - 1)) * i
24518
+ : layout.plotLeft + layout.plotWidth / 2;
24519
+ return {
24520
+ kind: 'text',
24521
+ x,
24522
+ y: layout.plotBottom + 12,
24523
+ text: label,
24524
+ fontSize: DEFAULT_CHART_TEXT_PX,
24525
+ fill: AXIS_LABEL_COLOR,
24526
+ textAnchor: 'middle',
24527
+ };
24528
+ });
24529
+ }
24530
+
24261
24531
  /**
24262
24532
  * chart-view-model-types.ts: the framework-neutral descriptor types of the
24263
24533
  * chart engine (plot layout, interactive part refs, SVG primitives, legend
@@ -24309,7 +24579,9 @@ function buildFlatViewModel(element, chartData, categoryLabels, kind) {
24309
24579
  *
24310
24580
  * chart-view-model-types descriptor types (primitives, view-model, layout)
24311
24581
  * chart-view-model-scale palette, value ranges, axis value formatting
24312
- * chart-view-model-layout plot layout, gridlines, labels, legend placement
24582
+ * chart-view-model-layout plot layout math (inset + reservations)
24583
+ * chart-view-model-chrome gridlines, axis/category labels
24584
+ * chart-legend-build legend entries (colour/line swatch) + anchor position
24313
24585
  * chart-view-model-bars bar / column rects, line points
24314
24586
  * chart-view-model-points pie, scatter, bubble, radar geometry
24315
24587
  * chart-view-model-kinds supported kinds + preserveAspectRatio
@@ -103932,6 +104204,26 @@ function segmentFrameCount(durationMs, fps) {
103932
104204
  }
103933
104205
  return Math.max(1, Math.ceil(durationMs / (1000 / fps)));
103934
104206
  }
104207
+ /**
104208
+ * Stop every track on a `canvas.captureStream()` `MediaStream`.
104209
+ *
104210
+ * `MediaRecorder.stop()` only stops the recorder; the underlying capture
104211
+ * stream it was constructed from keeps its track live and compositing frames
104212
+ * from the source canvas indefinitely otherwise. Every binding's `recordWebm`
104213
+ * driver must call this once recording is done - on success, on a
104214
+ * `MediaRecorder` error, and on `AbortSignal` cancellation alike - or each
104215
+ * video export leaks one live capture track for the rest of the page's
104216
+ * lifetime, degrading a session that exports more than once. Pass
104217
+ * `recorder.stream` (every `MediaRecorder` exposes the stream it was built
104218
+ * from) so callers need not keep a separate reference to the stream.
104219
+ *
104220
+ * @param stream - The `MediaStream` to stop, typically `recorder.stream`.
104221
+ */
104222
+ function stopCaptureStream(stream) {
104223
+ for (const track of stream.getTracks()) {
104224
+ track.stop();
104225
+ }
104226
+ }
103935
104227
 
103936
104228
  /**
103937
104229
  * CRC-32 (PNG's checksum, ISO 3309 / ITU-T V.42 polynomial 0xEDB88320) pure
@@ -106873,7 +107165,7 @@ function createLocalStorageBackend(namespace) {
106873
107165
  /** Try IndexedDB first; fall back to localStorage on any failure. */
106874
107166
  async function resolveBackend(dbName, namespace) {
106875
107167
  try {
106876
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BKazjZCl.mjs');
107168
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-HvkahiGW.mjs');
106877
107169
  const db = await openChatDb(dbName);
106878
107170
  return createIdbBackend(db);
106879
107171
  }
@@ -119375,14 +119667,18 @@ class ChartRendererComponent {
119375
119667
  @if (legendItems().length > 0) {
119376
119668
  @for (item of legendItems(); track $index) {
119377
119669
  <g [attr.transform]="legendTransform(item)">
119378
- <rect
119379
- x="0"
119380
- y="-7"
119381
- [attr.width]="swatchSize"
119382
- [attr.height]="swatchSize"
119383
- rx="2"
119384
- [attr.fill]="item.color"
119385
- />
119670
+ @if (item.lineSwatch) {
119671
+ <g pptx-chart-primitives [primitives]="item.lineSwatch.primitives"></g>
119672
+ } @else {
119673
+ <rect
119674
+ x="0"
119675
+ y="-7"
119676
+ [attr.width]="swatchSize"
119677
+ [attr.height]="swatchSize"
119678
+ rx="2"
119679
+ [attr.fill]="item.color"
119680
+ />
119681
+ }
119386
119682
  <text
119387
119683
  [attr.x]="swatchSize + 3"
119388
119684
  y="3"
@@ -119588,14 +119884,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
119588
119884
  @if (legendItems().length > 0) {
119589
119885
  @for (item of legendItems(); track $index) {
119590
119886
  <g [attr.transform]="legendTransform(item)">
119591
- <rect
119592
- x="0"
119593
- y="-7"
119594
- [attr.width]="swatchSize"
119595
- [attr.height]="swatchSize"
119596
- rx="2"
119597
- [attr.fill]="item.color"
119598
- />
119887
+ @if (item.lineSwatch) {
119888
+ <g pptx-chart-primitives [primitives]="item.lineSwatch.primitives"></g>
119889
+ } @else {
119890
+ <rect
119891
+ x="0"
119892
+ y="-7"
119893
+ [attr.width]="swatchSize"
119894
+ [attr.height]="swatchSize"
119895
+ rx="2"
119896
+ [attr.fill]="item.color"
119897
+ />
119898
+ }
119599
119899
  <text
119600
119900
  [attr.x]="swatchSize + 3"
119601
119901
  y="3"
@@ -126160,6 +126460,15 @@ function buildAngularImageRenderView(element) {
126160
126460
  if (computed.opacity !== undefined) {
126161
126461
  imageStyle.opacity = computed.opacity;
126162
126462
  }
126463
+ // `a:blipFill/@rotWithShape="0"`: keep the picture's pixels upright/fixed to
126464
+ // the page frame while `frameGeometryMask`'s container still carries the
126465
+ // shape's own rotate/flip. `undefined` (no-op) in the overwhelming majority
126466
+ // of cases; see `getImageFillCounterTransform`.
126467
+ const fillCounterTransform = getImageFillCounterTransform(element, Boolean(imageStyle['transform']));
126468
+ if (fillCounterTransform) {
126469
+ imageStyle['transform'] = fillCounterTransform;
126470
+ imageStyle['transform-origin'] = 'center';
126471
+ }
126163
126472
  const frameGeometryMask = buildAngularImageContainerMask(element);
126164
126473
  const colorWash = getImageColorWashStyle(isImageLikeElement$1(element) ? element.imageEffects?.colorWash : undefined);
126165
126474
  const colorWashStyle = colorWash
@@ -132165,31 +132474,39 @@ async function recordWebm(canvases, opts = {}) {
132165
132474
  recorder.onerror = (e) => reject(e);
132166
132475
  });
132167
132476
  recorder.start();
132168
- const frameIntervalMs = fpsToFrameIntervalMs(fps);
132169
- for (let i = 0; i < canvases.length; i++) {
132170
- if (signal?.aborted) {
132171
- recorder.stop();
132172
- throw new DOMException('Export cancelled', 'AbortError');
132173
- }
132174
- onProgress?.(i, canvases.length);
132175
- const duration = slideTimingsMs?.[i] ?? slideDurationMs;
132176
- const framesNeeded = segmentFrameCount(duration, fps);
132177
- ctx.clearRect(0, 0, recordingCanvas.width, recordingCanvas.height);
132178
- ctx.drawImage(canvases[i], 0, 0);
132179
- for (let f = 0; f < framesNeeded; f++) {
132477
+ try {
132478
+ const frameIntervalMs = fpsToFrameIntervalMs(fps);
132479
+ for (let i = 0; i < canvases.length; i++) {
132180
132480
  if (signal?.aborted) {
132181
132481
  recorder.stop();
132182
132482
  throw new DOMException('Export cancelled', 'AbortError');
132183
132483
  }
132484
+ onProgress?.(i, canvases.length);
132485
+ const duration = slideTimingsMs?.[i] ?? slideDurationMs;
132486
+ const framesNeeded = segmentFrameCount(duration, fps);
132487
+ ctx.clearRect(0, 0, recordingCanvas.width, recordingCanvas.height);
132184
132488
  ctx.drawImage(canvases[i], 0, 0);
132185
- await new Promise((resolve) => {
132186
- setTimeout(resolve, frameIntervalMs);
132187
- });
132489
+ for (let f = 0; f < framesNeeded; f++) {
132490
+ if (signal?.aborted) {
132491
+ recorder.stop();
132492
+ throw new DOMException('Export cancelled', 'AbortError');
132493
+ }
132494
+ ctx.drawImage(canvases[i], 0, 0);
132495
+ await new Promise((resolve) => {
132496
+ setTimeout(resolve, frameIntervalMs);
132497
+ });
132498
+ }
132188
132499
  }
132500
+ recorder.stop();
132501
+ await recorderDone;
132502
+ return new Blob(chunks, { type: 'video/webm' });
132503
+ }
132504
+ finally {
132505
+ // `recorder.stop()` only stops the recorder; the capture stream itself
132506
+ // keeps compositing frames from `recordingCanvas` indefinitely otherwise
132507
+ // - a real leak on every export, not just an abort path.
132508
+ stopCaptureStream(stream);
132189
132509
  }
132190
- recorder.stop();
132191
- await recorderDone;
132192
- return new Blob(chunks, { type: 'video/webm' });
132193
132510
  }
132194
132511
 
132195
132512
  /**
@@ -147614,7 +147931,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
147614
147931
  }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], selectedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedElement", required: false }] }] } });
147615
147932
 
147616
147933
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
147617
- const PPTX_ANGULAR_VIEWER_VERSION = "3.19.0";
147934
+ const PPTX_ANGULAR_VIEWER_VERSION = "3.19.1";
147618
147935
 
147619
147936
  /**
147620
147937
  * account-page.component.ts: File > Account content.
@@ -185879,4 +186196,4 @@ function cn(...values) {
185879
186196
  */
185880
186197
 
185881
186198
  export { CollaborationCursorsComponent as $, AFTER_ANIMATION_VALUES as A, AnimationAuthorPanelComponent as B, AnimationPanelComponent as C, AnimationPlaybackService as D, AutosaveRecoveryDialogComponent as E, AutosaveService as F, BroadcastDialogComponent as G, CHART_EDITOR_STYLES as H, CINEMATIC_TRANSITION_KEYFRAMES as I, CURSOR_PALETTE as J, CanvasFitService as K, ChartAxisOptionsComponent as L, ChartAxisStyleOptionsComponent as M, ChartComboTypeOptionsComponent as N, ChartDataEditorComponent as O, ChartDataLabelOptionsComponent as P, ChartDatapointMarkerOptionsComponent as Q, ChartDatapointOptionsComponent as R, ChartDisplayOptionsComponent as S, ChartElementViewComponent as T, ChartErrorBarOptionsComponent as U, ChartMarkerOptionsComponent as V, ChartPartSelectionService as W, ChartPrimitivesComponent as X, ChartRendererComponent as Y, ChartTrendlineOptionsComponent as Z, ChartTypeSelectorComponent as _, ALIGN_OPTIONS as a, INSTANT as a$, CollaborationService as a0, ColorChangedImageComponent as a1, CommentMarkersOverlayComponent as a2, CommentsPanelComponent as a3, CommentsService as a4, ComparePanelComponent as a5, ConnectorRendererComponent as a6, ConnectorTextOverlayComponent as a7, CustomShowsComponent as a8, DEFAULT_BOUNDS as a9, EditorContextMenuComponent as aA, EditorHistory as aB, EditorStateService as aC, EditorToolbarComponent as aD, EffectsPanelComponent as aE, ElementRendererComponent as aF, EmbeddedFontsService as aG, EncryptedFileDialogComponent as aH, EquationEditorDialogComponent as aI, EquationRendererComponent as aJ, EquationTemplateGalleryComponent as aK, ExportProgressModalComponent as aL, ExportService as aM, FieldContextService as aN, FindBarComponent as aO, FindReplaceBarComponent as aP, FollowModeBarComponent as aQ, FontEmbeddingListComponent as aR, FontEmbeddingPanelComponent as aS, GALLERY_THEME_PRESETS as aT, GOOGLE_WEBFONTS_LINK_ID as aU, GRIDLINE_COLOR$1 as aV, GoogleWebfontsService as aW, GradientPickerComponent as aX, HANDOUT_OPTIONS as aY, HeaderFooterDialogComponent as aZ, HyperlinkDialogComponent as a_, DEFAULT_BROADCAST_SERVER_URL as aa, DEFAULT_CANVAS_HEIGHT as ab, DEFAULT_CANVAS_WIDTH as ac, DEFAULT_COLOR_SCHEME as ad, DEFAULT_FILL_COLOR$1 as ae, DEFAULT_LAYOUT as af, DEFAULT_MORPH_DURATION_MS as ag, DEFAULT_PALETTE$1 as ah, DEFAULT_PATTERN_FILL_PRESET as ai, DEFAULT_PRINT_SETTINGS as aj, DEFAULT_SLIDE_BACKGROUND as ak, DEFAULT_STROKE_COLOR as al, DEFAULT_STYLE as am, DEFAULT_TABLE_ROW_HEIGHT as an, DEFAULT_TEXT_COLOR$2 as ao, DEFAULT_VIEWER_PROFILE as ap, DIRECTIONAL_PRESETS as aq, DIRECTION_OPTIONS as ar, DocumentPropertiesCardComponent as as, EASE as at, EFFECT_SOUND_CATALOGUE as au, EMBEDDED_FONTS_STYLE_ID as av, EMPHASIS_PRESETS as aw, ENTRANCE_PRESETS as ax, TEMPLATES as ay, EXIT_PRESETS as az, ANIMATION_PRESET_CATEGORIES as b, REPEAT_MODE_OPTIONS as b$, ImagePropertiesPanelComponent as b0, InkDrawingService as b1, InkRendererComponent as b2, InsertSmartArtDialogComponent as b3, InspectorPaneHeaderComponent as b4, InspectorPanelComponent as b5, IsMobileService as b6, KeepAnnotationsDialogComponent as b7, LOCALE_CATALOG as b8, LONG_PRESS_DURATION_MS as b9, POWER_POINT_VIEWER_PROVIDERS as bA, PPTX_OPEN_ACCEPT as bB, PRESENTATION_OPEN_EXTENSIONS as bC, PRESENTER_CHANNEL_NAME as bD, PRESENTER_MSG_ORIGIN as bE, PRESENTER_TIMER_SEGMENT_MS as bF, PX_PER_CM as bG, PX_PER_INCH as bH, PasswordProtectionDialogComponent as bI, PasswordStrengthMeterComponent as bJ, PowerPointViewerComponent as bK, PresentToolbarAutoHide as bL, PresentationAnnotationOverlayComponent as bM, PresentationAnnotationsService as bN, PresentationOverlayComponent as bO, PresentationPropertiesPanelComponent as bP, PresentationSettingsCardComponent as bQ, PresentationSubtitleBarComponent as bR, PresentationToolbarComponent as bS, PresentationTransitionOverlayComponent as bT, PresenterViewComponent as bU, PresenterWindowService as bV, PrintDialogComponent as bW, PrintService as bX, PrintSettingsPanelComponent as bY, PropertiesDialogComponent as bZ, RANDOM_ELIGIBLE_TYPES as b_, LONG_PRESS_MOVE_TOLERANCE_PX as ba, LoadContentService as bb, LocalPresencePublisher as bc, MAX_ZOOM_SCALE as bd, MIN_ZOOM_SCALE as be, MOTION_PATH_COLUMNS as bf, MediaPreviewComponent as bg, MediaPropertiesPanelComponent as bh, MediaRendererComponent as bi, MediaTrimTimelineComponent as bj, MobileBottomBarComponent as bk, MobileMenuSheetComponent as bl, MobilePresenterViewComponent as bm, MobileSheetComponent as bn, MobileSlidesSheetComponent as bo, MobileToolbarComponent as bp, ModalDialogComponent as bq, Model3DRendererComponent as br, NotesHandoutCardComponent as bs, NotesPanelComponent as bt, NotesToolbarComponent as bu, OleRendererComponent as bv, OutlineViewOverlayComponent as bw, P14_TRANSITION_KEYFRAMES as bx, P14_TRANSITION_KEYFRAMES_2 as by, P14_TRANSITION_KEYFRAMES_ALL as bz, AUDIENCE_HASH as c, SlideSorterOverlayComponent as c$, RESIZE_HANDLES as c0, RULER_FONT_SIZE as c1, RULER_THICKNESS as c2, ReadingViewOverlayComponent as c3, RemoteSelectionOverlayComponent as c4, RibbonAnimationGalleryComponent as c5, RibbonAnimationsSectionComponent as c6, RibbonArrangeSectionComponent as c7, RibbonColorPopoverComponent as c8, RibbonComponent as c9, DEFAULT_PALETTE as cA, PALETTES$1 as cB, SMART_ART_COLOR_SCHEMES as cC, SMART_ART_STYLE_OPTIONS as cD, SUB_ITEM_LABEL as cE, SVG_WARP_PRESETS as cF, SWIPE_MAX_VERTICAL_PX as cG, SWIPE_THRESHOLD_PX as cH, SelectionPaneComponent as cI, SetUpSlideShowDialogComponent as cJ, SettingsAppearanceTabComponent as cK, SettingsDialogComponent as cL, SettingsLanguageTabComponent as cM, ShareDialogComponent as cN, ShortcutPanelComponent as cO, ShowOptionsFieldsetComponent as cP, ShowSlidesFieldsetComponent as cQ, SignatureStrippedDialogComponent as cR, SignaturesPanelComponent as cS, SignaturesService as cT, SlideBackgroundCardComponent as cU, SlideCanvasComponent as cV, SlideDefaultInspectorComponent as cW, SlideDiffChangesComponent as cX, SlideDiffRowComponent as cY, SlideDiffThumbnailsComponent as cZ, SlideSizeCardComponent as c_, RibbonDesignSectionComponent as ca, RibbonDrawSectionComponent as cb, RibbonDrawingGroupComponent as cc, RibbonEditingSectionComponent as cd, RibbonFileSectionComponent as ce, RibbonFontControlsComponent as cf, RibbonHomeSectionComponent as cg, RibbonHyperlinkButtonComponent as ch, RibbonInsertFieldsComponent as ci, RibbonInsertSectionComponent as cj, RibbonMotionPathGalleryComponent as ck, RibbonParagraphControlsComponent as cl, RibbonPrimaryRowComponent as cm, RibbonReviewSectionComponent as cn, RibbonShapeExtrasComponent as co, RibbonSlideshowSectionComponent as cp, RibbonTransitionsSectionComponent as cq, RibbonViewSectionComponent as cr, RulerGuidesService as cs, SEQUENCE_OPTIONS as ct, SEVERITY_GROUPS as cu, SEVERITY_LABELS as cv, DEFAULT_TRANSITION_DURATION_MS$1 as cw, SHORTCUT_REFERENCE_ITEMS as cx, SLIDE_TRANSITION_KEYFRAMES as cy, SLIDE_TRANSITION_KEYFRAMES_CSS as cz, AUDIENCE_NONCE_KEY as d, ZoomNavigationService as d$, SlideThemeOverridePanelComponent as d0, SlideTransitionCardComponent as d1, SlidesPanelComponent as d2, SmartArt3DRendererComponent as d3, SmartArt3DService as d4, SmartArtPreviewComponent as d5, SmartArtPropertiesComponent as d6, SmartArtRendererComponent as d7, StatusBarComponent as d8, TABLE_STRUCTURE_TOGGLES as d9, TransitionPreviewComponent as dA, VALIGN_OPTIONS as dB, VIEWER_THEME as dC, VersionHistoryPanelComponent as dD, ViewerCanvasEditingService as dE, ViewerCollabCursorService as dF, ViewerCollaborationSessionService as dG, ViewerCompareService as dH, ViewerCustomShowsService as dI, ViewerDialogsService as dJ, ViewerDocumentPropertiesService as dK, ViewerExportService as dL, ViewerExtraDialogsComponent as dM, ViewerFileIOService as dN, ViewerFindReplaceService as dO, ViewerFormatPainterService as dP, ViewerInspectorPanelService as dQ, ViewerKeyboardService as dR, ViewerMobileSheetService as dS, ViewerPresentationModeService as dT, ViewerThemeGalleryService as dU, ViewerTouchGesturesService as dV, ViewerZoomService as dW, WEBM_MIME_CANDIDATES as dX, WHEEL_SPOKE_COUNTS as dY, WriteBackScheduler as dZ, ZERO_LINE_COLOR as d_, TEXT_3D_BOTTOM_BEVEL_KEYS as da, TEXT_3D_TOP_BEVEL_KEYS as db, TEXT_DIRECTION_OPTIONS$1 as dc, THEME_CATALOG as dd, TIMING_CURVE_OPTIONS as de, TRANSITION_SPEED_DURATION_MS as df, TRIGGER_OPTIONS as dg, TYPE_LABELS as dh, TableCellAdvancedFillComponent as di, TableCellFormattingComponent as dj, TableDataEditorComponent as dk, TablePropertiesComponent as dl, TableRendererComponent as dm, TableResizeOverlayComponent as dn, TableSelectionService as dp, TagsCardComponent as dq, Text3DBevelSectionComponent as dr, Text3DPanelComponent as ds, TextAdvancedPanelComponent as dt, ThemeEditorFieldsComponent as du, ThemeGalleryComponent as dv, ThemeSelectorCardComponent as dw, TitleBarComponent as dx, TitleBarSearchComponent as dy, TransitionDirectionPickerComponent as dz, AVATAR_COLOR_SWATCHES as e, buildModel3DViewModel as e$, ZoomRendererComponent as e0, ZoomTargetService as e1, addCategory as e2, addCommentToList as e3, addGradientStopPatch as e4, addItem as e5, addSeries as e6, addSubItem as e7, advanceStep as e8, affordanceElements as e9, buildCellParagraphs as eA, buildChartViewModel as eB, buildChatLogExport as eC, buildChatLogMarkdown as eD, buildChromeStyle as eE, buildClearHyperlinkPatch as eF, buildClickGroups as eG, buildColStyles as eH, buildCollaborationConfig as eI, buildComboViewModel as eJ, buildCssGradientFromShapeStyle as eK, buildDuotoneFilter as eL, buildDuotoneFilterId as eM, buildEmbeddedFontStyles as eN, buildEquationElement as eO, buildEquationSegment as eP, buildFallbackViewModel as eQ, buildFontFaceRule as eR, buildGradientFillCss as eS, buildGridlinesAndLabels as eT, buildHyperlinkPatch as eU, buildInkContainerStyle as eV, buildInkStrokes as eW, buildLegend as eX, buildLiveInkStrokeView as eY, buildMarkTooltip as eZ, buildModel3DContainerStyle as e_, aiToggleVisible as ea, alignPatch as eb, animationFor as ec, animationPresetLabelKey as ed, annotationMapToInkInserts as ee, applyAcceptedDiff as ef, applyAnimationPreset as eg, applyFindReplacements as eh, applyFormatToElement as ei, applyMove as ej, applyResize as ek, asMediaElement as el, assignUserColor as em, attachShowVisibilityPause as en, attachTouchGestures as eo, axisTickValues as ep, beginDrawingNodeEdit as eq, beginNodeEdit as er, bevelSizePatch as es, boolFromEvent as et, bringForward as eu, bringToFront as ev, buildBarActions as ew, buildBroadcastConfig as ex, buildBroadcastViewerUrl as ey, buildCategoryLabels as ez, AXIS_LABEL_COLOR as f, computeErrorBarPrimitives as f$, buildOleActionModel as f0, buildOleInfoRows as f1, buildPatternFillCss as f2, buildPieViewModel as f3, buildPrintHtmlDocument as f4, buildPropertiesPatch as f5, buildRadarViewModel as f6, buildRegionMapViewModel as f7, buildSaveSlides as f8, buildShareUrl as f9, changeIcon as fA, characterSpacingPatch as fB, chartPreserveAspectRatio as fC, checkFontAvailable as fD, clampCursorPosition as fE, clampGifDimensions as fF, clampIndex as fG, clampNotesFontSize as fH, clampScale as fI, clampStep as fJ, clearAllLocalViewerData as fK, clearAudienceContent as fL, cn as fM, collectAccessibilityIssues as fN, collectElementText as fO, collectSlideText as fP, collectStoredChats as fQ, collectUsedFontFamilies as fR, columnWidthStyle as fS, commitNodeText as fT, computeAlign as fU, computeAxisTitlePrimitives as fV, computeBarRects as fW, computeBubbleRadius as fX, computeCornerHandle as fY, computeDistribute as fZ, computeDrawingViewBox as f_, buildSmartArtInsertElement as fa, buildSmartArtNodes as fb, buildStockViewModel as fc, buildSurfaceViewModel as fd, buildTableViewModel as fe, buildTreemapViewModel as ff, buildTrimFragment as fg, buildWaterfallViewModel as fh, buildZeroLine as fi, buildZoomContainerStyle as fj, buildZoomViewModel as fk, bulletIndentPx as fl, canAddTopLevelNode as fm, canEditSmartArtNodes as fn, canGroupSelection as fo, canRemoveTopLevelNode as fp, canSetStrokeWidth as fq, canStartBroadcast as fr, canStartShare as fs, canUngroupSelection as ft, canUseClipboard as fu, captionDisplayText as fv, cellRunStyle as fw, cellStyleToStyleMap as fx, cellTdStyle as fy, changeCountLabel as fz, AccessibilityPanelComponent as g, encodeGif as g$, computeFocusTargets as g0, computeGridSpacingPx as g1, computeHandleBoxes as g2, computeHandoutLayout as g3, computeIsMobile as g4, computeIsTablet as g5, computeLinePoints as g6, computeLinearRegression as g7, computePageCount as g8, computePieLayout as g9, createWebsocketBundle as gA, cssObjectToStyleMap as gB, currentColorScheme as gC, currentLayout as gD, currentStyle as gE, defaultCssVars as gF, defaultRadius as gG, defaultThemeColors as gH, deleteElementsByIds as gI, deleteVersion as gJ, demoteNode as gK, deriveModel3DBlobUrl as gL, derivePresenceList as gM, describeSmartArtBounds as gN, disableGlowPatch as gO, disableInnerShadowPatch as gP, disableOuterShadowPatch as gQ, disableReflectionPatch as gR, disableSoftEdgePatch as gS, duplicateElementById as gT, durationOf as gU, effectsStateOf as gV, enableGlowPatch as gW, enableInnerShadowPatch as gX, enableOuterShadowPatch as gY, enableReflectionPatch as gZ, enableSoftEdgePatch as g_, computePieSlicePath as ga, computePieSlices as gb, computePlotLayout as gc, computeRSquared as gd, computeRadarPoints as ge, computeResizeHandleBoxes as gf, computeRotateHandleBox as gg, computeScatterDots as gh, computeScatterXDomain as gi, computeSelectionBoxes as gj, computeSingleSelected as gk, computeSlideIndices as gl, computeSnap as gm, computeStackedBarRects as gn, computeStackedValueRange as go, computeTrendlinePrimitives as gp, computeValueRange as gq, convertOmmlToMathMl as gr, copyFormatFromElement as gs, countAccessibilityIssues as gt, countAnnotationStrokes as gu, createAngularAiBridge as gv, createCustomShow as gw, createImageElementFromFile as gx, createSwipeDismissDrag as gy, createWebrtcBundle as gz, AccessibilityService as h, gradientStateFromStyle as h$, endShowMediaCleanup as h0, estimatePageCount as h1, exitPresentationFullscreen as h2, exportAiChatLogs as h3, extractPathPoints as h4, eyedropperAvailable as h5, fillColorOf$1 as h6, findInSlides as h7, findOwningSlideIndex as h8, findSlideIndexByElementId as h9, getEffectSoundState as hA, getImageSrc as hB, getLocalStorageUsageSummary as hC, getOleAriaLabel as hD, getOleBadgeLabel as hE, getOleDisplayName as hF, getOleDownloadFileName as hG, getOleTypeColor as hH, getOleTypeLabel as hI, getP14TransitionAnimations as hJ, getPasswordStrength as hK, getPatternSvg as hL, getPlaceholderStyle as hM, getVersions as hN, getResolvedShapeClipPath as hO, getResolvedShapeClipPathFor as hP, getSessionTabId as hQ, getShapeFillStrokeStyle as hR, getSlideBackgroundStyle as hS, getSlideTransitionAnimations as hT, getSmartArtNodeBounds as hU, getSpeechRecognitionCtor as hV, getTextBlockStyle as hW, getTextWarp as hX, getTouchDistance as hY, getWarpCategory as hZ, getWarpPath as h_, firstVisibleIndex as ha, fitPolynomial as hb, fitZoom as hc, focusTargetChips as hd, fontMimeForFormat as he, fontSizeOf as hf, forgetSessionDeck as hg, formatAxisValue as hh, formatBytes as hi, formatCursorLabel as hj, formatElapsed as hk, formatFileSize as hl, formatInlineListStyle as hm, formatPropertyDate as hn, formatTime as ho, fpsToFrameIntervalMs as hp, generateBroadcastRoomId as hq, generateCommentId as hr, generateCustomShowId as hs, generatePressureCircles as ht, generateTicks as hu, getCinematicTransitionAnimations as hv, getClrChangeParams as hw, getContainerStyle as hx, getDuotoneFilterDef as hy, getEffectSoundAsset as hz, AccessibilityTextPanelComponent as i, narrowToRect as i$, gradientStateOf as i0, gradientStatePatch as i1, gradientStopColorCommitPatch as i2, gridColumns as i3, groupIssuesBySeverity as i4, hasAnimation as i5, hasCopyableFormat as i6, hasExistingLink as i7, hasExitedFullscreen as i8, hasGradientFill as i9, isValidRoomId as iA, isViewportBackgroundPressTarget as iB, isZoomActivationKey as iC, issueTrackKey as iD, issueTypeLabel as iE, keyToLabel as iF, lastVisibleIndex as iG, latexToMathml as iH, layoutConnectorPaints as iI, layoutNodeLabels as iJ, linePointsToSvgString as iK, lineSpacingPatch as iL, loadAudienceContent as iM, loadSessionDeck as iN, mediaFallbackFor as iO, mediaSurfaceFor as iP, mergeCaptionResults as iQ, mergeDown as iR, mergeRight as iS, mergeSelection as iT, mergeTablesDirective as iU, moveElementBy as iV, moveNodeDown as iW, moveNodeUp as iX, msToFrameDelayCs as iY, narrowToCircle as iZ, narrowToPolygon as i_, hasPressureVariation as ia, hasVisibleSlideAfter as ib, headerLabel as ic, imageDimensions as id, inkViewBox as ie, insertTableElementColumn as ig, insertTableElementRow as ih, interpolateWidth as ii, isAudienceTab as ij, isBold as ik, isBrowserOpenableMime as il, isChildNode as im, isElementInteractive as io, isInjectableUrl as ip, isItalic as iq, isLegacyBinaryPresentation as ir, isPpactionUrl as is, isPresenterMessage as it, isSigned as iu, isSupportedPresentationFile as iv, isTextElement as iw, isTwoTableFocus as ix, isUnderline as iy, isUrlSafe as iz, AccountPageComponent as j, removeNode as j$, newChartElement as j0, newEquationElement as j1, newPresetShapeElement as j2, newShapeElement as j3, newSmartArtElement as j4, newTableElement as j5, newTextElement as j6, nextVisibleIndex as j7, nodeBold as j8, nodeEditBox as j9, planGifFrames as jA, planVideoSegments as jB, pointFromPointerEvent as jC, pointsToSvgPathD as jD, presenceToCursors as jE, presentationBaseName as jF, presentationStageStyle as jG, presenterTimerProgress as jH, presetByLayout as jI, presetsForCategory as jJ, pressuresToWidths as jK, prevVisibleIndex as jL, projectDrawingShapes as jM, promoteNode as jN, provideViewerTheme as jO, radarAngle as jP, radarRingPoints as jQ, readAsDataUrl as jR, recordWebm as jS, registerCrossSlideAudio as jT, rememberSessionDeck as jU, removeAnimation as jV, removeCategory as jW, removeTableElementColumn as jX, removeCommentFromList as jY, removeElementAnimation as jZ, removeGradientStopPatch as j_, nodeFillColor as ja, nodeFontColor as jb, nodeIdFromKey as jc, nodeItalic as jd, nodeStyle as je, normalizeFontFormat as jf, normalizeSlidesPerPage as jg, normalizeValue as jh, numFromEvent as ji, ommlToMathml as jj, ooxmlDashToCssBorderStyle as jk, openNativeEyeDropper as jl, overallStatus as jm, paletteColor as jn, parseAudienceNonce as jo, parseNodeTextarea as jp, partitionSlides as jq, patchChartData as jr, patchChartStyle as js, patchTableData as jt, patchTextStyle as ju, patternPresetOptions as jv, pendingElementStyles as jw, pickColorByClickFallback as jx, pickFile as jy, pickSupportedMimeType as jz, ActionSettingsPanelComponent as k, setAxisLogScale as k$, removeTableElementRow as k0, removeSeries as k1, renderToCanvas as k2, reorderAnimationDown as k3, reorderAnimationUp as k4, replaceInSlides as k5, replaceMatch as k6, requestPresentationFullscreen as k7, resizeElement as k8, resolveCaptionTracks as k9, rulerHighlight as kA, rulerStripTicks as kB, sampleColorFromSlide as kC, sanitizeColor as kD, sanitizeSlideIndex as kE, sanitizeUserName as kF, saveViewerProfile as kG, savedPresentationFileName as kH, scanAvailableFonts as kI, searchSlides as kJ, seedBroadcastFields as kK, seedHyperlinkDraft as kL, seedPropertiesDraft as kM, seedShareFields as kN, segmentFrameCount as kO, selectValue$3 as kP, sendBackward as kQ, sendToBack as kR, sequentialColorScale as kS, serializeWriteBack as kT, seriesColor as kU, setAfterAnimation as kV, setAfterAnimationColor as kW, setAnimationEmphasis as kX, setAnimationEntrance as kY, setAnimationExit as kZ, setAxis as k_, resolveChartKind as ka, resolveDirection as kb, resolveDirection8 as kc, resolveFontVariant as kd, resolveHyperlinkHref as ke, resolveInteractiveElementId as kf, resolveMediaSrc as kg, resolveOleType as kh, resolveOrientation as ki, resolveParagraphBullet as kj, resolvePresenterNotes as kk, resolveProfileInitial as kl, resolveRegionCode as km, resolveRibbonCanGroup as kn, resolveSlideAutoAdvanceMs as ko, resolveSlideTransition as kp, resolvePalette as kq, resolveThemeCatalogEntry as kr, resolveTransitionDuration as ks, resolveTransitionDurationMs as kt, resolveWheelSpokeCount as ku, restoreSessionDeck as kv, revealedElementStyles as kw, routeOrthogonalConnector as kx, rowStyle as ky, rulerDragToGuidePosition as kz, AdvancedChartEditorComponent as l, textAdvancedStateFromStyle as l$, setAxisTitleStyle as l0, setCategoryLabel as l1, setCellText as l2, setColorScheme as l3, setDataLabels as l4, setDataPointExplosion as l5, setDataPointFill as l6, setDataPointLabel as l7, setDataPointMarker as l8, setDelay as l9, sheetAfterNavigate as lA, shouldBlockClickAdvance as lB, shouldUseSvgWarp as lC, showDirectionPicker as lD, showsTemplateAffordance as lE, signatureCountLabel as lF, signatureKey as lG, signatureTimestamp as lH, signerName as lI, statusLabel as lJ, slideNumberOf as lK, slidesWithReappliedLayout as lL, smartArtNodes as lM, paletteColour as lN, snapToGridStep as lO, splitCursorCell as lP, splitMergedCell as lQ, statusKind as lR, statusLabel$1 as lS, storeAudienceContent as lT, stringFromEvent$5 as lU, strokeColorOf as lV, strokeToInkElement as lW, strokeWidthOf as lX, styleShadowFilter as lY, surfaceColor as lZ, textAdvancedPatch as l_, setDirection as la, setDuration as lb, setEffectSound as lc, setEffectStockSound as ld, setElementPosition as le, setGridlineStyle as lf, setLayout as lg, setLegend as lh, setNodeStyle as li, setNodeText as lj, setRepeatCount as lk, setRepeatMode as ll, setSequence as lm, setSeriesChartType as ln, setSeriesColor as lo, setSeriesErrorBars as lp, setSeriesMarker as lq, setSeriesName as lr, setSeriesTrendline as ls, setSeriesValue as lt, setStyle as lu, setTimingCurve as lv, setTitle as lw, setTrigger as lx, setTriggerShapeId as ly, shapeStylePatch$1 as lz, AiChangeOverlayComponent as m, textAdvancedStateOf as m0, textColorOf as m1, textDirectionPatch as m2, textFontSizePatch as m3, textStyleOf as m4, textStylePatch as m5, themeStyle as m6, themeToCssVars as m7, thumbnailHeight as m8, thumbnailZoom as m9, zoomTargetSlideIndex as mA, toggleCommentResolvedInList as ma, toggleNodeBold as mb, toggleNodeItalic as mc, toggleSheet as md, topLevelNodeCount as me, transformSelectedTextCase as mf, translationsEn as mg, updateElementById as mh, updateGlowPatch as mi, updateGradientStopPatch as mj, updateInnerShadowPatch as mk, updateOuterShadowPatch as ml, updateReflectionPatch as mm, vAlignPatch as mn, validatePassword as mo, validatePrintSettings as mp, validateRoomId as mq, valueToY as mr, vermilionDarkColors as ms, vermilionDarkTheme as mt, vermilionLightColors as mu, vermilionLightTheme as mv, vermilionRadius as mw, waypointsToPathD as mx, withManualLayouts as my, worstStatus as mz, AiChatPanelComponent as n, AiChatService as o, AiComposerComponent as p, AiFocusBarComponent as q, AiFocusHighlightOverlayComponent as r, AiHistoryMenuComponent as s, toChatSummary as t, AiHistoryService as u, AiMessageListComponent as v, AiPanelStore as w, AiProposalCardComponent as x, AiSettingsSectionComponent as y, AiToolCallCardComponent as z };
185882
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-D2wmF5iB.mjs.map
186199
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-Di10-gYO.mjs.map