feat: 补全 styles 映射 — opacity/lineHeight/letterSpacing/textDecoration/display/visibility
TEXT 新增: - textDecorationLine → underline/strike - letterSpacing → charSpacing - opacity → transparency - lineHeight → lineSpacingMultiple - display:none / visibility:hidden → 跳过 Shape 新增: - opacity → transparency - display:none / visibility:hidden → 跳过 PPTX 渲染端同步传递所有新属性
This commit is contained in:
+41
-2
@@ -524,6 +524,9 @@ function convert(input) {
|
|||||||
|
|
||||||
// text 节点
|
// text 节点
|
||||||
if (n.type === 'TEXT' && n.src) {
|
if (n.type === 'TEXT' && n.src) {
|
||||||
|
// 跳过不可见节点
|
||||||
|
if (n.styles.display === 'none' || n.styles.visibility === 'hidden') { continue; }
|
||||||
|
|
||||||
const st = n.styles;
|
const st = n.styles;
|
||||||
const fs = parseFloat(st.fontSize) || 14;
|
const fs = parseFloat(st.fontSize) || 14;
|
||||||
var pt = Math.round(fs);
|
var pt = Math.round(fs);
|
||||||
@@ -533,6 +536,28 @@ function convert(input) {
|
|||||||
if (parseInt(st.fontWeight) >= 700) opts.bold = true;
|
if (parseInt(st.fontWeight) >= 700) opts.bold = true;
|
||||||
if (st.fontStyle === 'italic') opts.italic = true;
|
if (st.fontStyle === 'italic') opts.italic = true;
|
||||||
if (st.textAlign && st.textAlign !== 'start') opts.align = st.textAlign;
|
if (st.textAlign && st.textAlign !== 'start') opts.align = st.textAlign;
|
||||||
|
// 文字装饰
|
||||||
|
if (st.textDecorationLine) {
|
||||||
|
if (st.textDecorationLine.includes('underline')) opts.underline = true;
|
||||||
|
if (st.textDecorationLine.includes('line-through')) opts.strike = 'sngStrike';
|
||||||
|
}
|
||||||
|
// 字符间距
|
||||||
|
if (st.letterSpacing && st.letterSpacing !== 'normal') {
|
||||||
|
var ls = parseFloat(st.letterSpacing);
|
||||||
|
if (!isNaN(ls) && ls !== 0) opts.charSpacing = Math.round(ls * 100 / fs); // 转为百分比
|
||||||
|
}
|
||||||
|
// 透明度
|
||||||
|
if (st.opacity !== undefined && st.opacity !== '' && parseFloat(st.opacity) < 1) {
|
||||||
|
opts.transparency = Math.round((1 - parseFloat(st.opacity)) * 100);
|
||||||
|
}
|
||||||
|
// 行高
|
||||||
|
if (st.lineHeight && st.lineHeight !== 'normal') {
|
||||||
|
var lh = parseFloat(st.lineHeight);
|
||||||
|
if (!isNaN(lh) && lh > 0) {
|
||||||
|
var lhRatio = lh / fs;
|
||||||
|
if (lhRatio > 0.5 && lhRatio < 5) opts.lineSpacingMultiple = Math.round(lhRatio * 100) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 宽度:顶层元素用 contentW,嵌套元素用 parentW,加最小宽度保障
|
// 宽度:顶层元素用 contentW,嵌套元素用 parentW,加最小宽度保障
|
||||||
var textW = n.parentW || r.w;
|
var textW = n.parentW || r.w;
|
||||||
@@ -571,6 +596,9 @@ function convert(input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ===== 提取填充色 =====
|
// ===== 提取填充色 =====
|
||||||
|
// 跳过不可见节点
|
||||||
|
if (n.styles.display === 'none' || n.styles.visibility === 'hidden') { continue; }
|
||||||
|
|
||||||
let fillColor = null;
|
let fillColor = null;
|
||||||
const bg = n.styles.backgroundColor;
|
const bg = n.styles.backgroundColor;
|
||||||
if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') {
|
if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') {
|
||||||
@@ -585,6 +613,10 @@ function convert(input) {
|
|||||||
}
|
}
|
||||||
if (fillColor) {
|
if (fillColor) {
|
||||||
var shapeOpts = { x: opts.x, y: opts.y, w: opts.w, h: opts.h, fill: { color: fillColor } };
|
var shapeOpts = { x: opts.x, y: opts.y, w: opts.w, h: opts.h, fill: { color: fillColor } };
|
||||||
|
// 透明度
|
||||||
|
if (n.styles.opacity !== undefined && n.styles.opacity !== '' && parseFloat(n.styles.opacity) < 1) {
|
||||||
|
shapeOpts.transparency = Math.round((1 - parseFloat(n.styles.opacity)) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
// 圆角
|
// 圆角
|
||||||
var brVal = n.styles.borderTopLeftRadius;
|
var brVal = n.styles.borderTopLeftRadius;
|
||||||
@@ -764,14 +796,20 @@ if (require.main === module) {
|
|||||||
for (const obj of (slideData.objects || [])) {
|
for (const obj of (slideData.objects || [])) {
|
||||||
const o = obj.options || {};
|
const o = obj.options || {};
|
||||||
if (obj.type === 'text') {
|
if (obj.type === 'text') {
|
||||||
slide.addText(obj.text || '', {
|
const textOpts = {
|
||||||
x: o.x, y: o.y, w: o.w, h: o.h,
|
x: o.x, y: o.y, w: o.w, h: o.h,
|
||||||
fontSize: o.fontSize || 12,
|
fontSize: o.fontSize || 12,
|
||||||
fontFace: o.fontFace || 'Arial',
|
fontFace: o.fontFace || 'Arial',
|
||||||
color: o.color || '000000',
|
color: o.color || '000000',
|
||||||
bold: o.bold || false,
|
bold: o.bold || false,
|
||||||
align: o.align || 'left'
|
align: o.align || 'left'
|
||||||
});
|
};
|
||||||
|
if (o.underline) textOpts.underline = o.underline;
|
||||||
|
if (o.strike) textOpts.strike = o.strike;
|
||||||
|
if (o.charSpacing) textOpts.charSpacing = o.charSpacing;
|
||||||
|
if (o.transparency !== undefined) textOpts.transparency = o.transparency;
|
||||||
|
if (o.lineSpacingMultiple) textOpts.lineSpacingMultiple = o.lineSpacingMultiple;
|
||||||
|
slide.addText(obj.text || '', textOpts);
|
||||||
} else if (obj.type === 'shape') {
|
} else if (obj.type === 'shape') {
|
||||||
const st = { rect: 'rect', roundRect: 'roundRect', ellipse: 'ellipse' }[obj.shapeName] || 'rect';
|
const st = { rect: 'rect', roundRect: 'roundRect', ellipse: 'ellipse' }[obj.shapeName] || 'rect';
|
||||||
const shapeOpts = {
|
const shapeOpts = {
|
||||||
@@ -782,6 +820,7 @@ if (require.main === module) {
|
|||||||
else shapeOpts.line = { type: 'none' }; // 去掉 pptxgenjs 默认边框
|
else shapeOpts.line = { type: 'none' }; // 去掉 pptxgenjs 默认边框
|
||||||
if (o.shadow) shapeOpts.shadow = o.shadow;
|
if (o.shadow) shapeOpts.shadow = o.shadow;
|
||||||
if (o.rectRadius) shapeOpts.rectRadius = o.rectRadius;
|
if (o.rectRadius) shapeOpts.rectRadius = o.rectRadius;
|
||||||
|
if (o.transparency !== undefined) shapeOpts.transparency = o.transparency;
|
||||||
slide.addShape(pres.ShapeType[st] || pres.ShapeType.rect, shapeOpts);
|
slide.addShape(pres.ShapeType[st] || pres.ShapeType.rect, shapeOpts);
|
||||||
} else if (obj.type === 'image') {
|
} else if (obj.type === 'image') {
|
||||||
slide.addImage({
|
slide.addImage({
|
||||||
|
|||||||
Reference in New Issue
Block a user