pptx-kit-preview 0.4.0 → 0.6.0
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 +1 -1
- package/dist/node.js +1 -1
- package/dist/{src-CDTTqUfI.js → src-DDyW3xOV.js} +276 -110
- package/dist/src-DDyW3xOV.js.map +1 -0
- package/package.json +3 -3
- package/dist/src-CDTTqUfI.js.map +0 -1
|
@@ -30,7 +30,7 @@ const defaultMeasurer = (text, spec) => {
|
|
|
30
30
|
const FALLBACK_ASCENT = .9;
|
|
31
31
|
const FALLBACK_DESCENT = .22;
|
|
32
32
|
const FALLBACK_LINEGAP = .08;
|
|
33
|
-
const
|
|
33
|
+
const BASELINE_LEADING_DROP = .036;
|
|
34
34
|
const GRID_NUDGE_X = -.75;
|
|
35
35
|
const specOf = (piece) => ({
|
|
36
36
|
family: piece.family,
|
|
@@ -56,7 +56,7 @@ const fmt = (n) => {
|
|
|
56
56
|
const r = Math.round(n * 100) / 100;
|
|
57
57
|
return Object.is(r, -0) ? "0" : String(r);
|
|
58
58
|
};
|
|
59
|
-
const
|
|
59
|
+
const layoutCore = (input, measure) => {
|
|
60
60
|
const widthCache = /* @__PURE__ */ new Map();
|
|
61
61
|
const metricCache = /* @__PURE__ */ new Map();
|
|
62
62
|
const key = (text, s) => `${s.family}|${s.sizePx}|${s.bold}|${s.italic}|${s.letterSpacingPx}|${text}`;
|
|
@@ -170,11 +170,21 @@ const layoutTextSvg = (input, measure) => {
|
|
|
170
170
|
line.textAnchor = "end";
|
|
171
171
|
line.anchorX = wrapRight;
|
|
172
172
|
}
|
|
173
|
-
if (isFirst && bullet)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
if (isFirst && bullet) {
|
|
174
|
+
let bulletX = firstLeft;
|
|
175
|
+
if (para.align === "center" || para.align === "right") {
|
|
176
|
+
let end = toks.length;
|
|
177
|
+
while (end > 0 && (toks[end - 1].isSpace || toks[end - 1].isBreak)) end--;
|
|
178
|
+
let lineW = 0;
|
|
179
|
+
for (let ti = 0; ti < end; ti++) if (!toks[ti].isBreak) lineW += toks[ti].width;
|
|
180
|
+
bulletX = (para.align === "right" ? wrapRight - lineW : (lineLeft + wrapRight) / 2 - lineW / 2) - (lineLeft - firstLeft);
|
|
181
|
+
}
|
|
182
|
+
line.bullet = {
|
|
183
|
+
x: bulletX,
|
|
184
|
+
baselineDy: 0,
|
|
185
|
+
b: bullet
|
|
186
|
+
};
|
|
187
|
+
}
|
|
178
188
|
line.advance = lineAdvance(line, para);
|
|
179
189
|
cursorY += line.advance;
|
|
180
190
|
lines.push(line);
|
|
@@ -189,7 +199,7 @@ const layoutTextSvg = (input, measure) => {
|
|
|
189
199
|
const vert = input.vert ?? "none";
|
|
190
200
|
const cx = input.boxXpx + input.boxWpx / 2;
|
|
191
201
|
const cy = input.boxYpx + input.boxHpx / 2;
|
|
192
|
-
const frame = vert === "none" ? {
|
|
202
|
+
const frame = vert === "none" || vert === "upright" ? {
|
|
193
203
|
x: input.boxXpx,
|
|
194
204
|
y: input.boxYpx,
|
|
195
205
|
w: input.boxWpx,
|
|
@@ -201,25 +211,43 @@ const layoutTextSvg = (input, measure) => {
|
|
|
201
211
|
h: input.boxWpx
|
|
202
212
|
};
|
|
203
213
|
const columns = vert === "none" ? input.columns ?? null : null;
|
|
204
|
-
const
|
|
205
|
-
|
|
214
|
+
const { placements, requiredH } = columns && columns.count >= 2 ? placeColumns(frame, columns, input.anchor, buildLines) : placeSingle(frame, input.anchor, buildLines);
|
|
215
|
+
return {
|
|
216
|
+
placements,
|
|
217
|
+
requiredH,
|
|
218
|
+
vert,
|
|
219
|
+
cx,
|
|
220
|
+
cy
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
const layoutTextSvg = (input, measure) => {
|
|
224
|
+
const { placements, vert, cx, cy } = layoutCore(input, measure);
|
|
225
|
+
const body = emitPlacements(placements);
|
|
226
|
+
if (vert === "none" || vert === "upright") return body;
|
|
206
227
|
return `<g transform="rotate(${vert === "cw90" ? 90 : 270} ${fmt(cx)} ${fmt(cy)})">${body}</g>`;
|
|
207
228
|
};
|
|
229
|
+
/** Content height (px) the body would occupy at the given input's font sizes —
|
|
230
|
+
* for a single column the block height, for multi-column the tallest filled
|
|
231
|
+
* column. The SVG normAutofit path uses this to pick a shrink scale. */
|
|
232
|
+
const measureTextBodyHeight = (input, measure) => layoutCore(input, measure).requiredH;
|
|
208
233
|
const anchorOffsetY = (frameY, frameH, blockH, anchor, firstLine) => {
|
|
209
234
|
let offsetY = frameY;
|
|
210
235
|
if (anchor === "center") offsetY = frameY + (frameH - blockH) / 2;
|
|
211
236
|
else if (anchor === "bottom") offsetY = frameY + (frameH - blockH);
|
|
212
|
-
if (
|
|
237
|
+
if (firstLine) offsetY += BASELINE_LEADING_DROP * (firstLine.ascent + firstLine.descent);
|
|
213
238
|
return offsetY;
|
|
214
239
|
};
|
|
215
240
|
const placeSingle = (frame, anchor, buildLines) => {
|
|
216
241
|
const { lines, blockH } = buildLines(frame.x, frame.x + frame.w);
|
|
217
242
|
const offsetY = anchorOffsetY(frame.y, frame.h, blockH, anchor, lines[0]);
|
|
218
|
-
return
|
|
219
|
-
line
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
243
|
+
return {
|
|
244
|
+
placements: lines.map((line) => ({
|
|
245
|
+
line,
|
|
246
|
+
baselineY: offsetY + line.topY + topPad(line) + line.ascent,
|
|
247
|
+
dx: 0
|
|
248
|
+
})),
|
|
249
|
+
requiredH: blockH
|
|
250
|
+
};
|
|
223
251
|
};
|
|
224
252
|
const placeColumns = (frame, columns, anchor, buildLines) => {
|
|
225
253
|
const gap = columns.gapPx;
|
|
@@ -246,11 +274,14 @@ const placeColumns = (frame, columns, anchor, buildLines) => {
|
|
|
246
274
|
if (localTopY + line.advance > tallest) tallest = localTopY + line.advance;
|
|
247
275
|
}
|
|
248
276
|
const offsetY = anchorOffsetY(frame.y, frame.h, tallest, anchor, lines[0]);
|
|
249
|
-
return
|
|
250
|
-
line,
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
277
|
+
return {
|
|
278
|
+
placements: placed.map(({ line, localTopY, col: c }) => ({
|
|
279
|
+
line,
|
|
280
|
+
baselineY: offsetY + localTopY + topPad(line) + line.ascent,
|
|
281
|
+
dx: c * (colW + gap)
|
|
282
|
+
})),
|
|
283
|
+
requiredH: tallest
|
|
284
|
+
};
|
|
254
285
|
};
|
|
255
286
|
const emitPlacements = (placements) => {
|
|
256
287
|
const parts = [];
|
|
@@ -348,8 +379,8 @@ const wrapTokens = (tokens, wrap, firstAvail, avail) => {
|
|
|
348
379
|
continue;
|
|
349
380
|
}
|
|
350
381
|
const limit = first ? firstAvail : avail;
|
|
351
|
-
const
|
|
352
|
-
if (wrap &&
|
|
382
|
+
const hasContent = lineW - trailingSpaceW > 0;
|
|
383
|
+
if (wrap && hasContent && lineW + tok.width > limit + .5) {
|
|
353
384
|
close();
|
|
354
385
|
cur.push(tok);
|
|
355
386
|
lineW = tok.width;
|
|
@@ -374,6 +405,7 @@ const PX_PER_PT = 96 / 72;
|
|
|
374
405
|
const DEFAULT_BODY_PT = 18;
|
|
375
406
|
const DEFAULT_TITLE_PT = 44;
|
|
376
407
|
const DEFAULT_FONT = "Calibri, 'Helvetica Neue', Arial, sans-serif";
|
|
408
|
+
const DEFAULT_BULLET_FONT = "Arial";
|
|
377
409
|
const DEFAULT_INSET_X = 91440;
|
|
378
410
|
const DEFAULT_INSET_Y = 45720;
|
|
379
411
|
const u8ToBase64 = (data) => {
|
|
@@ -629,15 +661,15 @@ const patternDef = (pat) => {
|
|
|
629
661
|
};
|
|
630
662
|
const pctMatch = /^pct(\d+)$/.exec(preset);
|
|
631
663
|
if (pctMatch) body = screen(Math.min(100, Math.max(0, Number.parseInt(pctMatch[1], 10))) / 100);
|
|
632
|
-
else if (preset === "
|
|
633
|
-
else if (preset === "
|
|
634
|
-
else if (preset === "
|
|
635
|
-
else if (preset === "
|
|
664
|
+
else if (preset === "horz" || preset === "ltHorz" || preset === "narHorz" || preset === "dashHorz" || preset === "horzBrick") body = stripe("h", .8);
|
|
665
|
+
else if (preset === "dkHorz") body = stripe("h", 2);
|
|
666
|
+
else if (preset === "vert" || preset === "ltVert" || preset === "narVert" || preset === "dashVert") body = stripe("v", .8);
|
|
667
|
+
else if (preset === "dkVert") body = stripe("v", 2);
|
|
636
668
|
else if (preset === "ltUpDiag" || preset === "wdUpDiag") body = stripe("d", .8);
|
|
637
669
|
else if (preset === "dkUpDiag") body = stripe("d", 2);
|
|
638
670
|
else if (preset === "ltDnDiag" || preset === "wdDnDiag") body = stripe("a", .8);
|
|
639
671
|
else if (preset === "dkDnDiag") body = stripe("a", 2);
|
|
640
|
-
else if (preset === "ltHorzCross" || preset === "smGrid" || preset === "cross") body = stripe("h", .8) + stripe("v", .8);
|
|
672
|
+
else if (preset === "ltHorzCross" || preset === "smGrid" || preset === "cross" || preset === "dotGrid") body = stripe("h", .8) + stripe("v", .8);
|
|
641
673
|
else if (preset === "dkHorzCross" || preset === "lgGrid" || preset === "plaid") body = stripe("h", 2) + stripe("v", 2);
|
|
642
674
|
else if (preset === "diagCross" || preset === "trellis" || preset === "shingle" || preset === "dashUpDiag" || preset === "dashDnDiag") body = stripe("d", .8) + stripe("a", .8);
|
|
643
675
|
else if (preset === "dkUpDiagStripe" || preset === "dkDnDiagStripe") body = stripe(preset === "dkUpDiagStripe" ? "d" : "a", 2);
|
|
@@ -829,42 +861,54 @@ const PRESET_POINTS = {
|
|
|
829
861
|
star16: () => star(16),
|
|
830
862
|
star24: () => star(24),
|
|
831
863
|
star32: () => star(32),
|
|
832
|
-
rightArrow: () =>
|
|
833
|
-
|
|
834
|
-
[
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
[
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
864
|
+
rightArrow: (w, h) => {
|
|
865
|
+
const bx = 1 - Math.min(1, .5 * Math.min(w, h) / w);
|
|
866
|
+
return [
|
|
867
|
+
[0, .25],
|
|
868
|
+
[bx, .25],
|
|
869
|
+
[bx, 0],
|
|
870
|
+
[1, .5],
|
|
871
|
+
[bx, 1],
|
|
872
|
+
[bx, .75],
|
|
873
|
+
[0, .75]
|
|
874
|
+
];
|
|
875
|
+
},
|
|
876
|
+
leftArrow: (w, h) => {
|
|
877
|
+
const bx = Math.min(1, .5 * Math.min(w, h) / w);
|
|
878
|
+
return [
|
|
879
|
+
[1, .25],
|
|
880
|
+
[bx, .25],
|
|
881
|
+
[bx, 0],
|
|
882
|
+
[0, .5],
|
|
883
|
+
[bx, 1],
|
|
884
|
+
[bx, .75],
|
|
885
|
+
[1, .75]
|
|
886
|
+
];
|
|
887
|
+
},
|
|
888
|
+
upArrow: (w, h) => {
|
|
889
|
+
const by = Math.min(1, .5 * Math.min(w, h) / h);
|
|
890
|
+
return [
|
|
891
|
+
[.25, 1],
|
|
892
|
+
[.25, by],
|
|
893
|
+
[0, by],
|
|
894
|
+
[.5, 0],
|
|
895
|
+
[1, by],
|
|
896
|
+
[.75, by],
|
|
897
|
+
[.75, 1]
|
|
898
|
+
];
|
|
899
|
+
},
|
|
900
|
+
downArrow: (w, h) => {
|
|
901
|
+
const by = 1 - Math.min(1, .5 * Math.min(w, h) / h);
|
|
902
|
+
return [
|
|
903
|
+
[.25, 0],
|
|
904
|
+
[.25, by],
|
|
905
|
+
[0, by],
|
|
906
|
+
[.5, 1],
|
|
907
|
+
[1, by],
|
|
908
|
+
[.75, by],
|
|
909
|
+
[.75, 0]
|
|
910
|
+
];
|
|
911
|
+
},
|
|
868
912
|
leftRightArrow: () => [
|
|
869
913
|
[0, .5],
|
|
870
914
|
[.18, .2],
|
|
@@ -1766,6 +1810,8 @@ const renderRun = (text, format, theme, effectivePt, _wasDefault = false) => {
|
|
|
1766
1810
|
};
|
|
1767
1811
|
const LINE_HEIGHT = 1.05;
|
|
1768
1812
|
const AVG_GLYPH_W_RATIO = .55;
|
|
1813
|
+
const AUTOFIT_FLOOR = .25;
|
|
1814
|
+
const AUTOFIT_STEP = .05;
|
|
1769
1815
|
const hasUnderlineFmt = (fmt) => {
|
|
1770
1816
|
const u = fmt?.underline;
|
|
1771
1817
|
return u !== void 0 && u !== false && u !== "none";
|
|
@@ -1778,15 +1824,15 @@ const alignOf = (a) => a === "center" || a === "right" || a === "justify" ? a :
|
|
|
1778
1824
|
const verticalLayoutOf = (vert) => {
|
|
1779
1825
|
switch (vert) {
|
|
1780
1826
|
case "vert":
|
|
1781
|
-
case "eaVert":
|
|
1827
|
+
case "eaVert": return "cw90";
|
|
1782
1828
|
case "wordArtVert":
|
|
1783
|
-
case "wordArtVertRtl": return "
|
|
1829
|
+
case "wordArtVertRtl": return "upright";
|
|
1784
1830
|
case "vert270":
|
|
1785
1831
|
case "mongolianVert": return "cw270";
|
|
1786
1832
|
case null: return "none";
|
|
1787
1833
|
}
|
|
1788
1834
|
};
|
|
1789
|
-
const
|
|
1835
|
+
const buildSvgTextInput = (a) => {
|
|
1790
1836
|
const scale = a.autoFitScale;
|
|
1791
1837
|
const paragraphs = a.paraData.map((para, pi) => {
|
|
1792
1838
|
const pieces = [];
|
|
@@ -1800,7 +1846,7 @@ const buildAndLayoutSvgText = (a) => {
|
|
|
1800
1846
|
const hlinkColor = a.theme ? normalizeHex(a.theme.hyperlink) : "#0563C1";
|
|
1801
1847
|
fmt = {
|
|
1802
1848
|
...fmt,
|
|
1803
|
-
color:
|
|
1849
|
+
color: hlinkColor,
|
|
1804
1850
|
underline: fmt?.underline ?? true
|
|
1805
1851
|
};
|
|
1806
1852
|
}
|
|
@@ -1824,9 +1870,19 @@ const buildAndLayoutSvgText = (a) => {
|
|
|
1824
1870
|
};
|
|
1825
1871
|
const segs = run.text.split("\n");
|
|
1826
1872
|
segs.forEach((seg, i) => {
|
|
1827
|
-
|
|
1873
|
+
const segText = caps ? seg.toUpperCase() : seg;
|
|
1874
|
+
if (a.vert === "upright") for (const g of Array.from(segText)) {
|
|
1875
|
+
const last = pieces[pieces.length - 1];
|
|
1876
|
+
if (last !== void 0 && !last.isBreak) pieces.push(breakPiece());
|
|
1877
|
+
pieces.push({
|
|
1878
|
+
...base,
|
|
1879
|
+
text: g,
|
|
1880
|
+
isBreak: false
|
|
1881
|
+
});
|
|
1882
|
+
}
|
|
1883
|
+
else pieces.push({
|
|
1828
1884
|
...base,
|
|
1829
|
-
text:
|
|
1885
|
+
text: segText,
|
|
1830
1886
|
isBreak: false
|
|
1831
1887
|
});
|
|
1832
1888
|
if (i < segs.length - 1) pieces.push(breakPiece());
|
|
@@ -1858,7 +1914,7 @@ const buildAndLayoutSvgText = (a) => {
|
|
|
1858
1914
|
fallbackSizePx: a.defaultPt * scale * PX_PER_PT
|
|
1859
1915
|
};
|
|
1860
1916
|
});
|
|
1861
|
-
return
|
|
1917
|
+
return {
|
|
1862
1918
|
boxXpx: a.innerX / EMU_PER_PX,
|
|
1863
1919
|
boxYpx: a.innerY / EMU_PER_PX,
|
|
1864
1920
|
boxWpx: a.innerW / EMU_PER_PX,
|
|
@@ -1868,8 +1924,9 @@ const buildAndLayoutSvgText = (a) => {
|
|
|
1868
1924
|
paragraphs,
|
|
1869
1925
|
vert: a.vert,
|
|
1870
1926
|
columns: a.columns
|
|
1871
|
-
}
|
|
1927
|
+
};
|
|
1872
1928
|
};
|
|
1929
|
+
const buildAndLayoutSvgText = (a) => layoutTextSvg(buildSvgTextInput(a), a.measure);
|
|
1873
1930
|
const breakPiece = () => ({
|
|
1874
1931
|
text: "",
|
|
1875
1932
|
family: "",
|
|
@@ -1889,17 +1946,52 @@ const buildBullet = (a, para, pi) => {
|
|
|
1889
1946
|
const numberLabel = a.numberLabels[pi] ?? null;
|
|
1890
1947
|
if (!(para.bulletStyle === "bullet" || explicitChar !== null || numberLabel !== null || para.bulletIsPicture || para.bulletStyle !== "none" && para.level > 0)) return null;
|
|
1891
1948
|
const char = para.bulletIsPicture ? "■" : numberLabel ?? explicitChar ?? bulletChar(para.level);
|
|
1892
|
-
const baseSizePx = a.defaultPt * PX_PER_PT * a.autoFitScale;
|
|
1949
|
+
const baseSizePx = (para.runs.find((r) => r.text !== "\n" && r.text !== "")?.sizePt ?? a.defaultPt) * PX_PER_PT * a.autoFitScale;
|
|
1893
1950
|
const sizePx = para.bulletDetail.sizePct !== null ? baseSizePx * para.bulletDetail.sizePct : para.bulletDetail.sizePts !== null ? para.bulletDetail.sizePts * PX_PER_PT * a.autoFitScale : baseSizePx;
|
|
1894
1951
|
const fillHex = para.bulletDetail.color ? resolveColor(para.bulletDetail.color, a.theme, "#000000") : a.defaultColor;
|
|
1895
1952
|
return {
|
|
1896
1953
|
text: char,
|
|
1897
|
-
family: substituteFamily(para.bulletDetail.font ??
|
|
1954
|
+
family: substituteFamily(para.bulletDetail.font ?? DEFAULT_BULLET_FONT),
|
|
1898
1955
|
sizePx,
|
|
1899
1956
|
fillHex,
|
|
1900
1957
|
...para.bulletImageHref ? { imageHref: para.bulletImageHref } : {}
|
|
1901
1958
|
};
|
|
1902
1959
|
};
|
|
1960
|
+
const presetTextRect = (preset) => {
|
|
1961
|
+
switch (preset) {
|
|
1962
|
+
case "triangle": return {
|
|
1963
|
+
l: .25,
|
|
1964
|
+
t: .5,
|
|
1965
|
+
r: .75,
|
|
1966
|
+
b: 1
|
|
1967
|
+
};
|
|
1968
|
+
case "diamond": return {
|
|
1969
|
+
l: .25,
|
|
1970
|
+
t: .25,
|
|
1971
|
+
r: .75,
|
|
1972
|
+
b: .75
|
|
1973
|
+
};
|
|
1974
|
+
case "pentagon": return {
|
|
1975
|
+
l: .191,
|
|
1976
|
+
t: .236,
|
|
1977
|
+
r: .809,
|
|
1978
|
+
b: 1
|
|
1979
|
+
};
|
|
1980
|
+
case "star5": return {
|
|
1981
|
+
l: .309,
|
|
1982
|
+
t: .382,
|
|
1983
|
+
r: .691,
|
|
1984
|
+
b: .764
|
|
1985
|
+
};
|
|
1986
|
+
case "leftRightArrow": return {
|
|
1987
|
+
l: .18,
|
|
1988
|
+
t: .35,
|
|
1989
|
+
r: .82,
|
|
1990
|
+
b: .65
|
|
1991
|
+
};
|
|
1992
|
+
default: return null;
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1903
1995
|
const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
1904
1996
|
let paragraphCount;
|
|
1905
1997
|
try {
|
|
@@ -1937,11 +2029,33 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
1937
2029
|
const tIns = margins.top ?? DEFAULT_INSET_Y;
|
|
1938
2030
|
const rIns = margins.right ?? DEFAULT_INSET_X;
|
|
1939
2031
|
const bIns = margins.bottom ?? DEFAULT_INSET_Y;
|
|
1940
|
-
const
|
|
1941
|
-
const
|
|
1942
|
-
const
|
|
1943
|
-
const
|
|
2032
|
+
const pRect = presetTextRect(getShapePreset(shape));
|
|
2033
|
+
const rectX = pRect ? bounds.x + pRect.l * bounds.w : bounds.x;
|
|
2034
|
+
const rectY = pRect ? bounds.y + pRect.t * bounds.h : bounds.y;
|
|
2035
|
+
const rectW = pRect ? (pRect.r - pRect.l) * bounds.w : bounds.w;
|
|
2036
|
+
const rectH = pRect ? (pRect.b - pRect.t) * bounds.h : bounds.h;
|
|
2037
|
+
let innerX = rectX + lIns;
|
|
2038
|
+
let innerY = rectY + tIns;
|
|
2039
|
+
let innerW = rectW - lIns - rIns;
|
|
2040
|
+
let innerH = rectH - tIns - bIns;
|
|
2041
|
+
if (pRect && (innerW <= 0 || innerH <= 0)) {
|
|
2042
|
+
innerX = rectX;
|
|
2043
|
+
innerY = rectY;
|
|
2044
|
+
innerW = rectW;
|
|
2045
|
+
innerH = rectH;
|
|
2046
|
+
}
|
|
1944
2047
|
if (innerW <= 0 || innerH <= 0) return "";
|
|
2048
|
+
const svgTextRect = (v) => v === "none" || v === "upright" ? {
|
|
2049
|
+
x: innerX,
|
|
2050
|
+
y: innerY,
|
|
2051
|
+
w: innerW,
|
|
2052
|
+
h: innerH
|
|
2053
|
+
} : {
|
|
2054
|
+
x: bounds.x + tIns,
|
|
2055
|
+
y: bounds.y + lIns,
|
|
2056
|
+
w: Math.max(0, bounds.w - tIns - bIns),
|
|
2057
|
+
h: Math.max(0, bounds.h - lIns - rIns)
|
|
2058
|
+
};
|
|
1945
2059
|
const paraData = [];
|
|
1946
2060
|
let hasAnyText = false;
|
|
1947
2061
|
for (let p = 0; p < paragraphCount; p++) {
|
|
@@ -2121,6 +2235,45 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2121
2235
|
numberLabels[i] = formatAutoNum(num, counter);
|
|
2122
2236
|
}
|
|
2123
2237
|
}
|
|
2238
|
+
if (authoredAutofit && autoFitScale === 1) {
|
|
2239
|
+
const fitVert = verticalLayoutOf(effectiveBody.vert ?? getShapeTextDirection(shape));
|
|
2240
|
+
const fitCols = getShapeTextColumns(shape);
|
|
2241
|
+
const fitColumns = fitVert === "none" && fitCols && fitCols.count >= 2 ? {
|
|
2242
|
+
count: fitCols.count,
|
|
2243
|
+
gapPx: fitCols.gapEmu !== void 0 ? fitCols.gapEmu / EMU_PER_PX : 12
|
|
2244
|
+
} : null;
|
|
2245
|
+
const fitRect = svgTextRect(fitVert);
|
|
2246
|
+
const fitBoxPx = (fitVert === "cw90" || fitVert === "cw270" ? fitRect.w : fitRect.h) / EMU_PER_PX;
|
|
2247
|
+
const fitArgsBase = {
|
|
2248
|
+
pres,
|
|
2249
|
+
shape,
|
|
2250
|
+
theme,
|
|
2251
|
+
paraData,
|
|
2252
|
+
numberLabels,
|
|
2253
|
+
lineHeightScale,
|
|
2254
|
+
defaultPt,
|
|
2255
|
+
themeFace,
|
|
2256
|
+
defaultColor: activeDeckTextColor,
|
|
2257
|
+
anchor: anchor === "center" || anchor === "bottom" ? anchor : "top",
|
|
2258
|
+
wrap: effectiveBody.wrap !== "none",
|
|
2259
|
+
innerX: fitRect.x,
|
|
2260
|
+
innerY: fitRect.y,
|
|
2261
|
+
innerW: fitRect.w,
|
|
2262
|
+
innerH: fitRect.h,
|
|
2263
|
+
measure: ctx.measure,
|
|
2264
|
+
vert: fitVert,
|
|
2265
|
+
columns: fitColumns
|
|
2266
|
+
};
|
|
2267
|
+
let s = 1;
|
|
2268
|
+
while (s > AUTOFIT_FLOOR) {
|
|
2269
|
+
if (measureTextBodyHeight(buildSvgTextInput({
|
|
2270
|
+
...fitArgsBase,
|
|
2271
|
+
autoFitScale: s
|
|
2272
|
+
}), ctx.measure) <= fitBoxPx) break;
|
|
2273
|
+
s -= AUTOFIT_STEP;
|
|
2274
|
+
}
|
|
2275
|
+
autoFitScale = Math.max(AUTOFIT_FLOOR, s);
|
|
2276
|
+
}
|
|
2124
2277
|
const paragraphs = [];
|
|
2125
2278
|
for (let pi = 0; pi < paraData.length; pi++) {
|
|
2126
2279
|
const para = paraData[pi];
|
|
@@ -2130,7 +2283,7 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2130
2283
|
const hlinkColor = theme ? normalizeHex(theme.hyperlink) : "#0563C1";
|
|
2131
2284
|
runFmt = {
|
|
2132
2285
|
...runFmt,
|
|
2133
|
-
color:
|
|
2286
|
+
color: hlinkColor,
|
|
2134
2287
|
underline: runFmt?.underline ?? true
|
|
2135
2288
|
};
|
|
2136
2289
|
}
|
|
@@ -2162,8 +2315,8 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2162
2315
|
const explicitChar = para.bulletStyle !== null && typeof para.bulletStyle === "object" && "char" in para.bulletStyle ? para.bulletStyle.char : null;
|
|
2163
2316
|
const numberLabel = numberLabels[pi];
|
|
2164
2317
|
const showBullet = para.bulletStyle === "bullet" || explicitChar !== null || numberLabel !== null || para.bulletIsPicture || para.bulletStyle !== "none" && para.level > 0;
|
|
2318
|
+
const baseBulletPx = (para.runs.find((r) => r.text !== "\n" && r.text !== "")?.sizePt ?? defaultPt) * PX_PER_PT * autoFitScale;
|
|
2165
2319
|
if (showBullet && para.bulletImageHref) {
|
|
2166
|
-
const baseBulletPx = defaultPt * PX_PER_PT * autoFitScale;
|
|
2167
2320
|
const bulletPx = para.bulletDetail.sizePct !== null ? baseBulletPx * para.bulletDetail.sizePct : para.bulletDetail.sizePts !== null ? para.bulletDetail.sizePts * PX_PER_PT * autoFitScale : baseBulletPx;
|
|
2168
2321
|
const imgStyles = [
|
|
2169
2322
|
`width:${bulletPx.toFixed(2)}px`,
|
|
@@ -2179,7 +2332,8 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2179
2332
|
if (para.bulletDetail.color) bulletStyles.push(`color:${resolveColor(para.bulletDetail.color, theme, "#000000")}`);
|
|
2180
2333
|
if (para.bulletDetail.sizePct !== null) bulletStyles.push(`font-size:${(para.bulletDetail.sizePct * 100).toFixed(1)}%`);
|
|
2181
2334
|
else if (para.bulletDetail.sizePts !== null) bulletStyles.push(`font-size:${(para.bulletDetail.sizePts * PX_PER_PT * autoFitScale).toFixed(2)}px`);
|
|
2182
|
-
|
|
2335
|
+
else bulletStyles.push(`font-size:${baseBulletPx.toFixed(2)}px`);
|
|
2336
|
+
bulletStyles.push(para.bulletDetail.font ? `font-family:${escapeXml(para.bulletDetail.font)}, ${DEFAULT_FONT}` : `font-family:${DEFAULT_BULLET_FONT}, ${DEFAULT_FONT}`);
|
|
2183
2337
|
prefix = `<span style="${bulletStyles.join(";")}">${escapeXml(char)}</span>`;
|
|
2184
2338
|
}
|
|
2185
2339
|
paragraphs.push(`<p style="${pStyles.join(";")}">${prefix}${runHtmls.join("") || "​"}</p>`);
|
|
@@ -2187,7 +2341,6 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2187
2341
|
const justify = ANCHOR_TO_CSS[anchor] ?? "flex-start";
|
|
2188
2342
|
const defaultColor = activeDeckTextColor;
|
|
2189
2343
|
if (ctx.mode === "svg") {
|
|
2190
|
-
const svgScale = authoredAutofit?.fontScale ?? 1;
|
|
2191
2344
|
const svgLineScale = 1 - (authoredAutofit?.lnSpcReduction ?? 0);
|
|
2192
2345
|
const svgVert = verticalLayoutOf(effectiveBody.vert ?? getShapeTextDirection(shape));
|
|
2193
2346
|
const svgCols = getShapeTextColumns(shape);
|
|
@@ -2195,31 +2348,37 @@ const renderTextBody = (pres, shape, bounds, theme, phType, ctx) => {
|
|
|
2195
2348
|
count: svgCols.count,
|
|
2196
2349
|
gapPx: svgCols.gapEmu !== void 0 ? svgCols.gapEmu / EMU_PER_PX : 12
|
|
2197
2350
|
} : null;
|
|
2198
|
-
const
|
|
2351
|
+
const { x: vInnerX, y: vInnerY, w: vInnerW, h: vInnerH } = svgTextRect(svgVert);
|
|
2352
|
+
if (vInnerW <= 0 || vInnerH <= 0) return "";
|
|
2353
|
+
const svgArgsBase = {
|
|
2199
2354
|
pres,
|
|
2200
2355
|
shape,
|
|
2201
2356
|
theme,
|
|
2202
2357
|
paraData,
|
|
2203
2358
|
numberLabels,
|
|
2204
|
-
autoFitScale: svgScale,
|
|
2205
2359
|
lineHeightScale: svgLineScale,
|
|
2206
2360
|
defaultPt,
|
|
2207
2361
|
themeFace,
|
|
2208
2362
|
defaultColor,
|
|
2209
2363
|
anchor: anchor === "center" || anchor === "bottom" ? anchor : "top",
|
|
2210
2364
|
wrap: effectiveBody.wrap !== "none",
|
|
2211
|
-
innerX,
|
|
2212
|
-
innerY,
|
|
2213
|
-
innerW,
|
|
2214
|
-
innerH,
|
|
2365
|
+
innerX: vInnerX,
|
|
2366
|
+
innerY: vInnerY,
|
|
2367
|
+
innerW: vInnerW,
|
|
2368
|
+
innerH: vInnerH,
|
|
2215
2369
|
measure: ctx.measure,
|
|
2216
2370
|
vert: svgVert,
|
|
2217
2371
|
columns: svgColumns
|
|
2372
|
+
};
|
|
2373
|
+
const svgScale = authoredAutofit ? autoFitScale : 1;
|
|
2374
|
+
const svgInner = buildAndLayoutSvgText({
|
|
2375
|
+
...svgArgsBase,
|
|
2376
|
+
autoFitScale: svgScale
|
|
2218
2377
|
});
|
|
2219
2378
|
const bodyRotDegSvg = getShapeTextBodyRotationDeg(shape);
|
|
2220
2379
|
if (bodyRotDegSvg !== null && bodyRotDegSvg !== 0) {
|
|
2221
|
-
const pivotX =
|
|
2222
|
-
const pivotY =
|
|
2380
|
+
const pivotX = vInnerX + vInnerW / 2;
|
|
2381
|
+
const pivotY = vInnerY + vInnerH / 2;
|
|
2223
2382
|
return `<g transform="rotate(${bodyRotDegSvg} ${E(pivotX)} ${E(pivotY)})">${svgInner}</g>`;
|
|
2224
2383
|
}
|
|
2225
2384
|
return svgInner;
|
|
@@ -2272,15 +2431,16 @@ const accentSequence = (theme) => {
|
|
|
2272
2431
|
].map((c) => normalizeHex(c)).filter((c) => /^#[0-9A-Fa-f]{6}$/.test(c));
|
|
2273
2432
|
return hexes.length > 0 ? hexes : fallbacks;
|
|
2274
2433
|
};
|
|
2275
|
-
const
|
|
2434
|
+
const DEFAULT_CHART_TITLE_PT = 13;
|
|
2435
|
+
const layoutChart = (xEmu, yEmu, wEmu, hEmu, hasTitle, hasAxes, titleOverlay = false, legendOverlay = false, hasLegend = true, titlePx = DEFAULT_CHART_TITLE_PT * PX_PER_PT) => {
|
|
2276
2436
|
const x = xEmu / EMU_PER_PX;
|
|
2277
2437
|
const y = yEmu / EMU_PER_PX;
|
|
2278
2438
|
const w = wEmu / EMU_PER_PX;
|
|
2279
2439
|
const h = hEmu / EMU_PER_PX;
|
|
2280
|
-
const titleStrip = hasTitle && !titleOverlay ?
|
|
2440
|
+
const titleStrip = hasTitle && !titleOverlay ? Math.round(titlePx * 2.4) : 0;
|
|
2281
2441
|
const legendStrip = hasLegend && !legendOverlay ? 18 : 0;
|
|
2282
2442
|
const padding = 8;
|
|
2283
|
-
const yAxisGutter = hasAxes ?
|
|
2443
|
+
const yAxisGutter = hasAxes ? 32 : 0;
|
|
2284
2444
|
const xAxisGutter = hasAxes ? 18 : 0;
|
|
2285
2445
|
return {
|
|
2286
2446
|
x,
|
|
@@ -2291,7 +2451,7 @@ const layoutChart = (xEmu, yEmu, wEmu, hEmu, hasTitle, hasAxes, titleOverlay = f
|
|
|
2291
2451
|
plotY: y + titleStrip + padding,
|
|
2292
2452
|
plotW: Math.max(0, w - 2 * padding - yAxisGutter),
|
|
2293
2453
|
plotH: Math.max(0, h - titleStrip - legendStrip - xAxisGutter - 2 * padding),
|
|
2294
|
-
titleY: y + (titleOverlay ? 14 :
|
|
2454
|
+
titleY: y + (titleOverlay ? 14 : padding + titlePx * .7),
|
|
2295
2455
|
legendY: y + h - (legendOverlay ? 18 : legendStrip / 2)
|
|
2296
2456
|
};
|
|
2297
2457
|
};
|
|
@@ -2379,12 +2539,13 @@ const DISPLAY_UNIT_LABEL = {
|
|
|
2379
2539
|
const DEFAULT_AXIS_COLOR = "#000000";
|
|
2380
2540
|
const DEFAULT_GRID_COLOR = "#D9D9D9";
|
|
2381
2541
|
const AXIS_TICK_LEN = 5;
|
|
2542
|
+
const chartFontPx = (sizePt) => (sizePt * PX_PER_PT).toFixed(1);
|
|
2382
2543
|
const axisTickAttrs = (style) => {
|
|
2383
2544
|
const sz = style?.sizePt ?? 10;
|
|
2384
2545
|
const fill = style?.color ?? "#6B7280";
|
|
2385
2546
|
const weight = style?.bold ? " font-weight=\"600\"" : "";
|
|
2386
2547
|
const italic = style?.italic ? " font-style=\"italic\"" : "";
|
|
2387
|
-
return `font-family="sans-serif" font-size="${sz
|
|
2548
|
+
return `font-family="sans-serif" font-size="${chartFontPx(sz)}" fill="${fill}"${weight}${italic}`;
|
|
2388
2549
|
};
|
|
2389
2550
|
const renderValueAxis = (f, axis) => {
|
|
2390
2551
|
const ticks = axis.majorUnit ? (() => {
|
|
@@ -2537,11 +2698,11 @@ const seriesMinMax = (spec) => {
|
|
|
2537
2698
|
};
|
|
2538
2699
|
const renderChartTitle = (f, title, style) => {
|
|
2539
2700
|
if (!title) return "";
|
|
2540
|
-
const sz = style?.sizePt ??
|
|
2701
|
+
const sz = style?.sizePt ?? DEFAULT_CHART_TITLE_PT;
|
|
2541
2702
|
const fill = style?.color ?? "#1F2937";
|
|
2542
2703
|
const weight = style?.bold === false ? "400" : "600";
|
|
2543
2704
|
const fontStyleAttr = style?.italic ? " font-style=\"italic\"" : "";
|
|
2544
|
-
return `<text x="${px(f.x + f.w / 2)}" y="${px(f.titleY)}" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="${sz
|
|
2705
|
+
return `<text x="${px(f.x + f.w / 2)}" y="${px(f.titleY)}" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="${chartFontPx(sz)}" fill="${fill}" font-weight="${weight}"${fontStyleAttr}>${escapeXml(title)}</text>`;
|
|
2545
2706
|
};
|
|
2546
2707
|
const renderChartLegend = (f, names, colors, position = "b", textStyle, markerSymbols) => {
|
|
2547
2708
|
if (names.length === 0) return "";
|
|
@@ -2549,7 +2710,7 @@ const renderChartLegend = (f, names, colors, position = "b", textStyle, markerSy
|
|
|
2549
2710
|
const fill = textStyle?.color ?? "#374151";
|
|
2550
2711
|
const weight = textStyle?.bold ? " font-weight=\"600\"" : "";
|
|
2551
2712
|
const italic = textStyle?.italic ? " font-style=\"italic\"" : "";
|
|
2552
|
-
const textAttrs = `font-family="sans-serif" font-size="${sz
|
|
2713
|
+
const textAttrs = `font-family="sans-serif" font-size="${chartFontPx(sz)}" fill="${fill}"${weight}${italic}`;
|
|
2553
2714
|
const swatch = (i, swatchX, swatchY) => {
|
|
2554
2715
|
const color = colors[i % colors.length];
|
|
2555
2716
|
const sym = markerSymbols?.[i];
|
|
@@ -2836,7 +2997,7 @@ const dataLabelTextAttrs = (spec, seriesIdx, fallbackFill, fallbackSizePt = 9, f
|
|
|
2836
2997
|
const fill = style?.color ?? fallbackFill;
|
|
2837
2998
|
const weight = style?.bold ?? fallbackBold ? " font-weight=\"600\"" : "";
|
|
2838
2999
|
const italic = style?.italic ? " font-style=\"italic\"" : "";
|
|
2839
|
-
return `font-family="sans-serif" font-size="${sz
|
|
3000
|
+
return `font-family="sans-serif" font-size="${chartFontPx(sz)}" fill="${fill}"${weight}${italic}`;
|
|
2840
3001
|
};
|
|
2841
3002
|
const renderBarChart = (f, spec, colors) => {
|
|
2842
3003
|
const N = pointCount(spec);
|
|
@@ -2930,7 +3091,8 @@ const renderLineChart = (f, spec, colors, fill) => {
|
|
|
2930
3091
|
const isPercent = grouping === "percentStacked";
|
|
2931
3092
|
const { min, max } = seriesMinMax(spec);
|
|
2932
3093
|
const range = max - min || 1;
|
|
2933
|
-
const
|
|
3094
|
+
const band = N > 1 ? fill ? f.plotW / (N - 1) : f.plotW / N : 0;
|
|
3095
|
+
const xAt = (c) => fill ? f.plotX + c * band : f.plotX + (c + .5) * band;
|
|
2934
3096
|
const baseY = f.plotY + f.plotH - (0 - min) / range * f.plotH;
|
|
2935
3097
|
const out = [];
|
|
2936
3098
|
out.push(`<line x1="${px(f.plotX)}" y1="${px(baseY)}" x2="${px(f.plotX + f.plotW)}" y2="${px(baseY)}" stroke="#E5E7EB" stroke-width="0.5"/>`);
|
|
@@ -2943,7 +3105,7 @@ const renderLineChart = (f, spec, colors, fill) => {
|
|
|
2943
3105
|
const ptsRaw = [];
|
|
2944
3106
|
const basePtsRaw = [];
|
|
2945
3107
|
for (let c = 0; c < N; c++) {
|
|
2946
|
-
const xp =
|
|
3108
|
+
const xp = xAt(c);
|
|
2947
3109
|
const rawV = series.values[c];
|
|
2948
3110
|
const isNullish = rawV === null || rawV === void 0 || !Number.isFinite(rawV);
|
|
2949
3111
|
let v;
|
|
@@ -3058,7 +3220,7 @@ const renderLineChart = (f, spec, colors, fill) => {
|
|
|
3058
3220
|
}
|
|
3059
3221
|
}
|
|
3060
3222
|
if (!isStacked && (spec.dropLines || spec.hiLowLines) && spec.series.length > 0) for (let c = 0; c < N; c++) {
|
|
3061
|
-
const xp =
|
|
3223
|
+
const xp = xAt(c);
|
|
3062
3224
|
if (spec.dropLines) {
|
|
3063
3225
|
const firstVal = spec.series[0]?.values[c];
|
|
3064
3226
|
if (firstVal !== null && firstVal !== void 0 && Number.isFinite(firstVal)) {
|
|
@@ -3363,7 +3525,7 @@ const renderChart = (shape, x, y, w, h, transform, theme) => {
|
|
|
3363
3525
|
const isCartesian = spec.kind === "column" || spec.kind === "bar" || spec.kind === "line" || spec.kind === "area";
|
|
3364
3526
|
const hasAxes = isCartesian || spec.kind === "scatter" || spec.kind === "bubble";
|
|
3365
3527
|
const hasLegend = spec.legend !== void 0 && spec.legend.position !== null;
|
|
3366
|
-
const f = layoutChart(x, y, w, h, !!spec.title, hasAxes, spec.titleOverlay ?? false, spec.legend?.overlay ?? false, hasLegend);
|
|
3528
|
+
const f = layoutChart(x, y, w, h, !!spec.title, hasAxes, spec.titleOverlay ?? false, spec.legend?.overlay ?? false, hasLegend, (spec.titleStyle?.sizePt ?? DEFAULT_CHART_TITLE_PT) * PX_PER_PT);
|
|
3367
3529
|
const allNamesForLegend = spec.kind === "pie" || spec.kind === "doughnut" ? Array.from(spec.categories) : spec.series.map((s) => s.name);
|
|
3368
3530
|
const allColorsForLegend = spec.kind === "pie" || spec.kind === "doughnut" ? spec.categories.map((_, i) => spec.series[0]?.pointColors?.[i] ?? spec.series[0]?.color ?? colors[i % colors.length] ?? "#888") : spec.series.map((s, i) => s.color ?? colors[i % colors.length] ?? "#888");
|
|
3369
3531
|
const hiddenSet = new Set(spec.legend?.hiddenIndices ?? []);
|
|
@@ -3443,7 +3605,7 @@ const renderChart = (shape, x, y, w, h, transform, theme) => {
|
|
|
3443
3605
|
const fill = style?.color ?? "#374151";
|
|
3444
3606
|
const weight = style?.bold === false ? "400" : "600";
|
|
3445
3607
|
const italicAttr = style?.italic ? " font-style=\"italic\"" : "";
|
|
3446
|
-
return `font-family="sans-serif" font-size="${sz
|
|
3608
|
+
return `font-family="sans-serif" font-size="${chartFontPx(sz)}" fill="${fill}" font-weight="${weight}"${italicAttr}`;
|
|
3447
3609
|
};
|
|
3448
3610
|
const valueAxisTitleRot = spec.valueAxisTitleRotationDeg ?? -90;
|
|
3449
3611
|
const valueAxisTitleSvg = spec.valueAxisTitle ? `<text x="${px(f.plotX - 26)}" y="${px(f.plotY + f.plotH / 2)}" text-anchor="middle" ${axisTitleAttrs(spec.valueAxisTitleStyle)} transform="rotate(${valueAxisTitleRot} ${px(f.plotX - 26)} ${px(f.plotY + f.plotH / 2)})">${escapeXml(spec.valueAxisTitle)}</text>` : "";
|
|
@@ -3821,8 +3983,10 @@ const renderShape = (shape, pres, theme, ctx) => {
|
|
|
3821
3983
|
const strokeColor = p.stroke === "none" ? resolveColor("scheme:tx1", theme, "#1F2937") : p.stroke;
|
|
3822
3984
|
const sa = p.strokeAttrs ? ` ${p.strokeAttrs}` : "";
|
|
3823
3985
|
const ma = p.markerAttrs ?? "";
|
|
3986
|
+
const capDefault = sa.includes("stroke-linecap") ? "" : " stroke-linecap=\"round\"";
|
|
3987
|
+
const joinDefault = sa.includes("stroke-linejoin") ? "" : " stroke-linejoin=\"round\"";
|
|
3824
3988
|
const preset = getShapePreset(shape) ?? "line";
|
|
3825
|
-
if (preset === "straightConnector1" || preset === "line") return `${p.defs}<line x1="${E(x1)}" y1="${E(y1)}" x2="${E(x2)}" y2="${E(y2)}" stroke="${strokeColor}" stroke-width="${E(sw)}"
|
|
3989
|
+
if (preset === "straightConnector1" || preset === "line") return `${p.defs}<line x1="${E(x1)}" y1="${E(y1)}" x2="${E(x2)}" y2="${E(y2)}" stroke="${strokeColor}" stroke-width="${E(sw)}"${capDefault}${sa}${ma}${transform}/>`;
|
|
3826
3990
|
const px1 = x1 / EMU_PER_PX;
|
|
3827
3991
|
const py1 = y1 / EMU_PER_PX;
|
|
3828
3992
|
const px2 = x2 / EMU_PER_PX;
|
|
@@ -3847,7 +4011,7 @@ const renderShape = (shape, pres, theme, ctx) => {
|
|
|
3847
4011
|
const c2x = px1 + 2 * (px2 - px1) / 3;
|
|
3848
4012
|
d += ` C${c1x.toFixed(2)} ${py1.toFixed(2)} ${c2x.toFixed(2)} ${py2.toFixed(2)} ${px2.toFixed(2)} ${py2.toFixed(2)}`;
|
|
3849
4013
|
} else d += ` L${px2.toFixed(2)} ${py2.toFixed(2)}`;
|
|
3850
|
-
return `${p.defs}<path d="${d}" fill="none" stroke="${strokeColor}" stroke-width="${E(sw)}"
|
|
4014
|
+
return `${p.defs}<path d="${d}" fill="none" stroke="${strokeColor}" stroke-width="${E(sw)}"${capDefault}${joinDefault}${sa}${ma}${transform}/>`;
|
|
3851
4015
|
}
|
|
3852
4016
|
if (kind === "group") {
|
|
3853
4017
|
const xform = getGroupTransform(shape);
|
|
@@ -3923,7 +4087,7 @@ const renderShape = (shape, pres, theme, ctx) => {
|
|
|
3923
4087
|
if (pathFn) geomSvg = `<path d="${pathFn(x / EMU_PER_PX, y / EMU_PER_PX, w / EMU_PER_PX, h / EMU_PER_PX)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}" fill-rule="evenodd"${sa}${ma}/>`;
|
|
3924
4088
|
else {
|
|
3925
4089
|
const pointsFn = PRESET_POINTS[preset];
|
|
3926
|
-
if (pointsFn) geomSvg = `<polygon points="${pointsFn().map(([nx, ny]) => `${E(x + nx * w)},${E(y + ny * h)}`).join(" ")}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4090
|
+
if (pointsFn) geomSvg = `<polygon points="${pointsFn(w / EMU_PER_PX, h / EMU_PER_PX).map(([nx, ny]) => `${E(x + nx * w)},${E(y + ny * h)}`).join(" ")}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
3927
4091
|
else geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma} data-pptx-preset="${escapeXml(preset)}"><title>${escapeXml(`preset: ${preset}`)}</title></rect>`;
|
|
3928
4092
|
}
|
|
3929
4093
|
}
|
|
@@ -4040,11 +4204,13 @@ const buildEffectsFilter = (pres, shape) => {
|
|
|
4040
4204
|
primitives.push(`<feGaussianBlur in="SourceAlpha" stdDeviation="${blurPx.toFixed(2)}" result="innerBlur${i}"/>`, `<feOffset in="innerBlur${i}" dx="${dx.toFixed(2)}" dy="${dy.toFixed(2)}" result="innerOff${i}"/>`, `<feComposite in="innerOff${i}" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="innerMask${i}"/>`, `<feFlood flood-color="${color}" flood-opacity="${opacity.toFixed(3)}" result="innerCol${i}"/>`, `<feComposite in="innerCol${i}" in2="innerMask${i}" operator="in" result="innerOut${i}"/>`);
|
|
4041
4205
|
layers.push(`innerOut${i}`);
|
|
4042
4206
|
} else if (e.kind === "glow") {
|
|
4043
|
-
const
|
|
4207
|
+
const radiusPx = e.radiusEmu / EMU_PER_PX;
|
|
4208
|
+
const dilatePx = radiusPx * .5;
|
|
4209
|
+
const featherPx = radiusPx * .3;
|
|
4044
4210
|
const color = e.color || "#FFFFFF";
|
|
4045
4211
|
const opacity = e.opacity ?? 1;
|
|
4046
4212
|
const i = primitives.length;
|
|
4047
|
-
primitives.push(`<feMorphology in="SourceAlpha" operator="dilate" radius="${
|
|
4213
|
+
primitives.push(`<feMorphology in="SourceAlpha" operator="dilate" radius="${dilatePx.toFixed(2)}" result="glowExp${i}"/>`, `<feGaussianBlur in="glowExp${i}" stdDeviation="${featherPx.toFixed(2)}" result="glowBlur${i}"/>`, `<feFlood flood-color="${color}" flood-opacity="${opacity.toFixed(3)}" result="glowCol${i}"/>`, `<feComposite in="glowCol${i}" in2="glowBlur${i}" operator="in" result="glowOut${i}"/>`);
|
|
4048
4214
|
layers.push(`glowOut${i}`);
|
|
4049
4215
|
} else if (e.kind === "softEdge") {
|
|
4050
4216
|
const blurPx = e.radiusEmu / EMU_PER_PX / 2;
|
|
@@ -4174,4 +4340,4 @@ const detectImageFormatLocal = (bytes) => {
|
|
|
4174
4340
|
//#endregion
|
|
4175
4341
|
export { SERIF as a, substituteFamily as c, SANS as i, ARIAL as n, TIMES as o, MONO as r, defaultMeasurer as s, renderSlideSvg as t };
|
|
4176
4342
|
|
|
4177
|
-
//# sourceMappingURL=src-
|
|
4343
|
+
//# sourceMappingURL=src-DDyW3xOV.js.map
|