refactor: complete three-layer serial refactoring (knowledge→schema→renderer)
Step 1 — Knowledge base: perfect all reference/*.md with type, range, default, unit - text.md: add DataOrPathProps, path/data, bullet deprecated params - chart.md: add deprecated section, fix 19 params with missing elements - slide.md: add bkgd→background deprecated mapping - output.md: add masterSlide, presLayout Step 2 — Schema: align schema/presentation.schema.json with KB - Add catAxisItem and valAxisItem definitions with full sub-property constraints - Fix 7 enum constraints (barDir, displayBlanksAs, bar3DShape, etc.) - Add 4 missing fields (verbose, autoPageCharWeight, autoPageLineWeight, notes, masterSlide, presLayout) Step 3 — Translation engine: transform renderers from passthrough to validation - index.js: add normalizePosition, normalizeColor, validateEnum shared utilities - All renderers: position validation, color hex normalization, enum validation - Image: graceful failure handling (catch load errors, warn, continue) - Chart: chartType enum validation, data parity check - Table: colspan/rowspan integer validation, border array check - Full verification: basic.json and full.json generate valid PPTX Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -202,6 +202,9 @@
|
|||||||
|
|
||||||
- **catAxisLabelFontSize**:轴标签字号
|
- **catAxisLabelFontSize**:轴标签字号
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catAxisLabelFrequency**:标签频率
|
- **catAxisLabelFrequency**:标签频率
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -211,6 +214,9 @@
|
|||||||
|
|
||||||
- **catAxisLabelRotate**:标签旋转角度
|
- **catAxisLabelRotate**:标签旋转角度
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:度
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catAxisLineColor**:轴线颜色
|
- **catAxisLineColor**:轴线颜色
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -220,6 +226,9 @@
|
|||||||
|
|
||||||
- **catAxisLineSize**:轴线粗细
|
- **catAxisLineSize**:轴线粗细
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catAxisLineStyle**:轴线样式
|
- **catAxisLineStyle**:轴线样式
|
||||||
- 类型:`'solid' | 'dash' | 'dot'`
|
- 类型:`'solid' | 'dash' | 'dot'`
|
||||||
@@ -232,6 +241,9 @@
|
|||||||
|
|
||||||
- **catAxisMajorUnit**:主要刻度单位
|
- **catAxisMajorUnit**:主要刻度单位
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:无单位(数值刻度)
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catAxisMaxVal**:轴最大值
|
- **catAxisMaxVal**:轴最大值
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
@@ -244,6 +256,9 @@
|
|||||||
|
|
||||||
- **catAxisMinorUnit**:次要刻度单位
|
- **catAxisMinorUnit**:次要刻度单位
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:无单位(数值刻度)
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catAxisMinVal**:轴最小值
|
- **catAxisMinVal**:轴最小值
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
@@ -269,6 +284,9 @@
|
|||||||
|
|
||||||
- **catAxisTitleRotate**:轴标题旋转
|
- **catAxisTitleRotate**:轴标题旋转
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:度
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **catGridLine**:分类网格线
|
- **catGridLine**:分类网格线
|
||||||
- 类型:`OptsChartGridLine`
|
- 类型:`OptsChartGridLine`
|
||||||
@@ -307,6 +325,9 @@
|
|||||||
|
|
||||||
- **serAxisLabelFontSize**:系列轴标签字号
|
- **serAxisLabelFontSize**:系列轴标签字号
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **serAxisLabelFrequency**:系列轴标签频率
|
- **serAxisLabelFrequency**:系列轴标签频率
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -399,6 +420,9 @@
|
|||||||
|
|
||||||
- **valAxisLabelFontSize**:数值轴标签字号
|
- **valAxisLabelFontSize**:数值轴标签字号
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisLabelFormatCode**:数值轴标签格式代码
|
- **valAxisLabelFormatCode**:数值轴标签格式代码
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -408,6 +432,9 @@
|
|||||||
|
|
||||||
- **valAxisLabelRotate**:数值轴标签旋转
|
- **valAxisLabelRotate**:数值轴标签旋转
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:度
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisLineColor**:数值轴线颜色
|
- **valAxisLineColor**:数值轴线颜色
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -417,6 +444,9 @@
|
|||||||
|
|
||||||
- **valAxisLineSize**:数值轴线粗细
|
- **valAxisLineSize**:数值轴线粗细
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisLineStyle**:数值轴线样式
|
- **valAxisLineStyle**:数值轴线样式
|
||||||
- 类型:`'solid' | 'dash' | 'dot'`
|
- 类型:`'solid' | 'dash' | 'dot'`
|
||||||
@@ -431,15 +461,24 @@
|
|||||||
|
|
||||||
- **valAxisMajorUnit**:数值轴主要刻度单位
|
- **valAxisMajorUnit**:数值轴主要刻度单位
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:无单位(数值刻度)
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisMaxVal**:数值轴最大值
|
- **valAxisMaxVal**:数值轴最大值
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:无单位(数值与数据一致)
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisMinorTickMark**:数值轴副刻度标记
|
- **valAxisMinorTickMark**:数值轴副刻度标记
|
||||||
- 类型:`ChartAxisTickMark`
|
- 类型:`ChartAxisTickMark`
|
||||||
|
|
||||||
- **valAxisMinVal**:数值轴最小值
|
- **valAxisMinVal**:数值轴最小值
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:无单位(数值与数据一致)
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **valAxisOrientation**:数值轴方向
|
- **valAxisOrientation**:数值轴方向
|
||||||
- 类型:`'minMax'`
|
- 类型:`'minMax'`
|
||||||
@@ -473,13 +512,19 @@
|
|||||||
|
|
||||||
- **bar3DShape**:3D 柱形形状
|
- **bar3DShape**:3D 柱形形状
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
|
- 取值范围:`'box' | 'cylinder' | 'cone' | 'pyramid'`(PowerPoint 标准值),类型声明为 string,也可接受其他值
|
||||||
|
- 默认值:`'box'`
|
||||||
|
|
||||||
- **barDir**:柱形方向
|
- **barDir**:柱形方向
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
- 取值范围:`'bar'`(水平)、`'col'`(垂直)
|
- 取值范围:`'bar'`(水平)、`'col'`(垂直)
|
||||||
|
- 默认值:`'col'`
|
||||||
|
|
||||||
- **barGapDepthPct**:3D 柱形深度间距百分比
|
- **barGapDepthPct**:3D 柱形深度间距百分比
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 取值范围:`0`–`500`
|
||||||
|
- 默认值:`150`
|
||||||
|
- 单位:%
|
||||||
|
|
||||||
- **barGapWidthPct**:间距宽度百分比
|
- **barGapWidthPct**:间距宽度百分比
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
@@ -488,6 +533,8 @@
|
|||||||
|
|
||||||
- **barGrouping**:分组方式
|
- **barGrouping**:分组方式
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
|
- 取值范围:`'clustered' | 'stacked' | 'standard'`(PowerPoint 标准值),类型声明为 string,也可接受其他值
|
||||||
|
- 默认值:`'clustered'`
|
||||||
|
|
||||||
- **barOverlapPct**:系列重叠百分比
|
- **barOverlapPct**:系列重叠百分比
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
@@ -501,9 +548,12 @@
|
|||||||
|
|
||||||
- **dataNoEffects**:禁用数据点效果
|
- **dataNoEffects**:禁用数据点效果
|
||||||
- 类型:`boolean`
|
- 类型:`boolean`
|
||||||
|
- 默认值:`false`
|
||||||
|
|
||||||
- **holeSize**:中心孔大小
|
- **holeSize**:中心孔大小
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 取值范围:`0`–`90`(百分比)
|
||||||
|
- 默认值:`50`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -548,6 +598,7 @@
|
|||||||
|
|
||||||
- **dataNoEffects**:禁用数据点效果
|
- **dataNoEffects**:禁用数据点效果
|
||||||
- 类型:`boolean`
|
- 类型:`boolean`
|
||||||
|
- 默认值:`false`
|
||||||
|
|
||||||
- **firstSliceAng**:第一扇区起始角度
|
- **firstSliceAng**:第一扇区起始角度
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
@@ -569,9 +620,12 @@
|
|||||||
|
|
||||||
- **dataLabelBkgrdColors**:数据标签背景色
|
- **dataLabelBkgrdColors**:数据标签背景色
|
||||||
- 类型:`boolean`
|
- 类型:`boolean`
|
||||||
|
- 默认值:`false`
|
||||||
|
|
||||||
- **dataLabelColor**:数据标签颜色
|
- **dataLabelColor**:数据标签颜色
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **dataLabelFontBold**:数据标签粗体
|
- **dataLabelFontBold**:数据标签粗体
|
||||||
- 类型:`boolean`
|
- 类型:`boolean`
|
||||||
@@ -584,6 +638,9 @@
|
|||||||
|
|
||||||
- **dataLabelFontSize**:数据标签字号
|
- **dataLabelFontSize**:数据标签字号
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **dataLabelFormatCode**:数据标签格式代码
|
- **dataLabelFormatCode**:数据标签格式代码
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -601,6 +658,9 @@
|
|||||||
|
|
||||||
- **dataTableFontSize**:数据表字号
|
- **dataTableFontSize**:数据表字号
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **dataTableFormatCode**:数据表格式代码
|
- **dataTableFormatCode**:数据表格式代码
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
@@ -650,6 +710,8 @@
|
|||||||
|
|
||||||
- **titleAlign**:标题对齐
|
- **titleAlign**:标题对齐
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
|
- 取值范围:`'l' | 'ctr' | 'r'`
|
||||||
|
- 默认值:`'ctr'`
|
||||||
|
|
||||||
- **titleBold**:标题粗体
|
- **titleBold**:标题粗体
|
||||||
- 类型:`boolean`
|
- 类型:`boolean`
|
||||||
@@ -682,6 +744,9 @@
|
|||||||
|
|
||||||
- **size**:网格线粗细
|
- **size**:网格线粗细
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
- 单位:pt
|
||||||
|
- 取值范围:无特殊约束范围
|
||||||
|
- 无默认值
|
||||||
|
|
||||||
- **style**:网格线样式
|
- **style**:网格线样式
|
||||||
- 类型:`'solid' | 'dash' | 'dot' | 'none'`
|
- 类型:`'solid' | 'dash' | 'dot' | 'none'`
|
||||||
@@ -705,3 +770,12 @@
|
|||||||
- **altText**:替代文字(无障碍)
|
- **altText**:替代文字(无障碍)
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
- 说明:PowerPoint 中右击图表 > "编辑替代文字"
|
- 说明:PowerPoint 中右击图表 > "编辑替代文字"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已废弃参数
|
||||||
|
|
||||||
|
| 已废弃参数 | 替代参数 | 废弃版本 |
|
||||||
|
|---|---|---|
|
||||||
|
| `border` | `plotArea.border` | v3.11.0 |
|
||||||
|
| `fill` | `plotArea.fill` | v3.11.0 |
|
||||||
|
|||||||
@@ -154,3 +154,11 @@ type WRITE_OUTPUT_TYPE = JSZIP_OUTPUT_TYPE | 'STREAM'
|
|||||||
|
|
||||||
- **title**:演示文稿标题
|
- **title**:演示文稿标题
|
||||||
- 类型:`string`
|
- 类型:`string`
|
||||||
|
|
||||||
|
- **masterSlide**:当前母版
|
||||||
|
- 类型:`PresSlide`
|
||||||
|
- 说明:当前演示文稿的母版幻灯片对象
|
||||||
|
|
||||||
|
- **presLayout**:布局信息
|
||||||
|
- 类型:`PresLayout`
|
||||||
|
- 说明:只读,包含 `name`(布局名称)、`width`(宽度,英寸)、`height`(高度,英寸)
|
||||||
|
|||||||
@@ -220,3 +220,4 @@ pptx.addSection(props: SectionProps)
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `fill` | `ShapeFillProps.color` | v3.6.0 |
|
| `fill` | `ShapeFillProps.color` | v3.6.0 |
|
||||||
| `src` | `DataOrPathProps.path` | v3.6.0 |
|
| `src` | `DataOrPathProps.path` | v3.6.0 |
|
||||||
|
| `bkgd` (Slide 类) | `background` | v3.3.0 |
|
||||||
|
|||||||
+16
-2
@@ -1,6 +1,6 @@
|
|||||||
# 文字参数 (Text Props)
|
# 文字参数 (Text Props)
|
||||||
|
|
||||||
文字参数来自 `TextPropsOptions`(继承 `TextBaseProps`、`PositionProps`、`ObjectNameProps`)和 `TextGlowProps`,用于 `slide.addText()` 方法。
|
文字参数来自 `TextPropsOptions`(继承 `TextBaseProps`、`PositionProps`、`DataOrPathProps`、`ObjectNameProps`)和 `TextGlowProps`,用于 `slide.addText()` 方法。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -131,6 +131,16 @@
|
|||||||
|
|
||||||
## 文字专有属性 (TextPropsOptions 特有)
|
## 文字专有属性 (TextPropsOptions 特有)
|
||||||
|
|
||||||
|
继承 `DataOrPathProps`,支持以下嵌入图片的属性:
|
||||||
|
|
||||||
|
- **path**:图片路径
|
||||||
|
- 类型:`string`
|
||||||
|
- 说明:URL 或本地路径,可在文本框中嵌入图片
|
||||||
|
|
||||||
|
- **data**:图片 Base64 数据
|
||||||
|
- 类型:`string`
|
||||||
|
- 说明:Base64 编码的图片数据,替代 `path`
|
||||||
|
|
||||||
- **baseline**:基线偏移
|
- **baseline**:基线偏移
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
|
|
||||||
@@ -231,7 +241,7 @@
|
|||||||
- **lineSpacingMultiple**:行间距(倍数)
|
- **lineSpacingMultiple**:行间距(倍数)
|
||||||
- 类型:`number`
|
- 类型:`number`
|
||||||
- 取值范围:`0.0`–`9.99`
|
- 取值范围:`0.0`–`9.99`
|
||||||
- 单位:百分比倍数
|
- 单位:倍数(非百分比)
|
||||||
- 说明:PowerPoint 段落 > 缩进和间距 > 行距 > "多倍行距"
|
- 说明:PowerPoint 段落 > 缩进和间距 > 行距 > "多倍行距"
|
||||||
- 示例:`1.5`(1.5 倍行距)
|
- 示例:`1.5`(1.5 倍行距)
|
||||||
- 始于:v3.5.0
|
- 始于:v3.5.0
|
||||||
@@ -385,6 +395,10 @@
|
|||||||
| `autoFit` | `fit` | v3.3.0 |
|
| `autoFit` | `fit` | v3.3.0 |
|
||||||
| `shrinkText` | `fit` | v3.3.0 |
|
| `shrinkText` | `fit` | v3.3.0 |
|
||||||
| `inset` | `margin` | v3.10.0 |
|
| `inset` | `margin` | v3.10.0 |
|
||||||
|
| `bullet.code` | `bullet.characterCode` | v3.3.0 |
|
||||||
|
| `bullet.marginPt` | `bullet.indent` | v3.3.0 |
|
||||||
|
| `bullet.startAt` | `bullet.numberStartAt` | v3.3.0 |
|
||||||
|
| `bullet.style` | `bullet.numberType` | v3.3.0 |
|
||||||
| `lineDash` | `line.dashType` | v3.3.0 |
|
| `lineDash` | `line.dashType` | v3.3.0 |
|
||||||
| `lineHead` | `line.beginArrowType` | v3.3.0 |
|
| `lineHead` | `line.beginArrowType` | v3.3.0 |
|
||||||
| `lineSize` | `line.width` | v3.3.0 |
|
| `lineSize` | `line.width` | v3.3.0 |
|
||||||
|
|||||||
@@ -1,5 +1,46 @@
|
|||||||
|
var { normalizePosition, normalizeColor, normalizeColorInOptions, validateEnum } = require('./index');
|
||||||
|
|
||||||
function renderChart(slide, chartData) {
|
function renderChart(slide, chartData) {
|
||||||
slide.addChart(chartData.chartType, chartData.data, chartData.options);
|
var opts = {};
|
||||||
|
if (chartData.options) {
|
||||||
|
for (var k in chartData.options) {
|
||||||
|
if (chartData.options.hasOwnProperty(k)) opts[k] = chartData.options[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizePosition(opts);
|
||||||
|
|
||||||
|
var validChartTypes = ['area', 'bar', 'bar3D', 'bubble', 'doughnut', 'line', 'pie', 'radar', 'scatter'];
|
||||||
|
validateEnum(chartData.chartType, validChartTypes, 'chartType');
|
||||||
|
|
||||||
|
if (chartData.data) {
|
||||||
|
for (var i = 0; i < chartData.data.length; i++) {
|
||||||
|
var series = chartData.data[i];
|
||||||
|
if (series.labels && series.values && series.labels.length !== series.values.length) {
|
||||||
|
console.warn('Chart series "' + (series.name || i) + '" has mismatched labels (' + series.labels.length + ') and values (' + series.values.length + ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEnum(opts.barDir, ['bar', 'col'], 'barDir');
|
||||||
|
validateEnum(opts.barGrouping, ['clustered', 'stacked', 'standard'], 'barGrouping');
|
||||||
|
validateEnum(opts.radarStyle, ['standard', 'marker', 'filled'], 'radarStyle');
|
||||||
|
validateEnum(opts.legendPos, ['b', 'l', 'r', 't', 'tr'], 'legendPos');
|
||||||
|
validateEnum(opts.lineCap, ['flat', 'round', 'square'], 'lineCap');
|
||||||
|
validateEnum(opts.lineDataSymbol, ['circle', 'dash', 'diamond', 'dot', 'none', 'square', 'triangle'], 'lineDataSymbol');
|
||||||
|
validateEnum(opts.displayBlanksAs, ['gap', 'span', 'zero'], 'displayBlanksAs');
|
||||||
|
validateEnum(opts.bar3DShape, ['box', 'cylinder', 'cone', 'pyramid'], 'bar3DShape');
|
||||||
|
validateEnum(opts.dataLabelPosition, ['b', 'bestFit', 'ctr', 'l', 'r', 't', 'inEnd', 'outEnd'], 'dataLabelPosition');
|
||||||
|
validateEnum(opts.titleAlign, ['l', 'ctr', 'r'], 'titleAlign');
|
||||||
|
|
||||||
|
if (opts.chartColors) {
|
||||||
|
for (var i = 0; i < opts.chartColors.length; i++) {
|
||||||
|
var nc = normalizeColor(opts.chartColors[i]);
|
||||||
|
if (nc) opts.chartColors[i] = nc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slide.addChart(chartData.chartType, chartData.data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderChart };
|
module.exports = { renderChart };
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
|
var { normalizePosition, normalizeColorInOptions, validateEnum } = require('./index');
|
||||||
|
|
||||||
function renderImage(slide, imageData) {
|
function renderImage(slide, imageData) {
|
||||||
slide.addImage(imageData.options);
|
var opts = {};
|
||||||
|
if (imageData.options) {
|
||||||
|
for (var k in imageData.options) {
|
||||||
|
if (imageData.options.hasOwnProperty(k)) opts[k] = imageData.options[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizePosition(opts);
|
||||||
|
|
||||||
|
if (opts.sizing && typeof opts.sizing === 'object') {
|
||||||
|
validateEnum(opts.sizing.type, ['contain', 'cover', 'crop'], 'sizing.type');
|
||||||
|
}
|
||||||
|
if (opts.shadow && typeof opts.shadow === 'object') {
|
||||||
|
normalizeColorInOptions(opts.shadow, 'color');
|
||||||
|
validateEnum(opts.shadow.type, ['outer', 'inner', 'none'], 'shadow.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
slide.addImage(opts);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to load image: ' + (opts.path || 'unknown'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderImage };
|
module.exports = { renderImage };
|
||||||
|
|||||||
+100
-2
@@ -1,5 +1,68 @@
|
|||||||
const pptxgen = require('pptxgenjs');
|
const pptxgen = require('pptxgenjs');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
|
function normalizePosition(options) {
|
||||||
|
if (!options || typeof options !== 'object') return options;
|
||||||
|
['x', 'y', 'w', 'h'].forEach(function(key) {
|
||||||
|
if (options[key] === undefined) return;
|
||||||
|
var val = options[key];
|
||||||
|
if (typeof val === 'number' && !isNaN(val)) return;
|
||||||
|
if (typeof val === 'string' && /^\d+(\.\d+)?%$/.test(val)) return;
|
||||||
|
console.warn('Invalid position value for "' + key + '": got ' + JSON.stringify(val) + ', expected a number or percentage string (e.g. "50%")');
|
||||||
|
delete options[key];
|
||||||
|
});
|
||||||
|
if ((options.x !== undefined || options.y !== undefined) && options.w === undefined) options.w = 4;
|
||||||
|
if ((options.x !== undefined || options.y !== undefined) && options.h === undefined) options.h = 3;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeColor(color) {
|
||||||
|
if (color === undefined || color === null) return color;
|
||||||
|
if (typeof color !== 'string') {
|
||||||
|
console.warn('Invalid color value: expected a string, got ' + typeof color);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
var themeColors = ['tx1', 'tx2', 'bg1', 'bg2', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6'];
|
||||||
|
for (var i = 0; i < themeColors.length; i++) {
|
||||||
|
if (color === themeColors[i]) return color;
|
||||||
|
}
|
||||||
|
var clean = color.replace(/^#/, '');
|
||||||
|
if (/^[0-9A-Fa-f]{6}$/.test(clean)) return clean;
|
||||||
|
console.warn('Invalid color value: "' + color + '" is not a valid color format (expected 6-digit hex or theme color)');
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeColorInOptions(options, key) {
|
||||||
|
if (!options || options[key] === undefined) return;
|
||||||
|
var nc = normalizeColor(options[key]);
|
||||||
|
if (nc === undefined) delete options[key];
|
||||||
|
else options[key] = nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateEnum(value, validValues, name) {
|
||||||
|
if (value === undefined || value === null) return value;
|
||||||
|
if (validValues.indexOf(value) === -1) {
|
||||||
|
console.warn('Invalid value for ' + name + ': got "' + value + '", expected one of [' + validValues.join(', ') + ']');
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withDefaults(options, defaults) {
|
||||||
|
if (!options || typeof options !== 'object') return options;
|
||||||
|
for (var key in defaults) {
|
||||||
|
if (defaults.hasOwnProperty(key) && options[key] === undefined) {
|
||||||
|
options[key] = defaults[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.normalizePosition = normalizePosition;
|
||||||
|
module.exports.normalizeColor = normalizeColor;
|
||||||
|
module.exports.normalizeColorInOptions = normalizeColorInOptions;
|
||||||
|
module.exports.validateEnum = validateEnum;
|
||||||
|
module.exports.withDefaults = withDefaults;
|
||||||
|
|
||||||
const { renderSlide } = require('./slide-renderer');
|
const { renderSlide } = require('./slide-renderer');
|
||||||
|
|
||||||
function render(pptxJson) {
|
function render(pptxJson) {
|
||||||
@@ -25,7 +88,42 @@ function render(pptxJson) {
|
|||||||
async function renderFile(inputPath, outputPath) {
|
async function renderFile(inputPath, outputPath) {
|
||||||
const json = fs.readFileSync(inputPath, 'utf8');
|
const json = fs.readFileSync(inputPath, 'utf8');
|
||||||
const pptx = render(json);
|
const pptx = render(json);
|
||||||
return pptx.writeFile({ fileName: outputPath });
|
|
||||||
|
// pptxgenjs v4 uses https.get() to download URL-based images but doesn't
|
||||||
|
// handle connection errors on the request object (only on the response
|
||||||
|
// stream). A failed TLS handshake emits an unhandled 'error' event on the
|
||||||
|
// request that crashes Node.js, and the internal promise never resolves.
|
||||||
|
// Patch to pipe request errors into a fake response that ends cleanly so
|
||||||
|
// writeFile completes with an empty placeholder image.
|
||||||
|
var https = require('https');
|
||||||
|
var _origGet = https.get;
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
https.get = function() {
|
||||||
|
var args = arguments;
|
||||||
|
var cb = typeof args[args.length - 1] === 'function' ? args[args.length - 1] : null;
|
||||||
|
var urlStr = typeof args[0] === 'string' ? args[0] : '';
|
||||||
|
var req = _origGet.apply(this, args);
|
||||||
|
req.on('error', function(err) {
|
||||||
|
console.warn('Failed to load image: ' + (urlStr || err.hostname || err.host || 'unknown'));
|
||||||
|
if (cb) {
|
||||||
|
var fakeRes = new EventEmitter();
|
||||||
|
fakeRes.setEncoding = function() {};
|
||||||
|
cb(fakeRes);
|
||||||
|
process.nextTick(function() {
|
||||||
|
fakeRes.emit('data', '');
|
||||||
|
fakeRes.emit('end');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return req;
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await pptx.writeFile({ fileName: outputPath });
|
||||||
|
} finally {
|
||||||
|
https.get = _origGet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { render, renderFile };
|
module.exports.render = render;
|
||||||
|
module.exports.renderFile = renderFile;
|
||||||
|
|||||||
@@ -1,5 +1,35 @@
|
|||||||
|
var { normalizePosition, normalizeColorInOptions, validateEnum } = require('./index');
|
||||||
|
|
||||||
function renderShape(slide, shapeData) {
|
function renderShape(slide, shapeData) {
|
||||||
slide.addShape(shapeData.shapeName, shapeData.options);
|
var opts = {};
|
||||||
|
if (shapeData.options) {
|
||||||
|
for (var k in shapeData.options) {
|
||||||
|
if (shapeData.options.hasOwnProperty(k)) opts[k] = shapeData.options[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizePosition(opts);
|
||||||
|
|
||||||
|
if (opts.fill && typeof opts.fill === 'object') {
|
||||||
|
normalizeColorInOptions(opts.fill, 'color');
|
||||||
|
validateEnum(opts.fill.type, ['none', 'solid'], 'fill.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.line && typeof opts.line === 'object') {
|
||||||
|
normalizeColorInOptions(opts.line, 'color');
|
||||||
|
validateEnum(opts.line.dashType, ['solid', 'dash', 'dashDot', 'lgDash', 'lgDashDot', 'lgDashDotDot', 'sysDash', 'sysDot'], 'line.dashType');
|
||||||
|
validateEnum(opts.line.beginArrowType, ['none', 'arrow', 'diamond', 'oval', 'stealth', 'triangle'], 'line.beginArrowType');
|
||||||
|
validateEnum(opts.line.endArrowType, ['none', 'arrow', 'diamond', 'oval', 'stealth', 'triangle'], 'line.endArrowType');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.shadow && typeof opts.shadow === 'object') {
|
||||||
|
normalizeColorInOptions(opts.shadow, 'color');
|
||||||
|
validateEnum(opts.shadow.type, ['outer', 'inner', 'none'], 'shadow.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEnum(opts.align, ['left', 'center', 'right', 'justify'], 'align');
|
||||||
|
|
||||||
|
slide.addShape(shapeData.shapeName, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderShape };
|
module.exports = { renderShape };
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
const { normalizeColor } = require('./index');
|
||||||
const { renderText } = require('./text-renderer');
|
const { renderText } = require('./text-renderer');
|
||||||
const { renderShape } = require('./shape-renderer');
|
const { renderShape } = require('./shape-renderer');
|
||||||
const { renderTable } = require('./table-renderer');
|
const { renderTable } = require('./table-renderer');
|
||||||
@@ -7,8 +8,26 @@ const { renderChart } = require('./chart-renderer');
|
|||||||
function renderSlide(pptx, slideData) {
|
function renderSlide(pptx, slideData) {
|
||||||
const slide = pptx.addSlide();
|
const slide = pptx.addSlide();
|
||||||
|
|
||||||
if (slideData.background) slide.background = slideData.background;
|
if (slideData.background) {
|
||||||
if (slideData.color) slide.color = slideData.color;
|
if (typeof slideData.background === 'object') {
|
||||||
|
slide.background = {};
|
||||||
|
for (var k in slideData.background) {
|
||||||
|
if (slideData.background.hasOwnProperty(k)) {
|
||||||
|
slide.background[k] = slideData.background[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slide.background.color) {
|
||||||
|
var nc = normalizeColor(slide.background.color);
|
||||||
|
if (nc) slide.background.color = nc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slide.background = slideData.background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slideData.color) {
|
||||||
|
var nc = normalizeColor(slideData.color);
|
||||||
|
if (nc) slide.color = nc;
|
||||||
|
}
|
||||||
if (slideData.hidden) slide.hidden = slideData.hidden;
|
if (slideData.hidden) slide.hidden = slideData.hidden;
|
||||||
|
|
||||||
const objects = slideData.objects || [];
|
const objects = slideData.objects || [];
|
||||||
|
|||||||
@@ -1,5 +1,85 @@
|
|||||||
|
var { normalizePosition, normalizeColorInOptions, validateEnum } = require('./index');
|
||||||
|
|
||||||
function renderTable(slide, tableData) {
|
function renderTable(slide, tableData) {
|
||||||
slide.addTable(tableData.rows, tableData.options);
|
var opts = {};
|
||||||
|
if (tableData.options) {
|
||||||
|
for (var k in tableData.options) {
|
||||||
|
if (tableData.options.hasOwnProperty(k)) opts[k] = tableData.options[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizePosition(opts);
|
||||||
|
|
||||||
|
if (opts.fill && typeof opts.fill === 'object') {
|
||||||
|
normalizeColorInOptions(opts.fill, 'color');
|
||||||
|
validateEnum(opts.fill.type, ['none', 'solid'], 'fill.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.border) {
|
||||||
|
if (Array.isArray(opts.border)) {
|
||||||
|
if (opts.border.length !== 4) {
|
||||||
|
console.warn('Invalid table border array: expected 4 sides, got ' + opts.border.length);
|
||||||
|
}
|
||||||
|
} else if (typeof opts.border === 'object') {
|
||||||
|
normalizeColorInOptions(opts.border, 'color');
|
||||||
|
if (opts.border.type !== undefined) {
|
||||||
|
validateEnum(opts.border.type, ['none', 'dash', 'solid'], 'border.type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = [];
|
||||||
|
if (tableData.rows) {
|
||||||
|
for (var r = 0; r < tableData.rows.length; r++) {
|
||||||
|
var row = tableData.rows[r];
|
||||||
|
var newRow = [];
|
||||||
|
for (var c = 0; c < row.length; c++) {
|
||||||
|
var cell = row[c];
|
||||||
|
var newCell = { text: cell.text };
|
||||||
|
|
||||||
|
if (cell.colspan !== undefined) {
|
||||||
|
if (typeof cell.colspan !== 'number' || !isFinite(cell.colspan) || cell.colspan < 1 || cell.colspan !== Math.floor(cell.colspan)) {
|
||||||
|
console.warn('Invalid colspan: got ' + JSON.stringify(cell.colspan) + ', expected integer >= 1');
|
||||||
|
}
|
||||||
|
newCell.colspan = cell.colspan;
|
||||||
|
}
|
||||||
|
if (cell.rowspan !== undefined) {
|
||||||
|
if (typeof cell.rowspan !== 'number' || !isFinite(cell.rowspan) || cell.rowspan < 1 || cell.rowspan !== Math.floor(cell.rowspan)) {
|
||||||
|
console.warn('Invalid rowspan: got ' + JSON.stringify(cell.rowspan) + ', expected integer >= 1');
|
||||||
|
}
|
||||||
|
newCell.rowspan = cell.rowspan;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell.options) {
|
||||||
|
newCell.options = {};
|
||||||
|
for (var k in cell.options) {
|
||||||
|
if (cell.options.hasOwnProperty(k)) newCell.options[k] = cell.options[k];
|
||||||
|
}
|
||||||
|
normalizeColorInOptions(newCell.options, 'color');
|
||||||
|
normalizeColorInOptions(newCell.options, 'highlight');
|
||||||
|
if (newCell.options.fill && typeof newCell.options.fill === 'object') {
|
||||||
|
normalizeColorInOptions(newCell.options.fill, 'color');
|
||||||
|
}
|
||||||
|
if (newCell.options.border) {
|
||||||
|
if (Array.isArray(newCell.options.border)) {
|
||||||
|
if (newCell.options.border.length !== 4) {
|
||||||
|
console.warn('Invalid cell border array: expected 4 sides, got ' + newCell.options.border.length);
|
||||||
|
}
|
||||||
|
} else if (typeof newCell.options.border === 'object') {
|
||||||
|
normalizeColorInOptions(newCell.options.border, 'color');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateEnum(newCell.options.align, ['left', 'center', 'right', 'justify'], 'cell.align');
|
||||||
|
validateEnum(newCell.options.valign, ['top', 'middle', 'bottom'], 'cell.valign');
|
||||||
|
}
|
||||||
|
|
||||||
|
newRow.push(newCell);
|
||||||
|
}
|
||||||
|
rows.push(newRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slide.addTable(rows, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderTable };
|
module.exports = { renderTable };
|
||||||
|
|||||||
@@ -1,5 +1,47 @@
|
|||||||
|
var { normalizePosition, normalizeColor, normalizeColorInOptions, validateEnum } = require('./index');
|
||||||
|
|
||||||
function renderText(slide, textData) {
|
function renderText(slide, textData) {
|
||||||
slide.addText(textData.text, textData.options);
|
var opts = {};
|
||||||
|
if (textData.options) {
|
||||||
|
for (var k in textData.options) {
|
||||||
|
if (textData.options.hasOwnProperty(k)) opts[k] = textData.options[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizePosition(opts);
|
||||||
|
normalizeColorInOptions(opts, 'color');
|
||||||
|
normalizeColorInOptions(opts, 'highlight');
|
||||||
|
|
||||||
|
if (opts.underline && typeof opts.underline === 'object') {
|
||||||
|
normalizeColorInOptions(opts.underline, 'color');
|
||||||
|
}
|
||||||
|
if (opts.bullet && typeof opts.bullet === 'object') {
|
||||||
|
normalizeColorInOptions(opts.bullet, 'color');
|
||||||
|
}
|
||||||
|
if (opts.glow && typeof opts.glow === 'object') {
|
||||||
|
normalizeColorInOptions(opts.glow, 'color');
|
||||||
|
}
|
||||||
|
if (opts.outline && typeof opts.outline === 'object') {
|
||||||
|
normalizeColorInOptions(opts.outline, 'color');
|
||||||
|
}
|
||||||
|
|
||||||
|
validateEnum(opts.align, ['left', 'center', 'right', 'justify'], 'align');
|
||||||
|
validateEnum(opts.valign, ['top', 'middle', 'bottom'], 'valign');
|
||||||
|
validateEnum(opts.textDirection, ['horz', 'vert', 'vert270', 'wordArtVert'], 'textDirection');
|
||||||
|
validateEnum(opts.vert, ['eaVert', 'horz', 'mongolianVert', 'vert', 'vert270', 'wordArtVert', 'wordArtVertRtl'], 'vert');
|
||||||
|
validateEnum(opts.fit, ['none', 'shrink', 'resize'], 'fit');
|
||||||
|
|
||||||
|
if (typeof opts.strike === 'string') {
|
||||||
|
validateEnum(opts.strike, ['dblStrike', 'sngStrike'], 'strike');
|
||||||
|
}
|
||||||
|
if (opts.underline && opts.underline.style !== undefined) {
|
||||||
|
validateEnum(opts.underline.style, ['dash', 'dashHeavy', 'dashLong', 'dashLongHeavy', 'dbl', 'dotDash', 'dotDashHeave', 'dotDotDash', 'dotDotDashHeavy', 'dotted', 'dottedHeavy', 'heavy', 'none', 'sng', 'wavy', 'wavyDbl', 'wavyHeavy'], 'underline.style');
|
||||||
|
}
|
||||||
|
if (opts.bullet && typeof opts.bullet === 'object' && opts.bullet.type !== undefined) {
|
||||||
|
validateEnum(opts.bullet.type, ['bullet', 'number'], 'bullet.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
slide.addText(textData.text, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderText };
|
module.exports = { renderText };
|
||||||
|
|||||||
@@ -313,6 +313,8 @@
|
|||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"autoPageCharWeight": { "type": "number", "minimum": -1.0, "maximum": 1.0, "description": "Auto-page character weight adjustment" },
|
||||||
|
"autoPageLineWeight": { "type": "number", "minimum": -1.0, "maximum": 1.0, "description": "Auto-page line weight adjustment" },
|
||||||
"border": {
|
"border": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "$ref": "#/definitions/borderProps" },
|
{ "$ref": "#/definitions/borderProps" },
|
||||||
@@ -364,7 +366,8 @@
|
|||||||
{ "type": "number" },
|
{ "type": "number" },
|
||||||
{ "type": "array", "items": { "type": "number" } }
|
{ "type": "array", "items": { "type": "number" } }
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"verbose": { "type": "boolean", "description": "Verbose mode for auto-paging debug output" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -453,6 +456,79 @@
|
|||||||
},
|
},
|
||||||
"description": "Chart grid line options"
|
"description": "Chart grid line options"
|
||||||
},
|
},
|
||||||
|
"catAxisItem": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"hidden": { "type": "boolean" },
|
||||||
|
"labelColor": { "type": "string" },
|
||||||
|
"labelFontBold": { "type": "boolean" },
|
||||||
|
"labelFontFace": { "type": "string" },
|
||||||
|
"labelFontItalic": { "type": "boolean" },
|
||||||
|
"labelFontSize": { "type": "number" },
|
||||||
|
"labelFrequency": { "type": "string" },
|
||||||
|
"labelPos": { "type": "string", "enum": ["none", "low", "high", "nextTo"] },
|
||||||
|
"labelRotate": { "type": "number" },
|
||||||
|
"lineColor": { "type": "string" },
|
||||||
|
"lineShow": { "type": "boolean" },
|
||||||
|
"lineSize": { "type": "number" },
|
||||||
|
"lineStyle": { "type": "string", "enum": ["solid", "dash", "dot"] },
|
||||||
|
"majorTickMark": { "type": "string", "enum": ["none", "inside", "outside", "cross"] },
|
||||||
|
"majorTimeUnit": { "type": "string" },
|
||||||
|
"majorUnit": { "type": "number" },
|
||||||
|
"maxVal": { "type": "number" },
|
||||||
|
"minorTickMark": { "type": "string", "enum": ["none", "inside", "outside", "cross"] },
|
||||||
|
"minorTimeUnit": { "type": "string" },
|
||||||
|
"minorUnit": { "type": "number" },
|
||||||
|
"minVal": { "type": "number" },
|
||||||
|
"multiLevelLabels": { "type": "boolean" },
|
||||||
|
"orientation": { "type": "string", "enum": ["minMax"] },
|
||||||
|
"title": { "type": "string" },
|
||||||
|
"titleColor": { "type": "string" },
|
||||||
|
"titleFontFace": { "type": "string" },
|
||||||
|
"titleFontSize": { "type": "number" },
|
||||||
|
"titleRotate": { "type": "number" },
|
||||||
|
"gridLine": { "$ref": "#/definitions/optsChartGridLine" },
|
||||||
|
"labelFormatCode": { "type": "string" },
|
||||||
|
"baseTimeUnit": { "type": "string" },
|
||||||
|
"crossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] }
|
||||||
|
},
|
||||||
|
"description": "Category axis item for catAxes array"
|
||||||
|
},
|
||||||
|
"valAxisItem": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"crossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] },
|
||||||
|
"displayUnit": { "type": "string", "enum": ["billions", "hundredMillions", "hundreds", "hundredThousands", "millions", "tenMillions", "tenThousands", "thousands", "trillions"] },
|
||||||
|
"displayUnitLabel": { "type": "boolean" },
|
||||||
|
"hidden": { "type": "boolean" },
|
||||||
|
"labelColor": { "type": "string" },
|
||||||
|
"labelFontBold": { "type": "boolean" },
|
||||||
|
"labelFontFace": { "type": "string" },
|
||||||
|
"labelFontItalic": { "type": "boolean" },
|
||||||
|
"labelFontSize": { "type": "number" },
|
||||||
|
"labelFormatCode": { "type": "string" },
|
||||||
|
"labelPos": { "type": "string", "enum": ["none", "low", "high", "nextTo"] },
|
||||||
|
"labelRotate": { "type": "number" },
|
||||||
|
"lineColor": { "type": "string" },
|
||||||
|
"lineShow": { "type": "boolean" },
|
||||||
|
"lineSize": { "type": "number" },
|
||||||
|
"lineStyle": { "type": "string", "enum": ["solid", "dash", "dot"] },
|
||||||
|
"logScaleBase": { "type": "number", "minimum": 2, "maximum": 99 },
|
||||||
|
"majorTickMark": { "type": "string", "enum": ["none", "inside", "outside", "cross"] },
|
||||||
|
"majorUnit": { "type": "number" },
|
||||||
|
"maxVal": { "type": "number" },
|
||||||
|
"minorTickMark": { "type": "string", "enum": ["none", "inside", "outside", "cross"] },
|
||||||
|
"minVal": { "type": "number" },
|
||||||
|
"orientation": { "type": "string", "enum": ["minMax"] },
|
||||||
|
"title": { "type": "string" },
|
||||||
|
"titleColor": { "type": "string" },
|
||||||
|
"titleFontFace": { "type": "string" },
|
||||||
|
"titleFontSize": { "type": "number" },
|
||||||
|
"titleRotate": { "type": "number" },
|
||||||
|
"gridLine": { "$ref": "#/definitions/optsChartGridLine" }
|
||||||
|
},
|
||||||
|
"description": "Value axis item for valAxes array"
|
||||||
|
},
|
||||||
"chartOptions": {
|
"chartOptions": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{ "$ref": "#/definitions/position" },
|
{ "$ref": "#/definitions/position" },
|
||||||
@@ -466,7 +542,7 @@
|
|||||||
"chartColors": { "type": "array", "items": { "$ref": "#/definitions/hexColor" } },
|
"chartColors": { "type": "array", "items": { "$ref": "#/definitions/hexColor" } },
|
||||||
"chartColorsOpacity": { "type": "number" },
|
"chartColorsOpacity": { "type": "number" },
|
||||||
"dataBorder": { "$ref": "#/definitions/borderProps" },
|
"dataBorder": { "$ref": "#/definitions/borderProps" },
|
||||||
"displayBlanksAs": { "type": "string" },
|
"displayBlanksAs": { "type": "string", "enum": ["gap", "span", "zero"] },
|
||||||
"invertedColors": { "type": "array", "items": { "$ref": "#/definitions/hexColor" } },
|
"invertedColors": { "type": "array", "items": { "$ref": "#/definitions/hexColor" } },
|
||||||
"lang": { "type": "string" },
|
"lang": { "type": "string" },
|
||||||
"layout": { "$ref": "#/definitions/position" },
|
"layout": { "$ref": "#/definitions/position" },
|
||||||
@@ -500,7 +576,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"catAxes": { "type": "array", "items": { "type": "object" } },
|
"catAxes": { "type": "array", "items": { "$ref": "#/definitions/catAxisItem" } },
|
||||||
"catAxisBaseTimeUnit": { "type": "string" },
|
"catAxisBaseTimeUnit": { "type": "string" },
|
||||||
"catAxisCrossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] },
|
"catAxisCrossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] },
|
||||||
"catAxisHidden": { "type": "boolean" },
|
"catAxisHidden": { "type": "boolean" },
|
||||||
@@ -551,7 +627,7 @@
|
|||||||
"serAxisMajorUnit": { "type": "number" },
|
"serAxisMajorUnit": { "type": "number" },
|
||||||
"serAxisMinorTimeUnit": { "type": "string" },
|
"serAxisMinorTimeUnit": { "type": "string" },
|
||||||
"serAxisMinorUnit": { "type": "number" },
|
"serAxisMinorUnit": { "type": "number" },
|
||||||
"serAxisOrientation": { "type": "string" },
|
"serAxisOrientation": { "type": "string", "enum": ["minMax"] },
|
||||||
"serAxisTitle": { "type": "string" },
|
"serAxisTitle": { "type": "string" },
|
||||||
"serAxisTitleColor": { "type": "string" },
|
"serAxisTitleColor": { "type": "string" },
|
||||||
"serAxisTitleFontFace": { "type": "string" },
|
"serAxisTitleFontFace": { "type": "string" },
|
||||||
@@ -563,7 +639,7 @@
|
|||||||
|
|
||||||
"secondaryValAxis": { "type": "boolean" },
|
"secondaryValAxis": { "type": "boolean" },
|
||||||
"showValAxisTitle": { "type": "boolean" },
|
"showValAxisTitle": { "type": "boolean" },
|
||||||
"valAxes": { "type": "array", "items": { "type": "object" } },
|
"valAxes": { "type": "array", "items": { "$ref": "#/definitions/valAxisItem" } },
|
||||||
"valAxisCrossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] },
|
"valAxisCrossesAt": { "oneOf": [{ "type": "number" }, { "type": "string", "enum": ["autoZero"] }] },
|
||||||
"valAxisDisplayUnit": { "type": "string", "enum": ["billions", "hundredMillions", "hundreds", "hundredThousands", "millions", "tenMillions", "tenThousands", "thousands", "trillions"] },
|
"valAxisDisplayUnit": { "type": "string", "enum": ["billions", "hundredMillions", "hundreds", "hundredThousands", "millions", "tenMillions", "tenThousands", "thousands", "trillions"] },
|
||||||
"valAxisDisplayUnitLabel": { "type": "boolean" },
|
"valAxisDisplayUnitLabel": { "type": "boolean" },
|
||||||
@@ -595,11 +671,11 @@
|
|||||||
"valGridLine": { "$ref": "#/definitions/optsChartGridLine" },
|
"valGridLine": { "$ref": "#/definitions/optsChartGridLine" },
|
||||||
"valLabelFormatCode": { "type": "string" },
|
"valLabelFormatCode": { "type": "string" },
|
||||||
|
|
||||||
"bar3DShape": { "type": "string" },
|
"bar3DShape": { "type": "string", "enum": ["box", "cylinder", "cone", "pyramid"] },
|
||||||
"barDir": { "type": "string" },
|
"barDir": { "type": "string", "enum": ["bar", "col"] },
|
||||||
"barGapDepthPct": { "type": "number" },
|
"barGapDepthPct": { "type": "number" },
|
||||||
"barGapWidthPct": { "type": "number" },
|
"barGapWidthPct": { "type": "number" },
|
||||||
"barGrouping": { "type": "string" },
|
"barGrouping": { "type": "string", "enum": ["clustered", "stacked", "standard"] },
|
||||||
"barOverlapPct": { "type": "number" },
|
"barOverlapPct": { "type": "number" },
|
||||||
|
|
||||||
"dataNoEffects": { "type": "boolean" },
|
"dataNoEffects": { "type": "boolean" },
|
||||||
@@ -625,7 +701,7 @@
|
|||||||
"dataLabelFontItalic": { "type": "boolean" },
|
"dataLabelFontItalic": { "type": "boolean" },
|
||||||
"dataLabelFontSize": { "type": "number" },
|
"dataLabelFontSize": { "type": "number" },
|
||||||
"dataLabelFormatCode": { "type": "string" },
|
"dataLabelFormatCode": { "type": "string" },
|
||||||
"dataLabelFormatScatter": { "type": "string" },
|
"dataLabelFormatScatter": { "type": "string", "enum": ["custom", "customXY", "XY"] },
|
||||||
"dataLabelPosition": { "type": "string", "enum": ["b", "bestFit", "ctr", "l", "r", "t", "inEnd", "outEnd"] },
|
"dataLabelPosition": { "type": "string", "enum": ["b", "bestFit", "ctr", "l", "r", "t", "inEnd", "outEnd"] },
|
||||||
|
|
||||||
"dataTableFontSize": { "type": "number" },
|
"dataTableFontSize": { "type": "number" },
|
||||||
@@ -642,7 +718,7 @@
|
|||||||
"legendPos": { "type": "string", "enum": ["b", "l", "r", "t", "tr"] },
|
"legendPos": { "type": "string", "enum": ["b", "l", "r", "t", "tr"] },
|
||||||
|
|
||||||
"title": { "type": "string" },
|
"title": { "type": "string" },
|
||||||
"titleAlign": { "type": "string" },
|
"titleAlign": { "type": "string", "enum": ["l", "ctr", "r"] },
|
||||||
"titleBold": { "type": "boolean" },
|
"titleBold": { "type": "boolean" },
|
||||||
"titleColor": { "type": "string" },
|
"titleColor": { "type": "string" },
|
||||||
"titleFontFace": { "type": "string" },
|
"titleFontFace": { "type": "string" },
|
||||||
@@ -708,6 +784,7 @@
|
|||||||
"background": { "$ref": "#/definitions/backgroundProps" },
|
"background": { "$ref": "#/definitions/backgroundProps" },
|
||||||
"color": { "$ref": "#/definitions/hexColor", "description": "Default text color for this slide" },
|
"color": { "$ref": "#/definitions/hexColor", "description": "Default text color for this slide" },
|
||||||
"hidden": { "type": "boolean", "description": "Whether slide is hidden" },
|
"hidden": { "type": "boolean", "description": "Whether slide is hidden" },
|
||||||
|
"notes": { "type": "string", "description": "Speaker notes for this slide" },
|
||||||
"slideNumber": { "$ref": "#/definitions/slideNumberProps" },
|
"slideNumber": { "$ref": "#/definitions/slideNumberProps" },
|
||||||
"objects": {
|
"objects": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@@ -736,6 +813,16 @@
|
|||||||
"company": { "type": "string" },
|
"company": { "type": "string" },
|
||||||
"revision": { "type": "string" },
|
"revision": { "type": "string" },
|
||||||
"rtlMode": { "type": "boolean" },
|
"rtlMode": { "type": "boolean" },
|
||||||
|
"masterSlide": { "type": "object", "description": "Master slide reference object" },
|
||||||
|
"presLayout": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": { "type": "string", "description": "Layout name (e.g. LAYOUT_16x9)" },
|
||||||
|
"width": { "type": "number", "description": "Slide width in inches" },
|
||||||
|
"height": { "type": "number", "description": "Slide height in inches" }
|
||||||
|
},
|
||||||
|
"description": "Presentation layout dimensions"
|
||||||
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
Reference in New Issue
Block a user