@hirokisakabe/pom 4.0.0 → 4.1.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/README.md +2 -3
- package/dist/calcYogaLayout/measureCompositeNodes.d.ts.map +1 -1
- package/dist/calcYogaLayout/measureCompositeNodes.js +5 -3
- package/dist/renderPptx/nodes/processArrow.d.ts.map +1 -1
- package/dist/renderPptx/nodes/processArrow.js +75 -15
- package/dist/shared/processArrowConstants.d.ts +7 -0
- package/dist/shared/processArrowConstants.d.ts.map +1 -0
- package/dist/shared/processArrowConstants.js +6 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1 align="center">pom</h1>
|
|
2
2
|
<p align="center">
|
|
3
|
-
|
|
3
|
+
AI-friendly PowerPoint generation with a Flexbox layout engine.
|
|
4
4
|
</p>
|
|
5
5
|
|
|
6
6
|
<p align="center">
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
|
-
<b>pom (PowerPoint Object Model)</b> is a TypeScript library that converts XML into PowerPoint files (.pptx)
|
|
14
|
-
Flexbox-style layout powered by <a href="https://www.yogalayout.dev/">yoga-layout</a>, rendered with <a href="https://github.com/nicktomlin/pptxgenjs">pptxgenjs</a>.
|
|
13
|
+
<b>pom (PowerPoint Object Model)</b> is a TypeScript library that converts XML into editable PowerPoint files (.pptx).
|
|
15
14
|
</p>
|
|
16
15
|
|
|
17
16
|
<p align="center">
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measureCompositeNodes.d.ts","sourceRoot":"","sources":["../../src/calcYogaLayout/measureCompositeNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,WAAW,EAEZ,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"measureCompositeNodes.d.ts","sourceRoot":"","sources":["../../src/calcYogaLayout/measureCompositeNodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,WAAW,EAEZ,MAAM,aAAa,CAAC;AAOrB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAuBA;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAoCA;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,GAAG;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAQA;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAuCA;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAsBA;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAcA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ARROW_DEPTH_RATIO, DEFAULT_PROCESS_ARROW_ITEM_WIDTH, DEFAULT_PROCESS_ARROW_ITEM_HEIGHT, } from "../shared/processArrowConstants.js";
|
|
1
2
|
/**
|
|
2
3
|
* ProcessArrow ノードの intrinsic size を計算する
|
|
3
4
|
*/
|
|
@@ -6,9 +7,10 @@ export function measureProcessArrow(node) {
|
|
|
6
7
|
if (stepCount === 0) {
|
|
7
8
|
return { width: 0, height: 0 };
|
|
8
9
|
}
|
|
9
|
-
const itemWidth = node.itemWidth ??
|
|
10
|
-
const itemHeight = node.itemHeight ??
|
|
11
|
-
const
|
|
10
|
+
const itemWidth = node.itemWidth ?? DEFAULT_PROCESS_ARROW_ITEM_WIDTH;
|
|
11
|
+
const itemHeight = node.itemHeight ?? DEFAULT_PROCESS_ARROW_ITEM_HEIGHT;
|
|
12
|
+
const arrowDepth = itemHeight * ARROW_DEPTH_RATIO;
|
|
13
|
+
const gap = node.gap ?? -arrowDepth;
|
|
12
14
|
const direction = node.direction ?? "horizontal";
|
|
13
15
|
if (direction === "horizontal") {
|
|
14
16
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processArrow.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/processArrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"processArrow.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/processArrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWjD,KAAK,0BAA0B,GAAG,OAAO,CACvC,cAAc,EACd;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CACzB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,0BAA0B,EAChC,GAAG,EAAE,aAAa,GACjB,IAAI,CA0DN"}
|
|
@@ -2,6 +2,7 @@ import { pxToIn, pxToPt } from "../units.js";
|
|
|
2
2
|
import { convertUnderline, convertStrike } from "../textOptions.js";
|
|
3
3
|
import { measureProcessArrow } from "../../calcYogaLayout/measureCompositeNodes.js";
|
|
4
4
|
import { calcScaleFactor } from "../utils/scaleToFit.js";
|
|
5
|
+
import { ARROW_DEPTH_RATIO, DEFAULT_PROCESS_ARROW_ITEM_WIDTH, DEFAULT_PROCESS_ARROW_ITEM_HEIGHT, } from "../../shared/processArrowConstants.js";
|
|
5
6
|
export function renderProcessArrowNode(node, ctx) {
|
|
6
7
|
const direction = node.direction ?? "horizontal";
|
|
7
8
|
const steps = node.steps;
|
|
@@ -10,23 +11,25 @@ export function renderProcessArrowNode(node, ctx) {
|
|
|
10
11
|
return;
|
|
11
12
|
const defaultColor = "4472C4"; // PowerPoint標準の青
|
|
12
13
|
const defaultTextColor = "FFFFFF";
|
|
13
|
-
const itemWidth = node.itemWidth ??
|
|
14
|
-
const itemHeight = node.itemHeight ??
|
|
15
|
-
const
|
|
14
|
+
const itemWidth = node.itemWidth ?? DEFAULT_PROCESS_ARROW_ITEM_WIDTH;
|
|
15
|
+
const itemHeight = node.itemHeight ?? DEFAULT_PROCESS_ARROW_ITEM_HEIGHT;
|
|
16
|
+
const arrowDepth = itemHeight * ARROW_DEPTH_RATIO;
|
|
17
|
+
const gap = node.gap ?? -arrowDepth;
|
|
16
18
|
// スケール係数を計算
|
|
17
19
|
const intrinsic = measureProcessArrow(node);
|
|
18
20
|
const scaleFactor = calcScaleFactor(node.w, node.h, intrinsic.width, intrinsic.height, "processArrow");
|
|
19
21
|
const scaledItemWidth = itemWidth * scaleFactor;
|
|
20
22
|
const scaledItemHeight = itemHeight * scaleFactor;
|
|
21
23
|
const scaledGap = gap * scaleFactor;
|
|
24
|
+
const scaledArrowDepth = arrowDepth * scaleFactor;
|
|
22
25
|
if (direction === "horizontal") {
|
|
23
|
-
renderHorizontalProcessArrow(node, ctx, steps, stepCount, scaledItemWidth, scaledItemHeight, scaledGap, defaultColor, defaultTextColor, scaleFactor);
|
|
26
|
+
renderHorizontalProcessArrow(node, ctx, steps, stepCount, scaledItemWidth, scaledItemHeight, scaledGap, scaledArrowDepth, defaultColor, defaultTextColor, scaleFactor);
|
|
24
27
|
}
|
|
25
28
|
else {
|
|
26
|
-
renderVerticalProcessArrow(node, ctx, steps, stepCount, scaledItemWidth, scaledItemHeight, scaledGap, defaultColor, defaultTextColor, scaleFactor);
|
|
29
|
+
renderVerticalProcessArrow(node, ctx, steps, stepCount, scaledItemWidth, scaledItemHeight, scaledGap, scaledArrowDepth, defaultColor, defaultTextColor, scaleFactor);
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
|
-
function renderHorizontalProcessArrow(node, ctx, steps, stepCount, itemWidth, itemHeight, gap, defaultColor, defaultTextColor, scaleFactor) {
|
|
32
|
+
function renderHorizontalProcessArrow(node, ctx, steps, stepCount, itemWidth, itemHeight, gap, arrowDepth, defaultColor, defaultTextColor, scaleFactor) {
|
|
30
33
|
const totalWidth = stepCount * itemWidth + (stepCount - 1) * gap;
|
|
31
34
|
const startX = node.x + (node.w - totalWidth) / 2;
|
|
32
35
|
const centerY = node.y + node.h / 2;
|
|
@@ -35,16 +38,45 @@ function renderHorizontalProcessArrow(node, ctx, steps, stepCount, itemWidth, it
|
|
|
35
38
|
const stepY = centerY - itemHeight / 2;
|
|
36
39
|
const fillColor = step.color?.replace("#", "") ?? defaultColor;
|
|
37
40
|
const textColor = step.textColor?.replace("#", "") ?? defaultTextColor;
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
+
// custGeom でシェブロン形状を描画
|
|
42
|
+
const isFirst = index === 0;
|
|
43
|
+
const points = isFirst
|
|
44
|
+
? [
|
|
45
|
+
// homePlate 風: 左辺フラット、右辺が矢印
|
|
46
|
+
{ x: 0, y: 0 },
|
|
47
|
+
{ x: pxToIn(itemWidth - arrowDepth), y: 0 },
|
|
48
|
+
{ x: pxToIn(itemWidth), y: pxToIn(itemHeight / 2) },
|
|
49
|
+
{ x: pxToIn(itemWidth - arrowDepth), y: pxToIn(itemHeight) },
|
|
50
|
+
{ x: 0, y: pxToIn(itemHeight) },
|
|
51
|
+
{ close: true },
|
|
52
|
+
]
|
|
53
|
+
: [
|
|
54
|
+
// chevron 風: 左辺に切り欠き、右辺が矢印
|
|
55
|
+
{ x: 0, y: 0 },
|
|
56
|
+
{ x: pxToIn(itemWidth - arrowDepth), y: 0 },
|
|
57
|
+
{ x: pxToIn(itemWidth), y: pxToIn(itemHeight / 2) },
|
|
58
|
+
{ x: pxToIn(itemWidth - arrowDepth), y: pxToIn(itemHeight) },
|
|
59
|
+
{ x: 0, y: pxToIn(itemHeight) },
|
|
60
|
+
{ x: pxToIn(arrowDepth), y: pxToIn(itemHeight / 2) },
|
|
61
|
+
{ close: true },
|
|
62
|
+
];
|
|
63
|
+
ctx.slide.addShape("custGeom", {
|
|
41
64
|
x: pxToIn(stepX),
|
|
42
65
|
y: pxToIn(stepY),
|
|
43
66
|
w: pxToIn(itemWidth),
|
|
44
67
|
h: pxToIn(itemHeight),
|
|
45
|
-
|
|
68
|
+
points,
|
|
46
69
|
fill: { color: fillColor },
|
|
47
70
|
line: { type: "none" },
|
|
71
|
+
});
|
|
72
|
+
// テキストを図形の中央(矢印部分を除いた領域)に配置
|
|
73
|
+
const textOffsetLeft = isFirst ? 0 : arrowDepth;
|
|
74
|
+
const textWidth = Math.max(1, itemWidth - arrowDepth - textOffsetLeft);
|
|
75
|
+
ctx.slide.addText(step.label, {
|
|
76
|
+
x: pxToIn(stepX + textOffsetLeft),
|
|
77
|
+
y: pxToIn(stepY),
|
|
78
|
+
w: pxToIn(textWidth),
|
|
79
|
+
h: pxToIn(itemHeight),
|
|
48
80
|
fontSize: pxToPt((node.fontPx ?? 14) * scaleFactor),
|
|
49
81
|
fontFace: "Noto Sans JP",
|
|
50
82
|
color: textColor,
|
|
@@ -58,7 +90,7 @@ function renderHorizontalProcessArrow(node, ctx, steps, stepCount, itemWidth, it
|
|
|
58
90
|
});
|
|
59
91
|
});
|
|
60
92
|
}
|
|
61
|
-
function renderVerticalProcessArrow(node, ctx, steps, stepCount, itemWidth, itemHeight, gap, defaultColor, defaultTextColor, scaleFactor) {
|
|
93
|
+
function renderVerticalProcessArrow(node, ctx, steps, stepCount, itemWidth, itemHeight, gap, arrowDepth, defaultColor, defaultTextColor, scaleFactor) {
|
|
62
94
|
const totalHeight = stepCount * itemHeight + (stepCount - 1) * gap;
|
|
63
95
|
const startY = node.y + (node.h - totalHeight) / 2;
|
|
64
96
|
const centerX = node.x + node.w / 2;
|
|
@@ -67,16 +99,44 @@ function renderVerticalProcessArrow(node, ctx, steps, stepCount, itemWidth, item
|
|
|
67
99
|
const stepY = startY + index * (itemHeight + gap);
|
|
68
100
|
const fillColor = step.color?.replace("#", "") ?? defaultColor;
|
|
69
101
|
const textColor = step.textColor?.replace("#", "") ?? defaultTextColor;
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
102
|
+
const isFirst = index === 0;
|
|
103
|
+
const points = isFirst
|
|
104
|
+
? [
|
|
105
|
+
// rect 風: 上辺フラット、下辺が矢印
|
|
106
|
+
{ x: 0, y: 0 },
|
|
107
|
+
{ x: pxToIn(itemWidth), y: 0 },
|
|
108
|
+
{ x: pxToIn(itemWidth), y: pxToIn(itemHeight - arrowDepth) },
|
|
109
|
+
{ x: pxToIn(itemWidth / 2), y: pxToIn(itemHeight) },
|
|
110
|
+
{ x: 0, y: pxToIn(itemHeight - arrowDepth) },
|
|
111
|
+
{ close: true },
|
|
112
|
+
]
|
|
113
|
+
: [
|
|
114
|
+
// pentagon 風: 上辺に切り欠き、下辺が矢印
|
|
115
|
+
{ x: pxToIn(itemWidth / 2), y: 0 },
|
|
116
|
+
{ x: pxToIn(itemWidth), y: pxToIn(arrowDepth) },
|
|
117
|
+
{ x: pxToIn(itemWidth), y: pxToIn(itemHeight - arrowDepth) },
|
|
118
|
+
{ x: pxToIn(itemWidth / 2), y: pxToIn(itemHeight) },
|
|
119
|
+
{ x: 0, y: pxToIn(itemHeight - arrowDepth) },
|
|
120
|
+
{ x: 0, y: pxToIn(arrowDepth) },
|
|
121
|
+
{ close: true },
|
|
122
|
+
];
|
|
123
|
+
ctx.slide.addShape("custGeom", {
|
|
73
124
|
x: pxToIn(stepX),
|
|
74
125
|
y: pxToIn(stepY),
|
|
75
126
|
w: pxToIn(itemWidth),
|
|
76
127
|
h: pxToIn(itemHeight),
|
|
77
|
-
|
|
128
|
+
points,
|
|
78
129
|
fill: { color: fillColor },
|
|
79
130
|
line: { type: "none" },
|
|
131
|
+
});
|
|
132
|
+
// テキストを図形の中央(矢印部分を除いた領域)に配置
|
|
133
|
+
const textOffsetTop = isFirst ? 0 : arrowDepth;
|
|
134
|
+
const textHeight = Math.max(1, itemHeight - arrowDepth - textOffsetTop);
|
|
135
|
+
ctx.slide.addText(step.label, {
|
|
136
|
+
x: pxToIn(stepX),
|
|
137
|
+
y: pxToIn(stepY + textOffsetTop),
|
|
138
|
+
w: pxToIn(itemWidth),
|
|
139
|
+
h: pxToIn(textHeight),
|
|
80
140
|
fontSize: pxToPt((node.fontPx ?? 14) * scaleFactor),
|
|
81
141
|
fontFace: "Noto Sans JP",
|
|
82
142
|
color: textColor,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** 矢印の先端/切り欠きの深さ(itemHeight に対する比率) */
|
|
2
|
+
export declare const ARROW_DEPTH_RATIO = 0.35;
|
|
3
|
+
/** ProcessArrow のデフォルト itemHeight(px) */
|
|
4
|
+
export declare const DEFAULT_PROCESS_ARROW_ITEM_HEIGHT = 80;
|
|
5
|
+
/** ProcessArrow のデフォルト itemWidth(px) */
|
|
6
|
+
export declare const DEFAULT_PROCESS_ARROW_ITEM_WIDTH = 150;
|
|
7
|
+
//# sourceMappingURL=processArrowConstants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processArrowConstants.d.ts","sourceRoot":"","sources":["../../src/shared/processArrowConstants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,yCAAyC;AACzC,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAEpD,wCAAwC;AACxC,eAAO,MAAM,gCAAgC,MAAM,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** 矢印の先端/切り欠きの深さ(itemHeight に対する比率) */
|
|
2
|
+
export const ARROW_DEPTH_RATIO = 0.35;
|
|
3
|
+
/** ProcessArrow のデフォルト itemHeight(px) */
|
|
4
|
+
export const DEFAULT_PROCESS_ARROW_ITEM_HEIGHT = 80;
|
|
5
|
+
/** ProcessArrow のデフォルト itemWidth(px) */
|
|
6
|
+
export const DEFAULT_PROCESS_ARROW_ITEM_WIDTH = 150;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hirokisakabe/pom",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
|
+
"description": "AI-friendly PowerPoint generation with a Flexbox layout engine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"fmt:check": "prettier --check .",
|
|
48
48
|
"knip": "knip",
|
|
49
49
|
"lint": "eslint",
|
|
50
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
+
"typecheck": "tsc --noEmit -p tsconfig.check.json",
|
|
51
51
|
"test": "vitest",
|
|
52
52
|
"test:ui": "vitest --ui",
|
|
53
53
|
"test:run": "vitest run",
|