pptx-kit-preview 0.3.1 → 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
@@ -607,27 +607,23 @@ var patternDef = (pat) => {
607
607
  return `<path d="M0 0L${W} ${H}" stroke="${fg}" stroke-width="${width}"/>`;
608
608
  return `<path d="M${W} 0L0 ${H}" stroke="${fg}" stroke-width="${width}"/>`;
609
609
  };
610
- const dots = (density) => {
611
- 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;
612
613
  const out = [];
613
- const grid = count <= 1 ? [[4, 4]] : count === 2 ? [
614
- [2, 2],
615
- [6, 6]
616
- ] : [
617
- [2, 2],
618
- [6, 2],
619
- [2, 6],
620
- [6, 6]
621
- ];
622
- for (const [x, y] of grid.slice(0, count)) {
623
- 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
+ }
624
620
  }
625
621
  return out.join("");
626
622
  };
627
623
  const pctMatch = /^pct(\d+)$/.exec(preset);
628
624
  if (pctMatch) {
629
- const pct = Math.min(100, Math.max(5, Number.parseInt(pctMatch[1], 10)));
630
- body = dots(pct / 100);
625
+ const pct = Math.min(100, Math.max(0, Number.parseInt(pctMatch[1], 10)));
626
+ body = screen(pct / 100);
631
627
  } else if (preset === "horzBrick" || preset === "ltHorizontal" || preset === "narHorz") {
632
628
  body = stripe("h", 0.8);
633
629
  } else if (preset === "dkHorizontal") {
@@ -661,7 +657,7 @@ var patternDef = (pat) => {
661
657
  } else if (preset === "solidDmnd" || preset === "openDmnd") {
662
658
  body = `<path d="M4 1L7 4 4 7 1 4Z" fill="${preset === "solidDmnd" ? fg : "none"}" stroke="${fg}" stroke-width="0.6"/>`;
663
659
  } else {
664
- body = dots(0.5);
660
+ body = screen(0.5);
665
661
  }
666
662
  const defs = `<defs><pattern id="${id}" patternUnits="userSpaceOnUse" width="${W}" height="${H}"><rect width="${W}" height="${H}" fill="${bg}"/>${body}</pattern></defs>`;
667
663
  return { defs, fillAttr: `url(#${id})` };
@@ -2520,6 +2516,9 @@ var DISPLAY_UNIT_LABEL = {
2520
2516
  billions: "Billions",
2521
2517
  trillions: "Trillions"
2522
2518
  };
2519
+ var DEFAULT_AXIS_COLOR = "#000000";
2520
+ var DEFAULT_GRID_COLOR = "#D9D9D9";
2521
+ var AXIS_TICK_LEN = 5;
2523
2522
  var axisTickAttrs = (style) => {
2524
2523
  const sz = style?.sizePt ?? 10;
2525
2524
  const fill = style?.color ?? "#6B7280";
@@ -2536,10 +2535,15 @@ var renderValueAxis = (f, axis) => {
2536
2535
  })() : niceTicks(axis.min, axis.max);
2537
2536
  const out = [];
2538
2537
  const range = axis.max - axis.min || 1;
2539
- const showGrid = axis.majorGridlines ?? true;
2540
- 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;
2541
2545
  const tickMark = axis.majorTickMark ?? "out";
2542
- const tickLen = 3;
2546
+ const tickLen = AXIS_TICK_LEN;
2543
2547
  for (const t of ticks) {
2544
2548
  if (axis.orientation === "vertical") {
2545
2549
  const yp = f.plotY + f.plotH - (t - axis.min) / range * f.plotH;
@@ -2552,19 +2556,14 @@ var renderValueAxis = (f, axis) => {
2552
2556
  const tx1 = tickMark === "in" ? f.plotX : f.plotX - tickLen;
2553
2557
  const tx2 = tickMark === "out" ? f.plotX : tickMark === "cross" ? f.plotX + tickLen : f.plotX + tickLen;
2554
2558
  out.push(
2555
- `<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"/>`
2556
2560
  );
2557
2561
  }
2558
2562
  const labelX = f.plotX - 4;
2559
2563
  const rot = axis.labelRotationDeg ?? 0;
2560
2564
  const transform = rot ? ` transform="rotate(${rot} ${px(labelX)} ${px(yp)})"` : "";
2561
2565
  out.push(
2562
- `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(
2563
- formatAxisLabel(
2564
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2565
- axis.numberFormat
2566
- )
2567
- )}</text>`
2566
+ `<text x="${px(labelX)}" y="${px(yp)}" text-anchor="end" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transform}>${escapeXml2(fmtTick(t))}</text>`
2568
2567
  );
2569
2568
  } else {
2570
2569
  const xp = f.plotX + (t - axis.min) / range * f.plotW;
@@ -2578,19 +2577,14 @@ var renderValueAxis = (f, axis) => {
2578
2577
  const ty1 = tickMark === "in" ? baseY : baseY + tickLen;
2579
2578
  const ty2 = tickMark === "out" ? baseY : tickMark === "cross" ? baseY - tickLen : baseY - tickLen;
2580
2579
  out.push(
2581
- `<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"/>`
2582
2581
  );
2583
2582
  }
2584
2583
  const horizLabelY = f.plotY + f.plotH + 12;
2585
2584
  const rotH = axis.labelRotationDeg ?? 0;
2586
2585
  const transformH = rotH ? ` transform="rotate(${rotH} ${px(xp)} ${px(horizLabelY)})"` : "";
2587
2586
  out.push(
2588
- `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(
2589
- formatAxisLabel(
2590
- axis.displayUnits ? t / DISPLAY_UNIT_DIVISOR[axis.displayUnits] : t,
2591
- axis.numberFormat
2592
- )
2593
- )}</text>`
2587
+ `<text x="${px(xp)}" y="${px(horizLabelY)}" text-anchor="middle" dominant-baseline="middle" ${axisTickAttrs(axis.labelStyle)}${transformH}>${escapeXml2(fmtTick(t))}</text>`
2594
2588
  );
2595
2589
  }
2596
2590
  }
@@ -2608,16 +2602,16 @@ var renderValueAxis = (f, axis) => {
2608
2602
  );
2609
2603
  }
