format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
This commit is contained in:
@@ -3,22 +3,23 @@
|
||||
## Setup & Basic Structure
|
||||
|
||||
```javascript
|
||||
const pptxgen = require("pptxgenjs");
|
||||
const pptxgen = require('pptxgenjs');
|
||||
|
||||
let pres = new pptxgen();
|
||||
pres.layout = 'LAYOUT_16x9'; // or 'LAYOUT_16x10', 'LAYOUT_4x3', 'LAYOUT_WIDE'
|
||||
pres.layout = 'LAYOUT_16x9'; // or 'LAYOUT_16x10', 'LAYOUT_4x3', 'LAYOUT_WIDE'
|
||||
pres.author = 'Your Name';
|
||||
pres.title = 'Presentation Title';
|
||||
|
||||
let slide = pres.addSlide();
|
||||
slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });
|
||||
slide.addText('Hello World!', { x: 0.5, y: 0.5, fontSize: 36, color: '363636' });
|
||||
|
||||
pres.writeFile({ fileName: "Presentation.pptx" });
|
||||
pres.writeFile({ fileName: 'Presentation.pptx' });
|
||||
```
|
||||
|
||||
## Layout Dimensions
|
||||
|
||||
Slide dimensions (coordinates in inches):
|
||||
|
||||
- `LAYOUT_16x9`: 10" × 5.625" (default)
|
||||
- `LAYOUT_16x10`: 10" × 6.25"
|
||||
- `LAYOUT_4x3`: 10" × 7.5"
|
||||
@@ -30,31 +31,48 @@ Slide dimensions (coordinates in inches):
|
||||
|
||||
```javascript
|
||||
// Basic text
|
||||
slide.addText("Simple Text", {
|
||||
x: 1, y: 1, w: 8, h: 2, fontSize: 24, fontFace: "Arial",
|
||||
color: "363636", bold: true, align: "center", valign: "middle"
|
||||
slide.addText('Simple Text', {
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 8,
|
||||
h: 2,
|
||||
fontSize: 24,
|
||||
fontFace: 'Arial',
|
||||
color: '363636',
|
||||
bold: true,
|
||||
align: 'center',
|
||||
valign: 'middle',
|
||||
});
|
||||
|
||||
// Character spacing (use charSpacing, not letterSpacing which is silently ignored)
|
||||
slide.addText("SPACED TEXT", { x: 1, y: 1, w: 8, h: 1, charSpacing: 6 });
|
||||
slide.addText('SPACED TEXT', { x: 1, y: 1, w: 8, h: 1, charSpacing: 6 });
|
||||
|
||||
// Rich text arrays
|
||||
slide.addText([
|
||||
{ text: "Bold ", options: { bold: true } },
|
||||
{ text: "Italic ", options: { italic: true } }
|
||||
], { x: 1, y: 3, w: 8, h: 1 });
|
||||
slide.addText(
|
||||
[
|
||||
{ text: 'Bold ', options: { bold: true } },
|
||||
{ text: 'Italic ', options: { italic: true } },
|
||||
],
|
||||
{ x: 1, y: 3, w: 8, h: 1 },
|
||||
);
|
||||
|
||||
// Multi-line text (requires breakLine: true)
|
||||
slide.addText([
|
||||
{ text: "Line 1", options: { breakLine: true } },
|
||||
{ text: "Line 2", options: { breakLine: true } },
|
||||
{ text: "Line 3" } // Last item doesn't need breakLine
|
||||
], { x: 0.5, y: 0.5, w: 8, h: 2 });
|
||||
slide.addText(
|
||||
[
|
||||
{ text: 'Line 1', options: { breakLine: true } },
|
||||
{ text: 'Line 2', options: { breakLine: true } },
|
||||
{ text: 'Line 3' }, // Last item doesn't need breakLine
|
||||
],
|
||||
{ x: 0.5, y: 0.5, w: 8, h: 2 },
|
||||
);
|
||||
|
||||
// Text box margin (internal padding)
|
||||
slide.addText("Title", {
|
||||
x: 0.5, y: 0.3, w: 9, h: 0.6,
|
||||
margin: 0 // Use 0 when aligning text with other elements like shapes or icons
|
||||
slide.addText('Title', {
|
||||
x: 0.5,
|
||||
y: 0.3,
|
||||
w: 9,
|
||||
h: 0.6,
|
||||
margin: 0, // Use 0 when aligning text with other elements like shapes or icons
|
||||
});
|
||||
```
|
||||
|
||||
@@ -86,47 +104,65 @@ slide.addText("• First item", { ... }); // Creates double bullets
|
||||
|
||||
```javascript
|
||||
slide.addShape(pres.shapes.RECTANGLE, {
|
||||
x: 0.5, y: 0.8, w: 1.5, h: 3.0,
|
||||
fill: { color: "FF0000" }, line: { color: "000000", width: 2 }
|
||||
x: 0.5,
|
||||
y: 0.8,
|
||||
w: 1.5,
|
||||
h: 3.0,
|
||||
fill: { color: 'FF0000' },
|
||||
line: { color: '000000', width: 2 },
|
||||
});
|
||||
|
||||
slide.addShape(pres.shapes.OVAL, { x: 4, y: 1, w: 2, h: 2, fill: { color: "0000FF" } });
|
||||
slide.addShape(pres.shapes.OVAL, { x: 4, y: 1, w: 2, h: 2, fill: { color: '0000FF' } });
|
||||
|
||||
slide.addShape(pres.shapes.LINE, {
|
||||
x: 1, y: 3, w: 5, h: 0, line: { color: "FF0000", width: 3, dashType: "dash" }
|
||||
x: 1,
|
||||
y: 3,
|
||||
w: 5,
|
||||
h: 0,
|
||||
line: { color: 'FF0000', width: 3, dashType: 'dash' },
|
||||
});
|
||||
|
||||
// With transparency
|
||||
slide.addShape(pres.shapes.RECTANGLE, {
|
||||
x: 1, y: 1, w: 3, h: 2,
|
||||
fill: { color: "0088CC", transparency: 50 }
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 3,
|
||||
h: 2,
|
||||
fill: { color: '0088CC', transparency: 50 },
|
||||
});
|
||||
|
||||
// Rounded rectangle (rectRadius only works with ROUNDED_RECTANGLE, not RECTANGLE)
|
||||
// ⚠️ Don't pair with rectangular accent overlays — they won't cover rounded corners. Use RECTANGLE instead.
|
||||
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
|
||||
x: 1, y: 1, w: 3, h: 2,
|
||||
fill: { color: "FFFFFF" }, rectRadius: 0.1
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 3,
|
||||
h: 2,
|
||||
fill: { color: 'FFFFFF' },
|
||||
rectRadius: 0.1,
|
||||
});
|
||||
|
||||
// With shadow
|
||||
slide.addShape(pres.shapes.RECTANGLE, {
|
||||
x: 1, y: 1, w: 3, h: 2,
|
||||
fill: { color: "FFFFFF" },
|
||||
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.15 }
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 3,
|
||||
h: 2,
|
||||
fill: { color: 'FFFFFF' },
|
||||
shadow: { type: 'outer', color: '000000', blur: 6, offset: 2, angle: 135, opacity: 0.15 },
|
||||
});
|
||||
```
|
||||
|
||||
Shadow options:
|
||||
|
||||
| Property | Type | Range | Notes |
|
||||
|----------|------|-------|-------|
|
||||
| `type` | string | `"outer"`, `"inner"` | |
|
||||
| `color` | string | 6-char hex (e.g. `"000000"`) | No `#` prefix, no 8-char hex — see Common Pitfalls |
|
||||
| `blur` | number | 0-100 pt | |
|
||||
| `offset` | number | 0-200 pt | **Must be non-negative** — negative values corrupt the file |
|
||||
| `angle` | number | 0-359 degrees | Direction the shadow falls (135 = bottom-right, 270 = upward) |
|
||||
| `opacity` | number | 0.0-1.0 | Use this for transparency, never encode in color string |
|
||||
| Property | Type | Range | Notes |
|
||||
| --------- | ------ | ---------------------------- | ------------------------------------------------------------- |
|
||||
| `type` | string | `"outer"`, `"inner"` | |
|
||||
| `color` | string | 6-char hex (e.g. `"000000"`) | No `#` prefix, no 8-char hex — see Common Pitfalls |
|
||||
| `blur` | number | 0-100 pt | |
|
||||
| `offset` | number | 0-200 pt | **Must be non-negative** — negative values corrupt the file |
|
||||
| `angle` | number | 0-359 degrees | Direction the shadow falls (135 = bottom-right, 270 = upward) |
|
||||
| `opacity` | number | 0.0-1.0 | Use this for transparency, never encode in color string |
|
||||
|
||||
To cast a shadow upward (e.g. on a footer bar), use `angle: 270` with a positive offset — do **not** use a negative offset.
|
||||
|
||||
@@ -140,28 +176,31 @@ To cast a shadow upward (e.g. on a footer bar), use `angle: 270` with a positive
|
||||
|
||||
```javascript
|
||||
// From file path
|
||||
slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 });
|
||||
slide.addImage({ path: 'images/chart.png', x: 1, y: 1, w: 5, h: 3 });
|
||||
|
||||
// From URL
|
||||
slide.addImage({ path: "https://example.com/image.jpg", x: 1, y: 1, w: 5, h: 3 });
|
||||
slide.addImage({ path: 'https://example.com/image.jpg', x: 1, y: 1, w: 5, h: 3 });
|
||||
|
||||
// From base64 (faster, no file I/O)
|
||||
slide.addImage({ data: "image/png;base64,iVBORw0KGgo...", x: 1, y: 1, w: 5, h: 3 });
|
||||
slide.addImage({ data: 'image/png;base64,iVBORw0KGgo...', x: 1, y: 1, w: 5, h: 3 });
|
||||
```
|
||||
|
||||
### Image Options
|
||||
|
||||
```javascript
|
||||
slide.addImage({
|
||||
path: "image.png",
|
||||
x: 1, y: 1, w: 5, h: 3,
|
||||
rotate: 45, // 0-359 degrees
|
||||
rounding: true, // Circular crop
|
||||
transparency: 50, // 0-100
|
||||
flipH: true, // Horizontal flip
|
||||
flipV: false, // Vertical flip
|
||||
altText: "Description", // Accessibility
|
||||
hyperlink: { url: "https://example.com" }
|
||||
path: 'image.png',
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 5,
|
||||
h: 3,
|
||||
rotate: 45, // 0-359 degrees
|
||||
rounding: true, // Circular crop
|
||||
transparency: 50, // 0-100
|
||||
flipH: true, // Horizontal flip
|
||||
flipV: false, // Vertical flip
|
||||
altText: 'Description', // Accessibility
|
||||
hyperlink: { url: 'https://example.com' },
|
||||
});
|
||||
```
|
||||
|
||||
@@ -181,11 +220,13 @@ slide.addImage({
|
||||
### Calculate Dimensions (preserve aspect ratio)
|
||||
|
||||
```javascript
|
||||
const origWidth = 1978, origHeight = 923, maxHeight = 3.0;
|
||||
const origWidth = 1978,
|
||||
origHeight = 923,
|
||||
maxHeight = 3.0;
|
||||
const calcWidth = maxHeight * (origWidth / origHeight);
|
||||
const centerX = (10 - calcWidth) / 2;
|
||||
|
||||
slide.addImage({ path: "image.png", x: centerX, y: 1.2, w: calcWidth, h: maxHeight });
|
||||
slide.addImage({ path: 'image.png', x: centerX, y: 1.2, w: calcWidth, h: maxHeight });
|
||||
```
|
||||
|
||||
### Supported Formats
|
||||
@@ -202,32 +243,35 @@ Use react-icons to generate SVG icons, then rasterize to PNG for universal compa
|
||||
### Setup
|
||||
|
||||
```javascript
|
||||
const React = require("react");
|
||||
const ReactDOMServer = require("react-dom/server");
|
||||
const sharp = require("sharp");
|
||||
const { FaCheckCircle, FaChartLine } = require("react-icons/fa");
|
||||
const React = require('react');
|
||||
const ReactDOMServer = require('react-dom/server');
|
||||
const sharp = require('sharp');
|
||||
const { FaCheckCircle, FaChartLine } = require('react-icons/fa');
|
||||
|
||||
function renderIconSvg(IconComponent, color = "#000000", size = 256) {
|
||||
function renderIconSvg(IconComponent, color = '#000000', size = 256) {
|
||||
return ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(IconComponent, { color, size: String(size) })
|
||||
React.createElement(IconComponent, { color, size: String(size) }),
|
||||
);
|
||||
}
|
||||
|
||||
async function iconToBase64Png(IconComponent, color, size = 256) {
|
||||
const svg = renderIconSvg(IconComponent, color, size);
|
||||
const pngBuffer = await sharp(Buffer.from(svg)).png().toBuffer();
|
||||
return "image/png;base64," + pngBuffer.toString("base64");
|
||||
return 'image/png;base64,' + pngBuffer.toString('base64');
|
||||
}
|
||||
```
|
||||
|
||||
### Add Icon to Slide
|
||||
|
||||
```javascript
|
||||
const iconData = await iconToBase64Png(FaCheckCircle, "#4472C4", 256);
|
||||
const iconData = await iconToBase64Png(FaCheckCircle, '#4472C4', 256);
|
||||
|
||||
slide.addImage({
|
||||
data: iconData,
|
||||
x: 1, y: 1, w: 0.5, h: 0.5 // Size in inches
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 0.5,
|
||||
h: 0.5, // Size in inches
|
||||
});
|
||||
```
|
||||
|
||||
@@ -238,6 +282,7 @@ slide.addImage({
|
||||
Install: `npm install -g react-icons react react-dom sharp`
|
||||
|
||||
Popular icon sets in react-icons:
|
||||
|
||||
- `react-icons/fa` - Font Awesome
|
||||
- `react-icons/md` - Material Design
|
||||
- `react-icons/hi` - Heroicons
|
||||
@@ -249,16 +294,16 @@ Popular icon sets in react-icons:
|
||||
|
||||
```javascript
|
||||
// Solid color
|
||||
slide.background = { color: "F1F1F1" };
|
||||
slide.background = { color: 'F1F1F1' };
|
||||
|
||||
// Color with transparency
|
||||
slide.background = { color: "FF3399", transparency: 50 };
|
||||
slide.background = { color: 'FF3399', transparency: 50 };
|
||||
|
||||
// Image from URL
|
||||
slide.background = { path: "https://example.com/bg.jpg" };
|
||||
slide.background = { path: 'https://example.com/bg.jpg' };
|
||||
|
||||
// Image from base64
|
||||
slide.background = { data: "image/png;base64,iVBORw0KGgo..." };
|
||||
slide.background = { data: 'image/png;base64,iVBORw0KGgo...' };
|
||||
```
|
||||
|
||||
---
|
||||
@@ -266,18 +311,25 @@ slide.background = { data: "image/png;base64,iVBORw0KGgo..." };
|
||||
## Tables
|
||||
|
||||
```javascript
|
||||
slide.addTable([
|
||||
["Header 1", "Header 2"],
|
||||
["Cell 1", "Cell 2"]
|
||||
], {
|
||||
x: 1, y: 1, w: 8, h: 2,
|
||||
border: { pt: 1, color: "999999" }, fill: { color: "F1F1F1" }
|
||||
});
|
||||
slide.addTable(
|
||||
[
|
||||
['Header 1', 'Header 2'],
|
||||
['Cell 1', 'Cell 2'],
|
||||
],
|
||||
{
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 8,
|
||||
h: 2,
|
||||
border: { pt: 1, color: '999999' },
|
||||
fill: { color: 'F1F1F1' },
|
||||
},
|
||||
);
|
||||
|
||||
// Advanced with merged cells
|
||||
let tableData = [
|
||||
[{ text: "Header", options: { fill: { color: "6699CC" }, color: "FFFFFF", bold: true } }, "Cell"],
|
||||
[{ text: "Merged", options: { colspan: 2 } }]
|
||||
[{ text: 'Header', options: { fill: { color: '6699CC' }, color: 'FFFFFF', bold: true } }, 'Cell'],
|
||||
[{ text: 'Merged', options: { colspan: 2 } }],
|
||||
];
|
||||
slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });
|
||||
```
|
||||
@@ -288,22 +340,51 @@ slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });
|
||||
|
||||
```javascript
|
||||
// Bar chart
|
||||
slide.addChart(pres.charts.BAR, [{
|
||||
name: "Sales", labels: ["Q1", "Q2", "Q3", "Q4"], values: [4500, 5500, 6200, 7100]
|
||||
}], {
|
||||
x: 0.5, y: 0.6, w: 6, h: 3, barDir: 'col',
|
||||
showTitle: true, title: 'Quarterly Sales'
|
||||
});
|
||||
slide.addChart(
|
||||
pres.charts.BAR,
|
||||
[
|
||||
{
|
||||
name: 'Sales',
|
||||
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||||
values: [4500, 5500, 6200, 7100],
|
||||
},
|
||||
],
|
||||
{
|
||||
x: 0.5,
|
||||
y: 0.6,
|
||||
w: 6,
|
||||
h: 3,
|
||||
barDir: 'col',
|
||||
showTitle: true,
|
||||
title: 'Quarterly Sales',
|
||||
},
|
||||
);
|
||||
|
||||
// Line chart
|
||||
slide.addChart(pres.charts.LINE, [{
|
||||
name: "Temp", labels: ["Jan", "Feb", "Mar"], values: [32, 35, 42]
|
||||
}], { x: 0.5, y: 4, w: 6, h: 3, lineSize: 3, lineSmooth: true });
|
||||
slide.addChart(
|
||||
pres.charts.LINE,
|
||||
[
|
||||
{
|
||||
name: 'Temp',
|
||||
labels: ['Jan', 'Feb', 'Mar'],
|
||||
values: [32, 35, 42],
|
||||
},
|
||||
],
|
||||
{ x: 0.5, y: 4, w: 6, h: 3, lineSize: 3, lineSmooth: true },
|
||||
);
|
||||
|
||||
// Pie chart
|
||||
slide.addChart(pres.charts.PIE, [{
|
||||
name: "Share", labels: ["A", "B", "Other"], values: [35, 45, 20]
|
||||
}], { x: 7, y: 1, w: 5, h: 4, showPercent: true });
|
||||
slide.addChart(
|
||||
pres.charts.PIE,
|
||||
[
|
||||
{
|
||||
name: 'Share',
|
||||
labels: ['A', 'B', 'Other'],
|
||||
values: [35, 45, 20],
|
||||
},
|
||||
],
|
||||
{ x: 7, y: 1, w: 5, h: 4, showPercent: true },
|
||||
);
|
||||
```
|
||||
|
||||
### Better-Looking Charts
|
||||
@@ -312,26 +393,30 @@ Default charts look dated. Apply these options for a modern, clean appearance:
|
||||
|
||||
```javascript
|
||||
slide.addChart(pres.charts.BAR, chartData, {
|
||||
x: 0.5, y: 1, w: 9, h: 4, barDir: "col",
|
||||
x: 0.5,
|
||||
y: 1,
|
||||
w: 9,
|
||||
h: 4,
|
||||
barDir: 'col',
|
||||
|
||||
// Custom colors (match your presentation palette)
|
||||
chartColors: ["0D9488", "14B8A6", "5EEAD4"],
|
||||
chartColors: ['0D9488', '14B8A6', '5EEAD4'],
|
||||
|
||||
// Clean background
|
||||
chartArea: { fill: { color: "FFFFFF" }, roundedCorners: true },
|
||||
chartArea: { fill: { color: 'FFFFFF' }, roundedCorners: true },
|
||||
|
||||
// Muted axis labels
|
||||
catAxisLabelColor: "64748B",
|
||||
valAxisLabelColor: "64748B",
|
||||
catAxisLabelColor: '64748B',
|
||||
valAxisLabelColor: '64748B',
|
||||
|
||||
// Subtle grid (value axis only)
|
||||
valGridLine: { color: "E2E8F0", size: 0.5 },
|
||||
catGridLine: { style: "none" },
|
||||
valGridLine: { color: 'E2E8F0', size: 0.5 },
|
||||
catGridLine: { style: 'none' },
|
||||
|
||||
// Data labels on bars
|
||||
showValue: true,
|
||||
dataLabelPosition: "outEnd",
|
||||
dataLabelColor: "1E293B",
|
||||
dataLabelPosition: 'outEnd',
|
||||
dataLabelColor: '1E293B',
|
||||
|
||||
// Hide legend for single series
|
||||
showLegend: false,
|
||||
@@ -339,6 +424,7 @@ slide.addChart(pres.charts.BAR, chartData, {
|
||||
```
|
||||
|
||||
**Key styling options:**
|
||||
|
||||
- `chartColors: [...]` - hex colors for series/segments
|
||||
- `chartArea: { fill, border, roundedCorners }` - chart background
|
||||
- `catGridLine/valGridLine: { color, style, size }` - grid lines (`style: "none"` to hide)
|
||||
@@ -351,14 +437,17 @@ slide.addChart(pres.charts.BAR, chartData, {
|
||||
|
||||
```javascript
|
||||
pres.defineSlideMaster({
|
||||
title: 'TITLE_SLIDE', background: { color: '283A5E' },
|
||||
objects: [{
|
||||
placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } }
|
||||
}]
|
||||
title: 'TITLE_SLIDE',
|
||||
background: { color: '283A5E' },
|
||||
objects: [
|
||||
{
|
||||
placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let titleSlide = pres.addSlide({ masterName: "TITLE_SLIDE" });
|
||||
titleSlide.addText("My Title", { placeholder: "title" });
|
||||
let titleSlide = pres.addSlide({ masterName: 'TITLE_SLIDE' });
|
||||
titleSlide.addText('My Title', { placeholder: 'title' });
|
||||
```
|
||||
|
||||
---
|
||||
@@ -368,12 +457,14 @@ titleSlide.addText("My Title", { placeholder: "title" });
|
||||
⚠️ These issues cause file corruption, visual bugs, or broken output. Avoid them.
|
||||
|
||||
1. **NEVER use "#" with hex colors** - causes file corruption
|
||||
|
||||
```javascript
|
||||
color: "FF0000" // ✅ CORRECT
|
||||
color: "#FF0000" // ❌ WRONG
|
||||
color: 'FF0000'; // ✅ CORRECT
|
||||
color: '#FF0000'; // ❌ WRONG
|
||||
```
|
||||
|
||||
2. **NEVER encode opacity in hex color strings** - 8-char colors (e.g., `"00000020"`) corrupt the file. Use the `opacity` property instead.
|
||||
|
||||
```javascript
|
||||
shadow: { type: "outer", blur: 6, offset: 2, color: "00000020" } // ❌ CORRUPTS FILE
|
||||
shadow: { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.12 } // ✅ CORRECT
|
||||
@@ -388,6 +479,7 @@ titleSlide.addText("My Title", { placeholder: "title" });
|
||||
6. **Each presentation needs fresh instance** - don't reuse `pptxgen()` objects
|
||||
|
||||
7. **NEVER reuse option objects across calls** - PptxGenJS mutates objects in-place (e.g. converting shadow values to EMU). Sharing one object between multiple calls corrupts the second shape.
|
||||
|
||||
```javascript
|
||||
const shadow = { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 };
|
||||
slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); // ❌ second call gets already-converted values
|
||||
@@ -399,14 +491,33 @@ titleSlide.addText("My Title", { placeholder: "title" });
|
||||
```
|
||||
|
||||
8. **Don't use `ROUNDED_RECTANGLE` with accent borders** - rectangular overlay bars won't cover rounded corners. Use `RECTANGLE` instead.
|
||||
|
||||
```javascript
|
||||
// ❌ WRONG: Accent bar doesn't cover rounded corners
|
||||
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
|
||||
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });
|
||||
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 3,
|
||||
h: 1.5,
|
||||
fill: { color: 'FFFFFF' },
|
||||
});
|
||||
slide.addShape(pres.shapes.RECTANGLE, {
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 0.08,
|
||||
h: 1.5,
|
||||
fill: { color: '0891B2' },
|
||||
});
|
||||
|
||||
// ✅ CORRECT: Use RECTANGLE for clean alignment
|
||||
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
|
||||
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });
|
||||
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: 'FFFFFF' } });
|
||||
slide.addShape(pres.shapes.RECTANGLE, {
|
||||
x: 1,
|
||||
y: 1,
|
||||
w: 0.08,
|
||||
h: 1.5,
|
||||
fill: { color: '0891B2' },
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user