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/node.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Resvg } from '@resvg/resvg-js';
2
- 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';
2
+ 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';
3
3
  import * as fontkit from 'fontkit';
4
4
  import { existsSync, readFileSync } from 'fs';
5
5
  import { fileURLToPath } from 'url';
@@ -564,6 +564,7 @@ var resolveColor = (c, theme, fallback = "#1F2937") => {
564
564
  var nextDefId = 0;
565
565
  var mintId = () => `pkdef-${(nextDefId++).toString(36)}`;
566
566
  var activeColorMap = null;
567
+ var activeDeckTextColor = "#000000";
567
568
  var gradientDef = (grad, theme) => {
568
569
  const id = mintId();
569
570
  const stops = grad.stops.map(
@@ -606,27 +607,23 @@ var patternDef = (pat) => {
606
607
  return `<path d="M0 0L${W} ${H}" stroke="${fg}" stroke-width="${width}"/>`;
607
608
  return `<path d="M${W} 0L0 ${H}" stroke="${fg}" stroke-width="${width}"/>`;
608
609
  };
609
- const dots = (density) => {
610
- const count = Math.max(1, Math.round(density * 4));
610
+ const BAYER4 = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
611
+ const screen = (density) => {
612
+ const threshold = density * 16;
611
613
  const out = [];
612
- const grid = count <= 1 ? [[4, 4]] : count === 2 ? [
613
- [2, 2],
614
- [6, 6]
615
- ] : [
616
- [2, 2],
617
- [6, 2],
618
- [2, 6],
619
- [6, 6]
620
- ];
621
- for (const [x, y] of grid.slice(0, count)) {
622
- out.push(`<circle cx="${x}" cy="${y}" r="0.7" fill="${fg}"/>`);
614
+ for (let i = 0; i < 16; i++) {
615
+ if (BAYER4[i] < threshold) {
616
+ const cx = i % 4 * 2;
617
+ const cy = Math.floor(i / 4) * 2;
618
+ out.push(`<rect x="${cx}" y="${cy}" width="2" height="2" fill="${fg}"/>`);
619
+ }
623
620
  }
624
621
  return out.join("");
625
622
  };
626
623
  const pctMatch = /^pct(\d+)$/.exec(preset);
627
624
  if (pctMatch) {
628
- const pct = Math.min(100, Math.max(5, Number.parseInt(pctMatch[1], 10)));
629
- body = dots(pct / 100);
625
+ const pct = Math.min(100, Math.max(0, Number.parseInt(pctMatch[1], 10)));
626
+ body = screen(pct / 100);
630
627
  } else if (preset === "horzBrick" || preset === "ltHorizontal" || preset === "narHorz") {
631
628
  body = stripe("h", 0.8);
632
629
  } else if (preset === "dkHorizontal") {
@@ -660,7 +657,7 @@ var patternDef = (pat) => {
660
657
  } else if (preset === "solidDmnd" || preset === "openDmnd") {
661
658
  body = `<path d="M4 1L7 4 4 7 1 4Z" fill="${preset === "solidDmnd" ? fg : "none"}" stroke="${fg}" stroke-width="0.6"/>`;
662
659
  } else {
663
- body = dots(0.5);
660
+ body = screen(0.5);
664
661
  }
665
662
  const defs = `<defs><pattern id="${id}" patternUnits="userSpaceOnUse" width="${W}" height="${H}"><rect width="${W}" height="${H}" fill="${bg}"/>${body}</pattern></defs>`;
666
663
  return { defs, fillAttr: `url(#${id})` };
@@ -2325,7 +2322,7 @@ var renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
2325
2322
  );
2326
2323
  }
2327
2324
  const justify = ANCHOR_TO_CSS[anchor] ?? "flex-start";
2328
- const defaultColor = resolveColor("scheme:tx1", theme, "#000000");
2325
+ const defaultColor = activeDeckTextColor;
2329
2326
  if (ctx.mode === "svg") {
2330
2327
  const svgScale = authoredAutofit?.fontScale ?? 1;
2331
2328
  const svgLineScale = 1 - (authoredAutofit?.lnSpcReduction ?? 0);
@@ -2519,6 +2516,9 @@ var DISPLAY_UNIT_LABEL = {
2519
2516
  billions: "Billions",
2520
2517
  trillions: "Trillions"
2521
2518
  };
2519
+ var DEFAULT_AXIS_COLOR = "#000000";
2520
+ var DEFAULT_GRID_COLOR = "#D9D9D9";
2521
+ var AXIS_TICK_LEN = 5;
2522
2522
  var axisTickAttrs = (style) => {
2523
2523
  const sz = style?.sizePt ?? 10;
2524
2524
  const fill = style?.color ?? "#6B7280";
@@ -2535,10 +2535,15 @@ var renderValueAxis = (f, axis) => {
2535
2535
  })() : niceTicks(axis.min, axis.max);
2536
2536
  const out = [];
2537
2537
  const range = axis.max - axis.min || 1;
2538
- const showGrid = axis.majorGridlines ?? true;
2539
- const gridStroke = axis.majorGridlineColor ?? "#E5E7EB";
2538
+ const fmtTick = (t) => axis.percent ? `${Math.round(t * 100)}%` : formatAxisLabel(
2539
+ axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2540
+ axis.numberFormat
2541
+ );
2542
+ const showGrid = axis.majorGridlines ?? false;
2543
+ const gridStroke = axis.majorGridlineColor ?? DEFAULT_GRID_COLOR;
2544
+ const axisColor = axis.lineColor ?? DEFAULT_AXIS_COLOR;
2540
2545
  const tickMark = axis.majorTickMark ?? "out";
2541
- const tickLen = 3;
2546
+ const tickLen = AXIS_TICK_LEN;
2542
2547
  for (const t of ticks) {
2543
2548
  if (axis.orientation === "vertical") {
2544
2549
  const yp = f.plotY + f.plotH - (t - axis.min) / range * f.plotH;
@@ -2551,19 +2556,14 @@ var renderValueAxis = (f, axis) => {
2551
2556
  const tx1 = tickMark === "in" ? f.plotX : f.plotX - tickLen;
2552
2557
  const tx2 = tickMark === "out" ? f.plotX : tickMark === "cross" ? f.plotX + tickLen : f.plotX + tickLen;
2553
2558
  out.push(
2554
- `<line x1="${px(tx1)}" y1="${px(yp)}" x2="${px(tx2)}" y2="${px(yp)}" stroke="#9CA3AF" stroke-width="0.5"/>`
2559
+ `<line x1="${px(tx1)}" y1="${px(yp)}" x2="${px(tx2)}" y2="${px(yp)}" stroke="${axisColor}" stroke-width="1"/>`
2555
2560
  );
2556
2561
  }
2557
2562
  const labelX = f.plotX - 4;
2558
2563
  const rot = axis.labelRotationDeg ?? 0;
2559
2564
  const transform = rot ? ` transform="rotate(${rot} ${px(labelX)} ${px(yp)})"` : "";
2560
2565
  out.push(
2561
- `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(
2562
- formatAxisLabel(
2563
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2564
- axis.numberFormat
2565
- )
2566
- )}</text>`
2566
+ `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(fmtTick(t))}</text>`
2567
2567
  );
2568
2568
  } else {
2569
2569
  const xp = f.plotX + (t - axis.min) / range * f.plotW;
@@ -2577,19 +2577,14 @@ var renderValueAxis = (f, axis) => {
2577
2577
  const ty1 = tickMark === "in" ? baseY : baseY + tickLen;
2578
2578
  const ty2 = tickMark === "out" ? baseY : tickMark === "cross" ? baseY - tickLen : baseY - tickLen;
2579
2579
  out.push(
2580
- `<line x1="${px(xp)}" y1="${px(ty1)}" x2="${px(xp)}" y2="${px(ty2)}" stroke="#9CA3AF" stroke-width="0.5"/>`
2580
+ `<line x1="${px(xp)}" y1="${px(ty1)}" x2="${px(xp)}" y2="${px(ty2)}" stroke="${axisColor}" stroke-width="1"/>`
2581
2581
  );
2582
2582
  }
2583
2583
  const horizLabelY = f.plotY + f.plotH + 12;
2584
2584
  const rotH = axis.labelRotationDeg ?? 0;
2585
2585
  const transformH = rotH ? ` transform="rotate(${rotH} ${px(xp)} ${px(horizLabelY)})"` : "";
2586
2586
  out.push(
2587
- `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(
2588
- formatAxisLabel(
2589
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2590
- axis.numberFormat
2591
- )
2592
- )}</text>`
2587
+ `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(fmtTick(t))}</text>`
2593
2588
  );
2594
2589
  }
2595
2590
  }
@@ -2607,16 +2602,16 @@ var renderValueAxis = (f, axis) => {
2607
2602
  );
2608
2603
  }
2609
2604
  }
2610
- if (axis.lineColor !== void 0) {
2611
- if (axis.orientation === "vertical") {
2612
- out.push(
2613
- `<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"/>`
2614
- );
2615
- } else {
2616
- out.push(
2617
- `<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"/>`
2618
- );
2619
- }
2605
+ if (axis.orientation === "vertical") {
2606
+ out.push(
2607
+ `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${axisColor}" stroke-width="1"/>`
2608
+ );
2609
+ } else {
2610
+ const zeroY = f.plotY + f.plotH - (0 - axis.min) / range * f.plotH;
2611
+ const spineY = axis.min <= 0 && axis.max >= 0 ? zeroY : f.plotY + f.plotH;
2612
+ out.push(
2613
+ `<line x1="${px(f.plotX)}" y1="${px(spineY)}" x2="${px(f.plotX + f.plotW)}" y2="${px(spineY)}" stroke="${axisColor}" stroke-width="1"/>`
2614
+ );
2620
2615
  }
2621
2616
  return out.join("");
2622
2617
  };
@@ -2645,7 +2640,7 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2645
2640
  const truncLen = labelRotationDeg && Math.abs(labelRotationDeg) >= 30 ? 28 : 14;
2646
2641
  for (let i = 0; i < pointCount2; i++) {
2647
2642
  if (skip > 1 && i % skip !== 0) continue;
2648
- const cy = f.plotY + (i + 0.5) * step;
2643
+ const cy = f.plotY + (pointCount2 - 1 - i + 0.5) * step;
2649
2644
  const lx = f.plotX - 4;
2650
2645
  const truncated = labels[i] !== void 0 && labels[i].length > truncLen ? `${labels[i].slice(0, truncLen - 2)}\u2026` : labels[i] ?? "";
2651
2646
  const transform = labelRotationDeg && labelRotationDeg !== 0 ? ` transform="rotate(${labelRotationDeg} ${px(lx)} ${px(cy)})"` : "";
@@ -2654,27 +2649,63 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2654
2649
  );
2655
2650
  }
2656
2651
  }
2657
- if (lineColor !== void 0) {
2658
- if (orientation === "horizontal") {
2652
+ const axisColor = lineColor ?? DEFAULT_AXIS_COLOR;
2653
+ if (orientation === "horizontal") {
2654
+ const baseY = f.plotY + f.plotH;
2655
+ out.push(
2656
+ `<line x1="${px(f.plotX)}" y1="${px(baseY)}" x2="${px(f.plotX + f.plotW)}" y2="${px(baseY)}" stroke="${axisColor}" stroke-width="1"/>`
2657
+ );
2658
+ const stepB = pointCount2 > 0 ? f.plotW / pointCount2 : 0;
2659
+ for (let i = 0; i <= pointCount2; i++) {
2660
+ const bx = f.plotX + i * stepB;
2659
2661
  out.push(
2660
- `<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"/>`
2662
+ `<line x1="${px(bx)}" y1="${px(baseY)}" x2="${px(bx)}" y2="${px(baseY + AXIS_TICK_LEN)}" stroke="${axisColor}" stroke-width="1"/>`
2661
2663
  );
2662
- } else {
2664
+ }
2665
+ } else {
2666
+ out.push(
2667
+ `<line x1="${px(f.plotX)}" y1="${px(f.plotY)}" x2="${px(f.plotX)}" y2="${px(f.plotY + f.plotH)}" stroke="${axisColor}" stroke-width="1"/>`
2668
+ );
2669
+ const stepB = pointCount2 > 0 ? f.plotH / pointCount2 : 0;
2670
+ for (let i = 0; i <= pointCount2; i++) {
2671
+ const by = f.plotY + i * stepB;
2663
2672
  out.push(
2664
- `<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"/>`
2673
+ `<line x1="${px(f.plotX - AXIS_TICK_LEN)}" y1="${px(by)}" x2="${px(f.plotX)}" y2="${px(by)}" stroke="${axisColor}" stroke-width="1"/>`
2665
2674
  );
2666
2675
  }
2667
2676
  }
2668
2677
  return out.join("");
2669
2678
  };
2670
2679
  var seriesMinMax = (spec) => {
2680
+ const isStacked = spec.grouping === "stacked" || spec.grouping === "percentStacked";
2681
+ const isPercent = spec.grouping === "percentStacked";
2671
2682
  let min = Infinity;
2672
2683
  let max = -Infinity;
2673
- for (const s of spec.series) {
2674
- for (const v of s.values) {
2675
- if (v !== null && Number.isFinite(v)) {
2676
- if (v < min) min = v;
2677
- if (v > max) max = v;
2684
+ if (isPercent) {
2685
+ min = 0;
2686
+ max = 1;
2687
+ } else if (isStacked) {
2688
+ const N = spec.series.reduce((n, s) => Math.max(n, s.values.length), 0);
2689
+ for (let c = 0; c < N; c++) {
2690
+ let pos = 0;
2691
+ let neg = 0;
2692
+ for (const s of spec.series) {
2693
+ const v = s.values[c];
2694
+ if (v !== null && v !== void 0 && Number.isFinite(v)) {
2695
+ if (v >= 0) pos += v;
2696
+ else neg += v;
2697
+ }
2698
+ }
2699
+ if (pos > max) max = pos;
2700
+ if (neg < min) min = neg;
2701
+ }
2702
+ } else {
2703
+ for (const s of spec.series) {
2704
+ for (const v of s.values) {
2705
+ if (v !== null && Number.isFinite(v)) {
2706
+ if (v < min) min = v;
2707
+ if (v > max) max = v;
2708
+ }
2678
2709
  }
2679
2710
  }
2680
2711
  }
@@ -2682,6 +2713,9 @@ var seriesMinMax = (spec) => {
2682
2713
  if (!Number.isFinite(max)) max = 1;
2683
2714
  if (max === min) max = min + 1;
2684
2715
  if (min > 0) min = 0;
2716
+ if (isPercent) {
2717
+ return { min: 0, max: 1, step: 0.2 };
2718
+ }
2685
2719
  const step = niceStep(max - min);
2686
2720
  max = (Math.floor(max / step) + 1) * step;
2687
2721
  if (spec.valueAxis?.min !== void 0) min = spec.valueAxis.min;
@@ -2707,9 +2741,9 @@ var renderChartLegend = (f, names, colors, position = "b", textStyle, markerSymb
2707
2741
  const swatch = (i, swatchX, swatchY) => {
2708
2742
  const color = colors[i % colors.length];
2709
2743
  const sym = markerSymbols?.[i];
2710
- if (sym && sym !== "none" && sym !== "auto") {
2744
+ if (markerSymbols !== void 0 && sym !== "none") {
2711
2745
  const r = 4.5;
2712
- return seriesMarker(sym, swatchX + r, swatchY + r, r, color);
2746
+ return seriesMarker(autoMarkerSymbol(sym, i), swatchX + r, swatchY + r, r, color);
2713
2747
  }
2714
2748
  return `<rect x="${px(swatchX)}" y="${px(swatchY)}" width="9" height="9" fill="${color}"/>`;
2715
2749
  };
@@ -2772,24 +2806,7 @@ var renderColumnChart = (f, spec, colors) => {
2772
2806
  const grouping = spec.grouping ?? "clustered";
2773
2807
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
2774
2808
  const isPercent = grouping === "percentStacked";
2775
- let { min, max } = seriesMinMax(spec);
2776
- if (isStacked) {
2777
- let sumMin = Infinity;
2778
- let sumMax = -Infinity;
2779
- for (let c = 0; c < N; c++) {
2780
- let pos = 0;
2781
- let neg = 0;
2782
- for (const s of spec.series) {
2783
- const v = s.values[c] ?? 0;
2784
- if (v >= 0) pos += v;
2785
- else neg += v;
2786
- }
2787
- if (neg < sumMin) sumMin = neg;
2788
- if (pos > sumMax) sumMax = pos;
2789
- }
2790
- min = isPercent ? 0 : Math.min(0, sumMin);
2791
- max = isPercent ? 1 : Math.max(1, sumMax);
2792
- }
2809
+ const { min, max } = seriesMinMax(spec);
2793
2810
  const range = max - min || 1;
2794
2811
  const groupW = f.plotW / N;
2795
2812
  const gapPctC = (spec.gapWidthPct ?? 150) / 100;
@@ -2822,7 +2839,7 @@ var renderColumnChart = (f, spec, colors) => {
2822
2839
  const y1 = f.plotY + f.plotH - (Math.min(stackedTop, stackedBase) - min) / range * f.plotH;
2823
2840
  const h = Math.abs(y1 - y0);
2824
2841
  out.push(
2825
- `<rect x="${px(x0)}" y="${px(y0)}" width="${px(barW)}" height="${px(h)}" fill="${colors[s % colors.length]}"/>`
2842
+ `<rect x="${px(x0)}" y="${px(y0)}" width="${px(barW)}" height="${px(h)}" fill="${spec.series[s]?.color ?? colors[s % colors.length]}"/>`
2826
2843
  );
2827
2844
  if (showLabelFor(s) && Math.abs(v) > 0) {
2828
2845
  const labelY = (y0 + y1) / 2 + 3;
@@ -2996,6 +3013,17 @@ var smoothPath = (pts) => {
2996
3013
  }
2997
3014
  return parts.join(" ");
2998
3015
  };
3016
+ var AUTO_MARKER_SYMBOLS = [
3017
+ "diamond",
3018
+ "square",
3019
+ "triangle",
3020
+ "x",
3021
+ "star",
3022
+ "dot",
3023
+ "plus",
3024
+ "dash"
3025
+ ];
3026
+ var autoMarkerSymbol = (symbol, seriesIdx) => symbol !== void 0 && symbol !== "auto" ? symbol : AUTO_MARKER_SYMBOLS[seriesIdx % AUTO_MARKER_SYMBOLS.length];
2999
3027
  var seriesMarker = (symbol, cx, cy, r, color) => {
3000
3028
  switch (symbol) {
3001
3029
  case "square":
@@ -3057,24 +3085,7 @@ var renderBarChart = (f, spec, colors) => {
3057
3085
  const grouping = spec.grouping ?? "clustered";
3058
3086
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3059
3087
  const isPercent = grouping === "percentStacked";
3060
- let { min, max } = seriesMinMax(spec);
3061
- if (isStacked) {
3062
- let sumMin = Infinity;
3063
- let sumMax = -Infinity;
3064
- for (let c = 0; c < N; c++) {
3065
- let pos = 0;
3066
- let neg = 0;
3067
- for (const s of spec.series) {
3068
- const v = s.values[c] ?? 0;
3069
- if (v >= 0) pos += v;
3070
- else neg += v;
3071
- }
3072
- if (neg < sumMin) sumMin = neg;
3073
- if (pos > sumMax) sumMax = pos;
3074
- }
3075
- min = isPercent ? 0 : Math.min(0, sumMin);
3076
- max = isPercent ? 1 : Math.max(1, sumMax);
3077
- }
3088
+ const { min, max } = seriesMinMax(spec);
3078
3089
  const range = max - min || 1;
3079
3090
  const groupH = f.plotH / N;
3080
3091
  const gapPctB = (spec.gapWidthPct ?? 150) / 100;
@@ -3099,12 +3110,12 @@ var renderBarChart = (f, spec, colors) => {
3099
3110
  }
3100
3111
  const base = v >= 0 ? posAcc : negAcc;
3101
3112
  const stackedTop = base + v;
3102
- const y0 = f.plotY + c * groupH + (groupH - barH) / 2;
3113
+ const y0 = f.plotY + (N - 1 - c) * groupH + (groupH - barH) / 2;
3103
3114
  const x0 = f.plotX + (Math.min(base, stackedTop) - min) / range * f.plotW;
3104
3115
  const x1 = f.plotX + (Math.max(base, stackedTop) - min) / range * f.plotW;
3105
3116
  const w = Math.abs(x1 - x0);
3106
3117
  out.push(
3107
- `<rect x="${px(x0)}" y="${px(y0)}" width="${px(w)}" height="${px(barH)}" fill="${colors[s % colors.length]}"/>`
3118
+ `<rect x="${px(x0)}" y="${px(y0)}" width="${px(w)}" height="${px(barH)}" fill="${spec.series[s]?.color ?? colors[s % colors.length]}"/>`
3108
3119
  );
3109
3120
  if (showLabelForBar(s) && Math.abs(v) > 0) {
3110
3121
  const labelX = (x0 + x1) / 2;
@@ -3118,11 +3129,11 @@ var renderBarChart = (f, spec, colors) => {
3118
3129
  }
3119
3130
  } else {
3120
3131
  const clusterH = barH * clusterUnitsB;
3121
- const clusterStartY = f.plotY + c * groupH + (groupH - clusterH) / 2;
3132
+ const clusterStartY = f.plotY + (N - 1 - c) * groupH + (groupH - clusterH) / 2;
3122
3133
  const strideB = barH * (1 - overlapPctB);
3123
3134
  for (let s = 0; s < spec.series.length; s++) {
3124
3135
  const v = spec.series[s]?.values[c] ?? 0;
3125
- const y0 = clusterStartY + s * strideB;
3136
+ const y0 = clusterStartY + (Sb - 1 - s) * strideB;
3126
3137
  const tip = f.plotX + (v - min) / range * f.plotW;
3127
3138
  const x0 = Math.min(tip, baseX);
3128
3139
  const w = Math.abs(tip - baseX);
@@ -3170,24 +3181,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3170
3181
  const grouping = spec.grouping ?? "clustered";
3171
3182
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3172
3183
  const isPercent = grouping === "percentStacked";
3173
- let { min, max } = seriesMinMax(spec);
3174
- if (isStacked) {
3175
- let sumMin = Infinity;
3176
- let sumMax = -Infinity;
3177
- for (let c = 0; c < N; c++) {
3178
- let pos = 0;
3179
- let neg = 0;
3180
- for (const s of spec.series) {
3181
- const v = s.values[c] ?? 0;
3182
- if (v >= 0) pos += v;
3183
- else neg += v;
3184
- }
3185
- if (neg < sumMin) sumMin = neg;
3186
- if (pos > sumMax) sumMax = pos;
3187
- }
3188
- min = isPercent ? 0 : Math.min(0, sumMin);
3189
- max = isPercent ? 1 : Math.max(1, sumMax);
3190
- }
3184
+ const { min, max } = seriesMinMax(spec);
3191
3185
  const range = max - min || 1;
3192
3186
  const step = N > 1 ? f.plotW / (N - 1) : 0;
3193
3187
  const baseY = f.plotY + f.plotH - (0 - min) / range * f.plotH;
@@ -3248,7 +3242,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3248
3242
  })();
3249
3243
  if (fill) {
3250
3244
  const back = basePts.slice().reverse().map(([xp, yp]) => `L${px(xp)},${px(yp)}`).join(" ");
3251
- out.push(`<path d="${dPath} ${back} Z" fill="${color}" fill-opacity="0.55" stroke="none"/>`);
3245
+ out.push(`<path d="${dPath} ${back} Z" fill="${color}" stroke="none"/>`);
3252
3246
  }
3253
3247
  const lineWPx = series.lineWidthEmu ? Math.max(0.3, series.lineWidthEmu / EMU_PER_PX) : 1.5;
3254
3248
  const dashAttr = series.lineDash ? (() => {
@@ -3262,8 +3256,9 @@ var renderLineChart = (f, spec, colors, fill) => {
3262
3256
  `<path d="${dPath}" fill="none" stroke="${color}" stroke-width="${lineWPx.toFixed(2)}" stroke-linejoin="round" stroke-linecap="round"${dashAttr}/>`
3263
3257
  );
3264
3258
  if (!isStacked) {
3265
- const symbol = series.markerSymbol ?? "auto";
3266
- if (symbol !== "none") {
3259
+ const explicitSymbol = series.markerSymbol !== void 0 && series.markerSymbol !== "auto" && series.markerSymbol !== "none";
3260
+ if (series.markerSymbol !== "none" && !fill && (spec.lineMarkers === true || explicitSymbol)) {
3261
+ const symbol = autoMarkerSymbol(series.markerSymbol, s);
3267
3262
  const size = series.markerSizePt ?? 5;
3268
3263
  const r = Math.max(1, size * 0.5);
3269
3264
  for (const [xp, yp] of pts) {
@@ -3505,7 +3500,7 @@ var renderScatterChart = (f, spec, colors) => {
3505
3500
  const drawMarker = sym === "none" ? false : showMarker || sym !== void 0 && sym !== "auto";
3506
3501
  if (drawMarker) {
3507
3502
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3508
- const glyph = sym && sym !== "auto" && sym !== "none" ? sym : "circle";
3503
+ const glyph = autoMarkerSymbol(sym, s);
3509
3504
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3510
3505
  }
3511
3506
  }
@@ -3628,7 +3623,7 @@ var renderRadarChart = (f, spec, colors) => {
3628
3623
  );
3629
3624
  if (showMarker) {
3630
3625
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3631
- const glyph = series.markerSymbol && series.markerSymbol !== "auto" && series.markerSymbol !== "none" ? series.markerSymbol : "circle";
3626
+ const glyph = autoMarkerSymbol(series.markerSymbol, s);
3632
3627
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3633
3628
  }
3634
3629
  }
@@ -3664,7 +3659,9 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3664
3659
  const hiddenSet = new Set(spec.legend?.hiddenIndices ?? []);
3665
3660
  const seriesNamesForLegend = allNamesForLegend.filter((_, i) => !hiddenSet.has(i));
3666
3661
  const seriesColorsForLegend = allColorsForLegend.filter((_, i) => !hiddenSet.has(i));
3667
- const markerSymbolsForLegend = spec.kind === "line" || spec.kind === "area" ? spec.series.map((s) => s.markerSymbol).filter((_, i) => !hiddenSet.has(i)) : void 0;
3662
+ const explicitMarker = (sym) => sym !== void 0 && sym !== "auto" && sym !== "none";
3663
+ const showsMarkers = spec.kind === "line" && (spec.lineMarkers === true || spec.series.some((s) => explicitMarker(s.markerSymbol)));
3664
+ const markerSymbolsForLegend = showsMarkers ? spec.series.map((s) => s.markerSymbol).filter((_, i) => !hiddenSet.has(i)) : void 0;
3668
3665
  let finiteCount = 0;
3669
3666
  for (const s of spec.series) {
3670
3667
  for (const v of s.values) if (v !== null && Number.isFinite(v)) finiteCount++;
@@ -3687,7 +3684,8 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3687
3684
  ...spec.valueAxisLabelRotationDeg !== void 0 ? { labelRotationDeg: spec.valueAxisLabelRotationDeg } : {},
3688
3685
  ...spec.valueAxis?.displayUnits !== void 0 ? { displayUnits: spec.valueAxis.displayUnits } : {}
3689
3686
  };
3690
- const valueAxis = spec.kind === "bar" ? { orientation: "horizontal", min, max, ...axisExtras } : { orientation: "vertical", min, max, ...axisExtras };
3687
+ const isPercentStacked = spec.grouping === "percentStacked";
3688
+ const valueAxis = spec.kind === "bar" ? { orientation: "horizontal", min, max, percent: isPercentStacked, ...axisExtras } : { orientation: "vertical", min, max, percent: isPercentStacked, ...axisExtras };
3691
3689
  if (!spec.valueAxisHidden) axes = renderValueAxis(f, valueAxis);
3692
3690
  const labelsHidden = spec.categoryAxisHidden || spec.categoryAxisTickLabelPos === "none";
3693
3691
  if (N > 0 && !labelsHidden) {
@@ -3752,8 +3750,11 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3752
3750
  `<g${transform}>`,
3753
3751
  // Chart-area backdrop honors <c:chartSpace><c:spPr><a:solidFill> /
3754
3752
  // <a:ln>. plot-area gets its own tinted rect + border when
3755
- // <c:plotArea><c:spPr> authors them.
3756
- `<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"' : ""}/>`,
3753
+ // <c:plotArea><c:spPr> authors them. PowerPoint draws no chart-area
3754
+ // border unless the chartSpace authors an <a:ln>, so the default is
3755
+ // `none` — an invented light-gray frame is the most visible single
3756
+ // divergence from PowerPoint's actual rendering.
3757
+ `<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"' : ""}/>`,
3757
3758
  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"/>` : "",
3758
3759
  renderChartTitle(f, spec.title ?? "", spec.titleStyle),
3759
3760
  axes,
@@ -3883,7 +3884,7 @@ var renderTable = (shape, pres, x, y, w, h, transform, theme, ctx) => {
3883
3884
  const accent = theme ? normalizeHex(theme.accent1) : "#4472C4";
3884
3885
  const headerFill = accent;
3885
3886
  const bandFill = mixHex(accent, "#FFFFFF", 0.92);
3886
- const textColor = resolveColor("scheme:tx1", theme, "#000000");
3887
+ const textColor = activeDeckTextColor;
3887
3888
  const tableThemeFace = getPresentationFonts(pres)?.minorLatin ?? null;
3888
3889
  const out = [];
3889
3890
  out.push(`<g${transform}>`);
@@ -4463,6 +4464,7 @@ var renderSlideSvg = (pres, slide, opts = {}) => {
4463
4464
  const H = size.height;
4464
4465
  const theme = getPresentationTheme(pres);
4465
4466
  activeColorMap = getEffectiveColorMap(slide);
4467
+ activeDeckTextColor = resolveDeckBodyTextColor(slide) ?? "#000000";
4466
4468
  const ctx = {
4467
4469
  mode: opts.textLayout ?? "foreignObject",
4468
4470
  measure: opts.measureText ?? defaultMeasurer