2610
2604
  }
2611
- if (axis.lineColor !== void 0) {
2612
- if (axis.orientation === "vertical") {
2613
- out.push(
2614
- `<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"/>`
2615
- );
2616
- } else {
2617
- out.push(
2618
- `<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"/>`
2619
- );
2620
- }
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
+ );
2621
2615
  }
2622
2616
  return out.join("");
2623
2617
  };
@@ -2646,7 +2640,7 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2646
2640
  const truncLen = labelRotationDeg && Math.abs(labelRotationDeg) >= 30 ? 28 : 14;
2647
2641
  for (let i = 0; i < pointCount2; i++) {
2648
2642
  if (skip > 1 && i % skip !== 0) continue;
2649
- const cy = f.plotY + (i + 0.5) * step;
2643
+ const cy = f.plotY + (pointCount2 - 1 - i + 0.5) * step;
2650
2644
  const lx = f.plotX - 4;
2651
2645
  const truncated = labels[i] !== void 0 && labels[i].length > truncLen ? `${labels[i].slice(0, truncLen - 2)}\u2026` : labels[i] ?? "";
2652
2646
  const transform = labelRotationDeg && labelRotationDeg !== 0 ? ` transform="rotate(${labelRotationDeg} ${px(lx)} ${px(cy)})"` : "";
@@ -2655,27 +2649,63 @@ var renderCategoryAxis = (f, orientation, cats, pointCount2, skip = 1, labelStyl
2655
2649
  );
2656
2650
  }
2657
2651
  }
2658
- if (lineColor !== void 0) {
2659
- 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;
2660
2661
  out.push(
2661
- `<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"/>`
2662
2663
  );
2663
- } 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;
2664
2672
  out.push(
2665
- `<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"/>`
2666
2674
  );
2667
2675
  }
2668
2676
  }
2669
2677
  return out.join("");
2670
2678
  };
2671
2679
  var seriesMinMax = (spec) => {
2680
+ const isStacked = spec.grouping === "stacked" || spec.grouping === "percentStacked";
2681
+ const isPercent = spec.grouping === "percentStacked";
2672
2682
  let min = Infinity;
2673
2683
  let max = -Infinity;
2674
- for (const s of spec.series) {
2675
- for (const v of s.values) {
2676
- if (v !== null && Number.isFinite(v)) {
2677
- if (v < min) min = v;
2678
- 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
+ }
2679
2709
  }
2680
2710
  }
2681
2711
  }
