pptx-kit-preview 0.3.0 → 0.3.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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getSlideSize, getPresentationTheme, getEffectiveColorMap, getSlideBackground, getSlideLayout, getSlideLayoutBackground, getSlideMasterBackground, getSlideBackgroundGradientFill, getSlideLayoutBackgroundGradientFill, getSlideMasterBackgroundGradientFill, getSlideBackgroundPatternFill, getSlideLayoutBackgroundPatternFill, getSlideMasterBackgroundPatternFill, getSlideBackgroundImageBytes, getSlideLayoutBackgroundImageBytes, getSlideMasterBackgroundImageBytes, getSlideMasterShapes, getSlideLayoutShapes, getSlideShapes, getShapeBoundsResolved, getShapeKind, getShapeFillEffective, getShapeStrokeEffective, getShapeRotation, getShapeFlip, getShapePlaceholderType, getShapeImageFormat, getShapeImageBytes, getShapeImageFillBytes, getShapePreset, getGroupTransform, getGroupChildren, isChartShape, isTableShape, getTableDimensions, getShapeCustomGeometry, getShapeXmlString, getShapeAdjustValues, getShapeHyperlink, getShapeHyperlinkTooltip, getShapeName, getShapeAltTitle, getShapeDescription, getShapeClickAction, getSlideIndex, getShapeParagraphCount, getPresentationFonts, getShapeBodyPrEffective, getShapeTextMargins, getShapeTextDirection, getShapeTextAnchor, isShapePlaceholder, isShapeTextBox, getParagraphPropertiesEffective, getParagraphLevel, getParagraphAlignment, getParagraphBullet, getParagraphBulletStyle, isParagraphBulletPicture, getParagraphBulletImageBytes, getParagraphSpacing, getParagraphIndent, getShapeParagraphElements, getShapeRunFormatEffective, getShapeRunFormat, getShapeRunHyperlink, getShapeRunClickAction, getShapeRunHyperlinkTooltip, getShapeTextAutoFitParams, getShapeTextColumns, getShapeTextBodyRotationDeg, getShapeImagePartName, getShapeImageCrop, getShapeImageBrightness, getShapeImageContrast, getShapeImageOpacity, isShapeImageGrayscale, getShapeImageBiLevelThreshold, getShapeImageDuotone, getShapeImageLinkUrl, getShapeFillColorResolved, getShapeGradientFillEffective, getShapeGradientFill, getShapePatternFill, getShapeStrokeColorResolved, getShapeStrokeDash, getShapeStrokeCap, getShapeStrokeJoin, getShapeStrokeCompound, getShapeStrokeArrow, getShapeChartSpec, getTableColumnWidths, getTableRowHeights, getTableCells, getTableStyleFlags, getTableCellSpan, getTableCellFill, getTableCellBorders, getTableCellParagraphs, getTableCellAnchor, getTableCellMargins, getShapeEffectsEffective } from 'pptx-kit';
1
+ import { getSlideSize, getPresentationTheme, getEffectiveColorMap, resolveDeckBodyTextColor, getSlideBackground, getSlideLayout, getSlideLayoutBackground, getSlideMasterBackground, getSlideBackgroundGradientFill, getSlideLayoutBackgroundGradientFill, getSlideMasterBackgroundGradientFill, getSlideBackgroundPatternFill, getSlideLayoutBackgroundPatternFill, getSlideMasterBackgroundPatternFill, getSlideBackgroundImageBytes, getSlideLayoutBackgroundImageBytes, getSlideMasterBackgroundImageBytes, getSlideMasterShapes, getSlideLayoutShapes, getSlideShapes, getShapeBoundsResolved, getShapeKind, getShapeFillEffective, getShapeStrokeEffective, getShapeRotation, getShapeFlip, getShapePlaceholderType, getShapeImageFormat, getShapeImageBytes, getShapeImageFillBytes, getShapePreset, getGroupTransform, getGroupChildren, isChartShape, isTableShape, getTableDimensions, getShapeCustomGeometry, getShapeXmlString, getShapeAdjustValues, getShapeHyperlink, getShapeHyperlinkTooltip, getShapeName, getShapeAltTitle, getShapeDescription, getShapeClickAction, getSlideIndex, getShapeParagraphCount, getPresentationFonts, getShapeBodyPrEffective, getShapeTextMargins, getShapeTextDirection, getShapeTextAnchor, isShapePlaceholder, isShapeTextBox, getParagraphPropertiesEffective, getParagraphLevel, getParagraphAlignment, getParagraphBullet, getParagraphBulletStyle, isParagraphBulletPicture, getParagraphBulletImageBytes, getParagraphSpacing, getParagraphIndent, getShapeParagraphElements, getShapeRunFormatEffective, getShapeRunFormat, getShapeRunHyperlink, getShapeRunClickAction, getShapeRunHyperlinkTooltip, getShapeTextAutoFitParams, getShapeTextColumns, getShapeTextBodyRotationDeg, getShapeImagePartName, getShapeImageCrop, getShapeImageBrightness, getShapeImageContrast, getShapeImageOpacity, isShapeImageGrayscale, getShapeImageBiLevelThreshold, getShapeImageDuotone, getShapeImageLinkUrl, getShapeFillColorResolved, getShapeGradientFillEffective, getShapeGradientFill, getShapePatternFill, getShapeStrokeColorResolved, getShapeStrokeDash, getShapeStrokeCap, getShapeStrokeJoin, getShapeStrokeCompound, getShapeStrokeArrow, getShapeChartSpec, getTableColumnWidths, getTableRowHeights, getTableCells, getTableStyleFlags, getTableCellSpan, getTableCellFill, getTableCellBorders, getTableCellParagraphs, getTableCellAnchor, getTableCellMargins, getShapeEffectsEffective } from 'pptx-kit';
2
2
 
3
3
  // src/render-slide.ts
4
4
 
@@ -560,6 +560,7 @@ var resolveColor = (c, theme, fallback = "#1F2937") => {
560
560
  var nextDefId = 0;
561
561
  var mintId = () => `pkdef-${(nextDefId++).toString(36)}`;
562
562
  var activeColorMap = null;
563
+ var activeDeckTextColor = "#000000";
563
564
  var gradientDef = (grad, theme) => {
564
565
  const id = mintId();
565
566
  const stops = grad.stops.map(
@@ -602,27 +603,23 @@ var patternDef = (pat) => {
602
603
  return `<path d="M0 0L${W} ${H}" stroke="${fg}" stroke-width="${width}"/>`;
603
604
  return `<path d="M${W} 0L0 ${H}" stroke="${fg}" stroke-width="${width}"/>`;
604
605
  };
605
- const dots = (density) => {
606
- const count = Math.max(1, Math.round(density * 4));
606
+ const BAYER4 = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
607
+ const screen = (density) => {
608
+ const threshold = density * 16;
607
609
  const out = [];
608
- const grid = count <= 1 ? [[4, 4]] : count === 2 ? [
609
- [2, 2],
610
- [6, 6]
611
- ] : [
612
- [2, 2],
613
- [6, 2],
614
- [2, 6],
615
- [6, 6]
616
- ];
617
- for (const [x, y] of grid.slice(0, count)) {
618
- out.push(`<circle cx="${x}" cy="${y}" r="0.7" fill="${fg}"/>`);
610
+ for (let i = 0; i < 16; i++) {
611
+ if (BAYER4[i] < threshold) {
612
+ const cx = i % 4 * 2;
613
+ const cy = Math.floor(i / 4) * 2;
614
+ out.push(`<rect x="${cx}" y="${cy}" width="2" height="2" fill="${fg}"/>`);
615
+ }
619
616
  }
620
617
  return out.join("");
621
618
  };
622
619
  const pctMatch = /^pct(\d+)$/.exec(preset);
623
620
  if (pctMatch) {
624
- const pct = Math.min(100, Math.max(5, Number.parseInt(pctMatch[1], 10)));
625
- body = dots(pct / 100);
621
+ const pct = Math.min(100, Math.max(0, Number.parseInt(pctMatch[1], 10)));
622
+ body = screen(pct / 100);
626
623
  } else if (preset === "horzBrick" || preset === "ltHorizontal" || preset === "narHorz") {
627
624
  body = stripe("h", 0.8);
628
625
  } else if (preset === "dkHorizontal") {
@@ -656,7 +653,7 @@ var patternDef = (pat) => {
656
653
  } else if (preset === "solidDmnd" || preset === "openDmnd") {
657
654
  body = `<path d="M4 1L7 4 4 7 1 4Z" fill="${preset === "solidDmnd" ? fg : "none"}" stroke="${fg}" stroke-width="0.6"/>`;
658
655
  } else {
659
- body = dots(0.5);
656
+ body = screen(0.5);
660
657
  }
661
658
  const defs = `<defs><pattern id="${id}" patternUnits="userSpaceOnUse" width="${W}" height="${H}"><rect width="${W}" height="${H}" fill="${bg}"/>${body}</pattern></defs>`;
662
659
  return { defs, fillAttr: `url(#${id})` };
@@ -2321,7 +2318,7 @@ var renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
2321
2318
  );
2322
2319
  }
2323
2320
  const justify = ANCHOR_TO_CSS[anchor] ?? "flex-start";
2324
- const defaultColor = resolveColor("scheme:tx1", theme, "#000000");
2321
+ const defaultColor = activeDeckTextColor;
2325
2322
  if (ctx.mode === "svg") {
2326
2323
  const svgScale = authoredAutofit?.fontScale ?? 1;
2327
2324
  const svgLineScale = 1 - (authoredAutofit?.lnSpcReduction ?? 0);
@@ -2515,6 +2512,9 @@ var DISPLAY_UNIT_LABEL = {
2515
2512
  billions: "Billions",
2516
2513
  trillions: "Trillions"
2517
2514
  };
2515
+ var DEFAULT_AXIS_COLOR = "#000000";
2516
+ var DEFAULT_GRID_COLOR = "#D9D9D9";
2517
+ var AXIS_TICK_LEN = 5;
2518
2518
  var axisTickAttrs = (style) => {
2519
2519
  const sz = style?.sizePt ?? 10;
2520
2520
  const fill = style?.color ?? "#6B7280";
@@ -2531,10 +2531,15 @@ var renderValueAxis = (f, axis) => {
2531
2531
  })() : niceTicks(axis.min, axis.max);
2532
2532
  const out = [];
2533
2533
  const range = axis.max - axis.min || 1;
2534
- const showGrid = axis.majorGridlines ?? true;
2535
- const gridStroke = axis.majorGridlineColor ?? "#E5E7EB";
2534
+ const fmtTick = (t) => axis.percent ? `${Math.round(t * 100)}%` : formatAxisLabel(
2535
+ axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2536
+ axis.numberFormat
2537
+ );
2538
+ const showGrid = axis.majorGridlines ?? false;
2539
+ const gridStroke = axis.majorGridlineColor ?? DEFAULT_GRID_COLOR;
2540
+ const axisColor = axis.lineColor ?? DEFAULT_AXIS_COLOR;
2536
2541
  const tickMark = axis.majorTickMark ?? "out";
2537
- const tickLen = 3;
2542
+ const tickLen = AXIS_TICK_LEN;
2538
2543
  for (const t of ticks) {
2539
2544
  if (axis.orientation === "vertical") {
2540
2545
  const yp = f.plotY + f.plotH - (t - axis.min) / range * f.plotH;
@@ -2547,19 +2552,14 @@ var renderValueAxis = (f, axis) => {
2547
2552
  const tx1 = tickMark === "in" ? f.plotX : f.plotX - tickLen;
2548
2553
  const tx2 = tickMark === "out" ? f.plotX : tickMark === "cross" ? f.plotX + tickLen : f.plotX + tickLen;
2549
2554
  out.push(
2550
- `<line x1="${px(tx1)}" y1="${px(yp)}" x2="${px(tx2)}" y2="${px(yp)}" stroke="#9CA3AF" stroke-width="0.5"/>`
2555
+ `<line x1="${px(tx1)}" y1="${px(yp)}" x2="${px(tx2)}" y2="${px(yp)}" stroke="${axisColor}" stroke-width="1"/>`
2551
2556
  );
2552
2557
  }
2553
2558
  const labelX = f.plotX - 4;
2554
2559
  const rot = axis.labelRotationDeg ?? 0;
2555
2560
  const transform = rot ? ` transform="rotate(${rot} ${px(labelX)} ${px(yp)})"` : "";
2556
2561
  out.push(
2557
- `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(
2558
- formatAxisLabel(
2559
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2560
- axis.numberFormat
2561
- )
2562
- )}</text>`
2562
+ `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(fmtTick(t))}</text>`
2563
2563
  );
2564
2564
  } else {
2565
2565
  const xp = f.plotX + (t - axis.min) / range * f.plotW;
@@ -2573,19 +2573,14 @@ var renderValueAxis = (f, axis) => {
2573
2573
  const ty1 = tickMark === "in" ? baseY : baseY + tickLen;
2574
2574
  const ty2 = tickMark === "out" ? baseY : tickMark === "cross" ? baseY - tickLen : baseY - tickLen;
2575
2575
  out.push(
2576
- `<line x1="${px(xp)}" y1="${px(ty1)}" x2="${px(xp)}" y2="${px(ty2)}" stroke="#9CA3AF" stroke-width="0.5"/>`
2576
+ `<line x1="${px(xp)}" y1="${px(ty1)}" x2="${px(xp)}" y2="${px(ty2)}" stroke="${axisColor}" stroke-width="1"/>`
2577
2577
  );
2578
2578
  }
2579
2579
  const horizLabelY = f.plotY + f.plotH + 12;
2580
2580
  const rotH = axis.labelRotationDeg ?? 0;
2581
2581
  const transformH = rotH ? ` transform="rotate(${rotH} ${px(xp)} ${px(horizLabelY)})"` : "";
2582
2582
  out.push(
2583
- `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(
2584
- formatAxisLabel(
2585
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2586
- axis.numberFormat
2587
- )
2588
- )}</text>`
2583
+ `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(fmtTick(t))}</text>`
2589
2584
  );
2590
2585
  }
2591
2586
  }
@@ -2603,16 +2598,16 @@ var renderValueAxis = (f, axis) => {
2603
2598
  );
2604
2599
  }
2605
2600
  }
2606
- if (axis.lineColor !== void 0) {
2607
- if (axis.orientation === "vertical") {
2608
- out.push(
2609
- `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${axis.lineColor}" stroke-width="0.75"/>`
2610
- );
2611
- } else {
2612
- out.push(
2613
- `<line x1="${px(f.plotX)}" y1="${px(f.plotY + f.plotH)}" x2="${px(f.plotX + f.plotW)}" y2="${px(f.plotY + f.plotH)}" stroke="${axis.lineColor}" stroke-width="0.75"/>`
2614
- );
2615
- }
2601
+ if (axis.orientation === "vertical") {
2602
+ out.push(
2603
+ `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${axisColor}" stroke-width="1"/>`
2604
+ );
2605
+ } else {
2606
+ const zeroY = f.plotY + f.plotH - (0 - axis.min) / range * f.plotH;
2607
+ const spineY = axis.min <= 0 && axis.max >= 0 ? zeroY : f.plotY + f.plotH;
2608
+ out.push(
2609
+ `<line x1="${px(f.plotX)}" y1="${px(spineY)}" x2="${px(f.plotX + f.plotW)}" y2="${px(spineY)}" stroke="${axisColor}" stroke-width="1"/>`
2610
+ );
2616
2611
  }
2617
2612
  return out.join("");
2618
2613
  };
@@ -2641,7 +2636,7 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2641
2636
  const truncLen = labelRotationDeg && Math.abs(labelRotationDeg) >= 30 ? 28 : 14;
2642
2637
  for (let i = 0; i < pointCount2; i++) {
2643
2638
  if (skip > 1 && i % skip !== 0) continue;
2644
- const cy = f.plotY + (i + 0.5) * step;
2639
+ const cy = f.plotY + (pointCount2 - 1 - i + 0.5) * step;
2645
2640
  const lx = f.plotX - 4;
2646
2641
  const truncated = labels[i] !== void 0 && labels[i].length > truncLen ? `${labels[i].slice(0, truncLen - 2)}\u2026` : labels[i] ?? "";
2647
2642
  const transform = labelRotationDeg && labelRotationDeg !== 0 ? ` transform="rotate(${labelRotationDeg} ${px(lx)} ${px(cy)})"` : "";
@@ -2650,27 +2645,63 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2650
2645
  );
2651
2646
  }
2652
2647
  }
2653
- if (lineColor !== void 0) {
2654
- if (orientation === "horizontal") {
2648
+ const axisColor = lineColor ?? DEFAULT_AXIS_COLOR;
2649
+ if (orientation === "horizontal") {
2650
+ const baseY = f.plotY + f.plotH;
2651
+ out.push(
2652
+ `<line x1="${px(f.plotX)}" y1="${px(baseY)}" x2="${px(f.plotX + f.plotW)}" y2="${px(baseY)}" stroke="${axisColor}" stroke-width="1"/>`
2653
+ );
2654
+ const stepB = pointCount2 > 0 ? f.plotW / pointCount2 : 0;
2655
+ for (let i = 0; i <= pointCount2; i++) {
2656
+ const bx = f.plotX + i * stepB;
2655
2657
  out.push(
2656
- `<line x1="${px(f.plotX)}" y1="${px(f.plotY + f.plotH)}" x2="${px(f.plotX + f.plotW)}" y2="${px(f.plotY + f.plotH)}" stroke="${lineColor}" stroke-width="0.75"/>`
2658
+ `<line x1="${px(bx)}" y1="${px(baseY)}" x2="${px(bx)}" y2="${px(baseY + AXIS_TICK_LEN)}" stroke="${axisColor}" stroke-width="1"/>`
2657
2659
  );
2658
- } else {
2660
+ }
2661
+ } else {
2662
+ out.push(
2663
+ `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${axisColor}" stroke-width="1"/>`
2664
+ );
2665
+ const stepB = pointCount2 > 0 ? f.plotH / pointCount2 : 0;
2666
+ for (let i = 0; i <= pointCount2; i++) {
2667
+ const by = f.plotY + i * stepB;
2659
2668
  out.push(
2660
- `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${lineColor}" stroke-width="0.75"/>`
2669
+ `<line x1="${px(f.plotX - AXIS_TICK_LEN)}" y1="${px(by)}" x2="${px(f.plotX)}" y2="${px(by)}" stroke="${axisColor}" stroke-width="1"/>`
2661
2670
  );
2662
2671
  }
2663
2672
  }
2664
2673
  return out.join("");
2665
2674
  };
2666
2675
  var seriesMinMax = (spec) => {
2676
+ const isStacked = spec.grouping === "stacked" || spec.grouping === "percentStacked";
2677
+ const isPercent = spec.grouping === "percentStacked";
2667
2678
  let min = Infinity;
2668
2679
  let max = -Infinity;
2669
- for (const s of spec.series) {
2670
- for (const v of s.values) {
2671
- if (v !== null && Number.isFinite(v)) {
2672
- if (v < min) min = v;
2673
- if (v > max) max = v;
2680
+ if (isPercent) {
2681
+ min = 0;
2682
+ max = 1;
2683
+ } else if (isStacked) {
2684
+ const N = spec.series.reduce((n, s) => Math.max(n, s.values.length), 0);
2685
+ for (let c = 0; c < N; c++) {
2686
+ let pos = 0;
2687
+ let neg = 0;
2688
+ for (const s of spec.series) {
2689
+ const v = s.values[c];
2690
+ if (v !== null && v !== void 0 && Number.isFinite(v)) {
2691
+ if (v >= 0) pos += v;
2692
+ else neg += v;
2693
+ }
2694
+ }
2695
+ if (pos > max) max = pos;
2696
+ if (neg < min) min = neg;
2697
+ }
2698
+ } else {
2699
+ for (const s of spec.series) {
2700
+ for (const v of s.values) {
2701
+ if (v !== null && Number.isFinite(v)) {
2702
+ if (v < min) min = v;
2703
+ if (v > max) max = v;
2704
+ }
2674
2705
  }
2675
2706
  }
2676
2707
  }
@@ -2678,6 +2709,9 @@ var seriesMinMax = (spec) => {
2678
2709
  if (!Number.isFinite(max)) max = 1;
2679
2710
  if (max === min) max = min + 1;
2680
2711
  if (min > 0) min = 0;
2712
+ if (isPercent) {
2713
+ return { min: 0, max: 1, step: 0.2 };
2714
+ }
2681
2715
  const step = niceStep(max - min);
2682
2716
  max = (Math.floor(max / step) + 1) * step;
2683
2717
  if (spec.valueAxis?.min !== void 0) min = spec.valueAxis.min;
@@ -2703,9 +2737,9 @@ var renderChartLegend = (f, names, colors, position = "b", textStyle, markerSymb
2703
2737
  const swatch = (i, swatchX, swatchY) => {
2704
2738
  const color = colors[i % colors.length];
2705
2739
  const sym = markerSymbols?.[i];
2706
- if (sym && sym !== "none" && sym !== "auto") {
2740
+ if (markerSymbols !== void 0 && sym !== "none") {
2707
2741
  const r = 4.5;
2708
- return seriesMarker(sym, swatchX + r, swatchY + r, r, color);
2742
+ return seriesMarker(autoMarkerSymbol(sym, i), swatchX + r, swatchY + r, r, color);
2709
2743
  }
2710
2744
  return `<rect x="${px(swatchX)}" y="${px(swatchY)}" width="9" height="9" fill="${color}"/>`;
2711
2745
  };
@@ -2768,24 +2802,7 @@ var renderColumnChart = (f, spec, colors) => {
2768
2802
  const grouping = spec.grouping ?? "clustered";
2769
2803
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
2770
2804
  const isPercent = grouping === "percentStacked";
2771
- let { min, max } = seriesMinMax(spec);
2772
- if (isStacked) {
2773
- let sumMin = Infinity;
2774
- let sumMax = -Infinity;
2775
- for (let c = 0; c < N; c++) {
2776
- let pos = 0;
2777
- let neg = 0;
2778
- for (const s of spec.series) {
2779
- const v = s.values[c] ?? 0;
2780
- if (v >= 0) pos += v;
2781
- else neg += v;
2782
- }
2783
- if (neg < sumMin) sumMin = neg;
2784
- if (pos > sumMax) sumMax = pos;
2785
- }
2786
- min = isPercent ? 0 : Math.min(0, sumMin);
2787
- max = isPercent ? 1 : Math.max(1, sumMax);
2788
- }
2805
+ const { min, max } = seriesMinMax(spec);
2789
2806
  const range = max - min || 1;
2790
2807
  const groupW = f.plotW / N;
2791
2808
  const gapPctC = (spec.gapWidthPct ?? 150) / 100;
@@ -2818,7 +2835,7 @@ var renderColumnChart = (f, spec, colors) => {
2818
2835
  const y1 = f.plotY + f.plotH - (Math.min(stackedTop, stackedBase) - min) / range * f.plotH;
2819
2836
  const h = Math.abs(y1 - y0);
2820
2837
  out.push(
2821
- `<rect x="${px(x0)}" y="${px(y0)}" width="${px(barW)}" height="${px(h)}" fill="${colors[s % colors.length]}"/>`
2838
+ `<rect x="${px(x0)}" y="${px(y0)}" width="${px(barW)}" height="${px(h)}" fill="${spec.series[s]?.color ?? colors[s % colors.length]}"/>`
2822
2839
  );
2823
2840
  if (showLabelFor(s) && Math.abs(v) > 0) {
2824
2841
  const labelY = (y0 + y1) / 2 + 3;
@@ -2992,6 +3009,17 @@ var smoothPath = (pts) => {
2992
3009
  }
2993
3010
  return parts.join(" ");
2994
3011
  };
3012
+ var AUTO_MARKER_SYMBOLS = [
3013
+ "diamond",
3014
+ "square",
3015
+ "triangle",
3016
+ "x",
3017
+ "star",
3018
+ "dot",
3019
+ "plus",
3020
+ "dash"
3021
+ ];
3022
+ var autoMarkerSymbol = (symbol, seriesIdx) => symbol !== void 0 && symbol !== "auto" ? symbol : AUTO_MARKER_SYMBOLS[seriesIdx % AUTO_MARKER_SYMBOLS.length];
2995
3023
  var seriesMarker = (symbol, cx, cy, r, color) => {
2996
3024
  switch (symbol) {
2997
3025
  case "square":
@@ -3053,24 +3081,7 @@ var renderBarChart = (f, spec, colors) => {
3053
3081
  const grouping = spec.grouping ?? "clustered";
3054
3082
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3055
3083
  const isPercent = grouping === "percentStacked";
3056
- let { min, max } = seriesMinMax(spec);
3057
- if (isStacked) {
3058
- let sumMin = Infinity;
3059
- let sumMax = -Infinity;
3060
- for (let c = 0; c < N; c++) {
3061
- let pos = 0;
3062
- let neg = 0;
3063
- for (const s of spec.series) {
3064
- const v = s.values[c] ?? 0;
3065
- if (v >= 0) pos += v;
3066
- else neg += v;
3067
- }
3068
- if (neg < sumMin) sumMin = neg;
3069
- if (pos > sumMax) sumMax = pos;
3070
- }
3071
- min = isPercent ? 0 : Math.min(0, sumMin);
3072
- max = isPercent ? 1 : Math.max(1, sumMax);
3073
- }
3084
+ const { min, max } = seriesMinMax(spec);
3074
3085
  const range = max - min || 1;
3075
3086
  const groupH = f.plotH / N;
3076
3087
  const gapPctB = (spec.gapWidthPct ?? 150) / 100;
@@ -3095,12 +3106,12 @@ var renderBarChart = (f, spec, colors) => {
3095
3106
  }
3096
3107
  const base = v >= 0 ? posAcc : negAcc;
3097
3108
  const stackedTop = base + v;
3098
- const y0 = f.plotY + c * groupH + (groupH - barH) / 2;
3109
+ const y0 = f.plotY + (N - 1 - c) * groupH + (groupH - barH) / 2;
3099
3110
  const x0 = f.plotX + (Math.min(base, stackedTop) - min) / range * f.plotW;
3100
3111
  const x1 = f.plotX + (Math.max(base, stackedTop) - min) / range * f.plotW;
3101
3112
  const w = Math.abs(x1 - x0);
3102
3113
  out.push(
3103
- `<rect x="${px(x0)}" y="${px(y0)}" width="${px(w)}" height="${px(barH)}" fill="${colors[s % colors.length]}"/>`
3114
+ `<rect x="${px(x0)}" y="${px(y0)}" width="${px(w)}" height="${px(barH)}" fill="${spec.series[s]?.color ?? colors[s % colors.length]}"/>`
3104
3115
  );
3105
3116
  if (showLabelForBar(s) && Math.abs(v) > 0) {
3106
3117
  const labelX = (x0 + x1) / 2;
@@ -3114,11 +3125,11 @@ var renderBarChart = (f, spec, colors) => {
3114
3125
  }
3115
3126
  } else {
3116
3127
  const clusterH = barH * clusterUnitsB;
3117
- const clusterStartY = f.plotY + c * groupH + (groupH - clusterH) / 2;
3128
+ const clusterStartY = f.plotY + (N - 1 - c) * groupH + (groupH - clusterH) / 2;
3118
3129
  const strideB = barH * (1 - overlapPctB);
3119
3130
  for (let s = 0; s < spec.series.length; s++) {
3120
3131
  const v = spec.series[s]?.values[c] ?? 0;
3121
- const y0 = clusterStartY + s * strideB;
3132
+ const y0 = clusterStartY + (Sb - 1 - s) * strideB;
3122
3133
  const tip = f.plotX + (v - min) / range * f.plotW;
3123
3134
  const x0 = Math.min(tip, baseX);
3124
3135
  const w = Math.abs(tip - baseX);
@@ -3166,24 +3177,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3166
3177
  const grouping = spec.grouping ?? "clustered";
3167
3178
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3168
3179
  const isPercent = grouping === "percentStacked";
3169
- let { min, max } = seriesMinMax(spec);
3170
- if (isStacked) {
3171
- let sumMin = Infinity;
3172
- let sumMax = -Infinity;
3173
- for (let c = 0; c < N; c++) {
3174
- let pos = 0;
3175
- let neg = 0;
3176
- for (const s of spec.series) {
3177
- const v = s.values[c] ?? 0;
3178
- if (v >= 0) pos += v;
3179
- else neg += v;
3180
- }
3181
- if (neg < sumMin) sumMin = neg;
3182
- if (pos > sumMax) sumMax = pos;
3183
- }
3184
- min = isPercent ? 0 : Math.min(0, sumMin);
3185
- max = isPercent ? 1 : Math.max(1, sumMax);
3186
- }
3180
+ const { min, max } = seriesMinMax(spec);
3187
3181
  const range = max - min || 1;
3188
3182
  const step = N > 1 ? f.plotW / (N - 1) : 0;
3189
3183
  const baseY = f.plotY + f.plotH - (0 - min) / range * f.plotH;
@@ -3244,7 +3238,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3244
3238
  })();
3245
3239
  if (fill) {
3246
3240
  const back = basePts.slice().reverse().map(([xp, yp]) => `L${px(xp)},${px(yp)}`).join(" ");
3247
- out.push(`<path d="${dPath} ${back} Z" fill="${color}" fill-opacity="0.55" stroke="none"/>`);
3241
+ out.push(`<path d="${dPath} ${back} Z" fill="${color}" stroke="none"/>`);
3248
3242
  }
3249
3243
  const lineWPx = series.lineWidthEmu ? Math.max(0.3, series.lineWidthEmu / EMU_PER_PX) : 1.5;
3250
3244
  const dashAttr = series.lineDash ? (() => {
@@ -3258,8 +3252,9 @@ var renderLineChart = (f, spec, colors, fill) => {
3258
3252
  `<path d="${dPath}" fill="none" stroke="${color}" stroke-width="${lineWPx.toFixed(2)}" stroke-linejoin="round" stroke-linecap="round"${dashAttr}/>`
3259
3253
  );
3260
3254
  if (!isStacked) {
3261
- const symbol = series.markerSymbol ?? "auto";
3262
- if (symbol !== "none") {
3255
+ const explicitSymbol = series.markerSymbol !== void 0 && series.markerSymbol !== "auto" && series.markerSymbol !== "none";
3256
+ if (series.markerSymbol !== "none" && !fill && (spec.lineMarkers === true || explicitSymbol)) {
3257
+ const symbol = autoMarkerSymbol(series.markerSymbol, s);
3263
3258
  const size = series.markerSizePt ?? 5;
3264
3259
  const r = Math.max(1, size * 0.5);
3265
3260
  for (const [xp, yp] of pts) {
@@ -3501,7 +3496,7 @@ var renderScatterChart = (f, spec, colors) => {
3501
3496
  const drawMarker = sym === "none" ? false : showMarker || sym !== void 0 && sym !== "auto";
3502
3497
  if (drawMarker) {
3503
3498
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3504
- const glyph = sym && sym !== "auto" && sym !== "none" ? sym : "circle";
3499
+ const glyph = autoMarkerSymbol(sym, s);
3505
3500
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3506
3501
  }
3507
3502
  }
@@ -3624,7 +3619,7 @@ var renderRadarChart = (f, spec, colors) => {
3624
3619
  );
3625
3620
  if (showMarker) {
3626
3621
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3627
- const glyph = series.markerSymbol && series.markerSymbol !== "auto" && series.markerSymbol !== "none" ? series.markerSymbol : "circle";
3622
+ const glyph = autoMarkerSymbol(series.markerSymbol, s);
3628
3623
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3629
3624
  }
3630
3625
  }
@@ -3660,7 +3655,9 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3660
3655
  const hiddenSet = new Set(spec.legend?.hiddenIndices ?? []);
3661
3656
  const seriesNamesForLegend = allNamesForLegend.filter((_, i) => !hiddenSet.has(i));
3662
3657
  const seriesColorsForLegend = allColorsForLegend.filter((_, i) => !hiddenSet.has(i));
3663
- const markerSymbolsForLegend = spec.kind === "line" || spec.kind === "area" ? spec.series.map((s) => s.markerSymbol).filter((_, i) => !hiddenSet.has(i)) : void 0;
3658
+ const explicitMarker = (sym) => sym !== void 0 && sym !== "auto" && sym !== "none";
3659
+ const showsMarkers = spec.kind === "line" && (spec.lineMarkers === true || spec.series.some((s) => explicitMarker(s.markerSymbol)));
3660
+ const markerSymbolsForLegend = showsMarkers ? spec.series.map((s) => s.markerSymbol).filter((_, i) => !hiddenSet.has(i)) : void 0;
3664
3661
  let finiteCount = 0;
3665
3662
  for (const s of spec.series) {
3666
3663
  for (const v of s.values) if (v !== null && Number.isFinite(v)) finiteCount++;
@@ -3683,7 +3680,8 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3683
3680
  ...spec.valueAxisLabelRotationDeg !== void 0 ? { labelRotationDeg: spec.valueAxisLabelRotationDeg } : {},
3684
3681
  ...spec.valueAxis?.displayUnits !== void 0 ? { displayUnits: spec.valueAxis.displayUnits } : {}
3685
3682
  };
3686
- const valueAxis = spec.kind === "bar" ? { orientation: "horizontal", min, max, ...axisExtras } : { orientation: "vertical", min, max, ...axisExtras };
3683
+ const isPercentStacked = spec.grouping === "percentStacked";
3684
+ const valueAxis = spec.kind === "bar" ? { orientation: "horizontal", min, max, percent: isPercentStacked, ...axisExtras } : { orientation: "vertical", min, max, percent: isPercentStacked, ...axisExtras };
3687
3685
  if (!spec.valueAxisHidden) axes = renderValueAxis(f, valueAxis);
3688
3686
  const labelsHidden = spec.categoryAxisHidden || spec.categoryAxisTickLabelPos === "none";
3689
3687
  if (N > 0 && !labelsHidden) {
@@ -3748,8 +3746,11 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3748
3746
  `<g${transform}>`,
3749
3747
  // Chart-area backdrop honors <c:chartSpace><c:spPr><a:solidFill> /
3750
3748
  // <a:ln>. plot-area gets its own tinted rect + border when
3751
- // <c:plotArea><c:spPr> authors them.
3752
- `<rect x="${px(f.x)}" y="${px(f.y)}" width="${px(f.w)}" height="${px(f.h)}" fill="${spec.chartAreaFill ?? "#FFFFFF"}" stroke="${spec.chartAreaStrokeColor ?? "#E5E7EB"}" stroke-width="0.6"${spec.roundedCorners ? ' rx="6" ry="6"' : ""}/>`,
3749
+ // <c:plotArea><c:spPr> authors them. PowerPoint draws no chart-area
3750
+ // border unless the chartSpace authors an <a:ln>, so the default is
3751
+ // `none` — an invented light-gray frame is the most visible single
3752
+ // divergence from PowerPoint's actual rendering.
3753
+ `<rect x="${px(f.x)}" y="${px(f.y)}" width="${px(f.w)}" height="${px(f.h)}" fill="${spec.chartAreaFill ?? "#FFFFFF"}" stroke="${spec.chartAreaStrokeColor ?? "none"}" stroke-width="0.6"${spec.roundedCorners ? ' rx="6" ry="6"' : ""}/>`,
3753
3754
  spec.plotAreaFill || spec.plotAreaStrokeColor ? `<rect x="${px(f.plotX)}" y="${px(f.plotY)}" width="${px(f.plotW)}" height="${px(f.plotH)}" fill="${spec.plotAreaFill ?? "none"}" stroke="${spec.plotAreaStrokeColor ?? "none"}" stroke-width="0.6"/>` : "",
3754
3755
  renderChartTitle(f, spec.title ?? "", spec.titleStyle),
3755
3756
  axes,
@@ -3879,7 +3880,7 @@ var renderTable = (shape, pres, x, y, w, h, transform, theme, ctx) => {
3879
3880
  const accent = theme ? normalizeHex(theme.accent1) : "#4472C4";
3880
3881
  const headerFill = accent;
3881
3882
  const bandFill = mixHex(accent, "#FFFFFF", 0.92);
3882
- const textColor = resolveColor("scheme:tx1", theme, "#000000");
3883
+ const textColor = activeDeckTextColor;
3883
3884
  const tableThemeFace = getPresentationFonts(pres)?.minorLatin ?? null;
3884
3885
  const out = [];
3885
3886
  out.push(`<g${transform}>`);
@@ -4459,6 +4460,7 @@ var renderSlideSvg = (pres, slide, opts = {}) => {
4459
4460
  const H = size.height;
4460
4461
  const theme = getPresentationTheme(pres);
4461
4462
  activeColorMap = getEffectiveColorMap(slide);
4463
+ activeDeckTextColor = resolveDeckBodyTextColor(slide) ?? "#000000";
4462
4464
  const ctx = {
4463
4465
  mode: opts.textLayout ?? "foreignObject",
4464
4466
  measure: opts.measureText ?? defaultMeasurer