@@ -2683,6 +2713,9 @@ var seriesMinMax = (spec) => {
2683
2713
  if (!Number.isFinite(max)) max = 1;
2684
2714
  if (max === min) max = min + 1;
2685
2715
  if (min > 0) min = 0;
2716
+ if (isPercent) {
2717
+ return { min: 0, max: 1, step: 0.2 };
2718
+ }
2686
2719
  const step = niceStep(max - min);
2687
2720
  max = (Math.floor(max / step) + 1) * step;
2688
2721
  if (spec.valueAxis?.min !== void 0) min = spec.valueAxis.min;
@@ -2708,9 +2741,9 @@ var renderChartLegend = (f, names, colors, position = "b", textStyle, markerSymb
2708
2741
  const swatch = (i, swatchX, swatchY) => {
2709
2742
  const color = colors[i % colors.length];
2710
2743
  const sym = markerSymbols?.[i];
2711
- if (sym && sym !== "none" && sym !== "auto") {
2744
+ if (markerSymbols !== void 0 && sym !== "none") {
2712
2745
  const r = 4.5;
2713
- return seriesMarker(sym, swatchX + r, swatchY + r, r, color);
2746
+ return seriesMarker(autoMarkerSymbol(sym, i), swatchX + r, swatchY + r, r, color);
2714
2747
  }
2715
2748
  return `<rect x="${px(swatchX)}" y="${px(swatchY)}" width="9" height="9" fill="${color}"/>`;
2716
2749
  };
@@ -2773,24 +2806,7 @@ var renderColumnChart = (f, spec, colors) => {
2773
2806
  const grouping = spec.grouping ?? "clustered";
2774
2807
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
2775
2808
  const isPercent = grouping === "percentStacked";
2776
- let { min, max } = seriesMinMax(spec);
2777
- if (isStacked) {
2778
- let sumMin = Infinity;
2779
- let sumMax = -Infinity;
2780
- for (let c = 0; c < N; c++) {
2781
- let pos = 0;
2782
- let neg = 0;
2783
- for (const s of spec.series) {
2784
- const v = s.values[c] ?? 0;
2785
- if (v >= 0) pos += v;
2786
- else neg += v;
2787
- }
2788
- if (neg < sumMin) sumMin = neg;
2789
- if (pos > sumMax) sumMax = pos;
2790
- }
2791
- min = isPercent ? 0 : Math.min(0, sumMin);
2792
- max = isPercent ? 1 : Math.max(1, sumMax);
2793
- }
2809
+ const { min, max } = seriesMinMax(spec);
2794
2810
  const range = max - min || 1;
2795
2811
  const groupW = f.plotW / N;
2796
2812
  const gapPctC = (spec.gapWidthPct ?? 150) / 100;
@@ -2823,7 +2839,7 @@ var renderColumnChart = (f, spec, colors) => {
2823
2839
  const y1 = f.plotY + f.plotH - (Math.min(stackedTop, stackedBase) - min) / range * f.plotH;
2824
2840
  const h = Math.abs(y1 - y0);
2825
2841
  out.push(
2826
- `<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]}"/>`
2827
2843
  );
2828
2844
  if (showLabelFor(s) && Math.abs(v) > 0) {
2829
2845
  const labelY = (y0 + y1) / 2 + 3;
@@ -2997,6 +3013,17 @@ var smoothPath = (pts) => {
2997
3013
  }
2998
3014
  return parts.join(" ");
2999
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];
3000
3027
  var seriesMarker = (symbol, cx, cy, r, color) => {
3001
3028
  switch (symbol) {
3002
3029
  case "square":
@@ -3058,24 +3085,7 @@ var renderBarChart = (f, spec, colors) => {
3058
3085
  const grouping = spec.grouping ?? "clustered";
3059
3086
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3060
3087
  const isPercent = grouping === "percentStacked";
3061
- let { min, max } = seriesMinMax(spec);
3062
- if (isStacked) {
3063
- let sumMin = Infinity;
3064
- let sumMax = -Infinity;
3065
- for (let c = 0; c < N; c++) {
3066
- let pos = 0;
3067
- let neg = 0;
3068
- for (const s of spec.series) {
3069
- const v = s.values[c] ?? 0;
3070
- if (v >= 0) pos += v;
3071
- else neg += v;
3072
- }
3073
- if (neg < sumMin) sumMin = neg;
3074
- if (pos > sumMax) sumMax = pos;
3075
- }
3076
- min = isPercent ? 0 : Math.min(0, sumMin);
3077
- max = isPercent ? 1 : Math.max(1, sumMax);
3078
- }
3088
+ const { min, max } = seriesMinMax(spec);
3079
3089
  const range = max - min || 1;
3080
3090
  const groupH = f.plotH / N;
3081
3091
  const gapPctB = (spec.gapWidthPct ?? 150) / 100;
@@ -3100,12 +3110,12 @@ var renderBarChart = (f, spec, colors) => {
3100
3110
  }
3101
3111
  const base = v >= 0 ? posAcc : negAcc;
3102
3112
  const stackedTop = base + v;
3103
- const y0 = f.plotY + c * groupH + (groupH - barH) / 2;
3113
+ const y0 = f.plotY + (N - 1 - c) * groupH + (groupH - barH) / 2;
3104
3114
  const x0 = f.plotX + (Math.min(base, stackedTop) - min) / range * f.plotW;
3105
3115
  const x1 = f.plotX + (Math.max(base, stackedTop) - min) / range * f.plotW;
3106
3116
  const w = Math.abs(x1 - x0);
3107
3117
  out.push(
3108
- `<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]}"/>`
3109
3119
  );
3110
3120
  if (showLabelForBar(s) && Math.abs(v) > 0) {
3111
3121
  const labelX = (x0 + x1) / 2;
@@ -3119,11 +3129,11 @@ var renderBarChart = (f, spec, colors) => {
3119
3129
  }
3120
3130
  } else {
3121
3131
  const clusterH = barH * clusterUnitsB;
3122
- const clusterStartY = f.plotY + c * groupH + (groupH - clusterH) / 2;
3132
+ const clusterStartY = f.plotY + (N - 1 - c) * groupH + (groupH - clusterH) / 2;
3123
3133
  const strideB = barH * (1 - overlapPctB);
3124
3134
  for (let s = 0; s < spec.series.length; s++) {
3125
3135
  const v = spec.series[s]?.values[c] ?? 0;
3126
- const y0 = clusterStartY + s * strideB;
3136
+ const y0 = clusterStartY + (Sb - 1 - s) * strideB;
3127
3137
  const tip = f.plotX + (v - min) / range * f.plotW;
3128
3138
  const x0 = Math.min(tip, baseX);
3129
3139
  const w = Math.abs(tip - baseX);
@@ -3171,24 +3181,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3171
3181
  const grouping = spec.grouping ?? "clustered";
3172
3182
  const isStacked = grouping === "stacked" || grouping === "percentStacked";
3173
3183
  const isPercent = grouping === "percentStacked";
3174
- let { min, max } = seriesMinMax(spec);
3175
- if (isStacked) {
3176
- let sumMin = Infinity;
3177
- let sumMax = -Infinity;
3178
- for (let c = 0; c < N; c++) {
3179
- let pos = 0;
3180
- let neg = 0;
3181
- for (const s of spec.series) {
3182
- const v = s.values[c] ?? 0;
3183
- if (v >= 0) pos += v;
3184
- else neg += v;
3185
- }
3186
- if (neg < sumMin) sumMin = neg;
3187
- if (pos > sumMax) sumMax = pos;
3188
- }
3189
- min = isPercent ? 0 : Math.min(0, sumMin);
3190
- max = isPercent ? 1 : Math.max(1, sumMax);
3191
- }
3184
+ const { min, max } = seriesMinMax(spec);
3192
3185
  const range = max - min || 1;
3193
3186
  const step = N > 1 ? f.plotW / (N - 1) : 0;
3194
3187
  const baseY = f.plotY + f.plotH - (0 - min) / range * f.plotH;
@@ -3249,7 +3242,7 @@ var renderLineChart = (f, spec, colors, fill) => {
3249
3242
  })();
3250
3243
  if (fill) {
3251
3244
  const back = basePts.slice().reverse().map(([xp, yp]) => `L${px(xp)},${px(yp)}`).join(" ");
3252
- 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"/>`);
3253
3246
  }
3254
3247
  const lineWPx = series.lineWidthEmu ? Math.max(0.3, series.lineWidthEmu / EMU_PER_PX) : 1.5;
3255
3248
  const dashAttr = series.lineDash ? (() => {
@@ -3263,8 +3256,9 @@ var renderLineChart = (f, spec, colors, fill) => {
3263
3256
  `<path d="${dPath}" fill="none" stroke="${color}" stroke-width="${lineWPx.toFixed(2)}" stroke-linejoin="round" stroke-linecap="round"${dashAttr}/>`
3264
3257
  );
3265
3258
  if (!isStacked) {
3266
- const symbol = series.markerSymbol ?? "auto";
3267
- 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);
3268
3262
  const size = series.markerSizePt ?? 5;
3269
3263
  const r = Math.max(1, size * 0.5);
3270
3264
  for (const [xp, yp] of pts) {
@@ -3506,7 +3500,7 @@ var renderScatterChart = (f, spec, colors) => {
3506
3500
  const drawMarker = sym === "none" ? false : showMarker || sym !== void 0 && sym !== "auto";
3507
3501
  if (drawMarker) {
3508
3502
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3509
- const glyph = sym && sym !== "auto" && sym !== "none" ? sym : "circle";
3503
+ const glyph = autoMarkerSymbol(sym, s);
3510
3504
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3511
3505
  }
3512
3506
  }
@@ -3629,7 +3623,7 @@ var renderRadarChart = (f, spec, colors) => {
3629
3623
  );
3630
3624
  if (showMarker) {
3631
3625
  const r = Math.max(1.5, (series.markerSizePt ?? 5) * 0.5);
3632
- const glyph = series.markerSymbol && series.markerSymbol !== "auto" && series.markerSymbol !== "none" ? series.markerSymbol : "circle";
3626
+ const glyph = autoMarkerSymbol(series.markerSymbol, s);
3633
3627
  for (const [xp, yp] of proj) out.push(seriesMarker(glyph, xp, yp, r, color));
3634
3628
  }
3635
3629
  }
@@ -3665,7 +3659,9 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3665
3659
  const hiddenSet = new Set(spec.legend?.hiddenIndices ?? []);
3666
3660
  const seriesNamesForLegend = allNamesForLegend.filter((_, i) => !hiddenSet.has(i));
3667
3661
  const seriesColorsForLegend = allColorsForLegend.filter((_, i) => !hiddenSet.has(i));
3668
- 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;
3669
3665
  let finiteCount = 0;
3670
3666
  for (const s of spec.series) {
3671
3667
  for (const v of s.values) if (v !== null && Number.isFinite(v)) finiteCount++;
@@ -3688,7 +3684,8 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3688
3684
  ...spec.valueAxisLabelRotationDeg !== void 0 ? { labelRotationDeg: spec.valueAxisLabelRotationDeg } : {},
3689
3685
  ...spec.valueAxis?.displayUnits !== void 0 ? { displayUnits: spec.valueAxis.displayUnits } : {}
3690
3686
  };
3691
- 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 };
3692
3689
  if (!spec.valueAxisHidden) axes = renderValueAxis(f, valueAxis);
3693
3690
  const labelsHidden = spec.categoryAxisHidden || spec.categoryAxisTickLabelPos === "none";
3694
3691
  if (N > 0 && !labelsHidden) {
@@ -3753,8 +3750,11 @@ var renderChart = (shape, x, y, w, h, transform, theme) => {
3753
3750
  `<g${transform}>`,
3754
3751
  // Chart-area backdrop honors <c:chartSpace><c:spPr><a:solidFill> /
3755
3752
  // <a:ln>. plot-area gets its own tinted rect + border when
3756
- // <c:plotArea><c:spPr> authors them.
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 ?? "#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"' : ""}/>`,
3758
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"/>` : "",
3759
3759
  renderChartTitle(f, spec.title ?? "", spec.titleStyle),
3760
3760
  axes,