@hirokisakabe/pom 8.3.0 → 8.4.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.
Files changed (120) hide show
  1. package/README.md +35 -23
  2. package/dist/autoFit/autoFit.js +1 -1
  3. package/dist/autoFit/autoFit.js.map +1 -1
  4. package/dist/autoFit/strategies/reduceFontSize.js +16 -14
  5. package/dist/autoFit/strategies/reduceFontSize.js.map +1 -1
  6. package/dist/autoFit/strategies/reduceGapAndPadding.js +13 -20
  7. package/dist/autoFit/strategies/reduceGapAndPadding.js.map +1 -1
  8. package/dist/autoFit/strategies/reduceTableRowHeight.js +8 -2
  9. package/dist/autoFit/strategies/reduceTableRowHeight.js.map +1 -1
  10. package/dist/autoFit/strategies/uniformScale.js +19 -20
  11. package/dist/autoFit/strategies/uniformScale.js.map +1 -1
  12. package/dist/autoFit/strategyResult.js +15 -0
  13. package/dist/autoFit/strategyResult.js.map +1 -0
  14. package/dist/buildPptx.js +1 -1
  15. package/dist/calcYogaLayout/calcYogaLayout.js +16 -27
  16. package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
  17. package/dist/diagnostics.d.ts +1 -1
  18. package/dist/diagnostics.d.ts.map +1 -1
  19. package/dist/diagnostics.js.map +1 -1
  20. package/dist/parseXml/coercionRules.js +43 -8
  21. package/dist/parseXml/coercionRules.js.map +1 -1
  22. package/dist/parseXml/parseXml.d.ts +8 -3
  23. package/dist/parseXml/parseXml.d.ts.map +1 -1
  24. package/dist/parseXml/parseXml.js +192 -212
  25. package/dist/parseXml/parseXml.js.map +1 -1
  26. package/dist/parseXml/serializeXml.d.ts.map +1 -1
  27. package/dist/parseXml/serializeXml.js +12 -17
  28. package/dist/parseXml/serializeXml.js.map +1 -1
  29. package/dist/registry/definitions/arrow.js +2 -2
  30. package/dist/registry/definitions/arrow.js.map +1 -1
  31. package/dist/registry/definitions/chart.js +2 -2
  32. package/dist/registry/definitions/chart.js.map +1 -1
  33. package/dist/registry/definitions/compositeNodes.js +7 -12
  34. package/dist/registry/definitions/compositeNodes.js.map +1 -1
  35. package/dist/registry/definitions/icon.js +2 -2
  36. package/dist/registry/definitions/icon.js.map +1 -1
  37. package/dist/registry/definitions/image.js +2 -2
  38. package/dist/registry/definitions/image.js.map +1 -1
  39. package/dist/registry/definitions/layer.js +4 -5
  40. package/dist/registry/definitions/layer.js.map +1 -1
  41. package/dist/registry/definitions/line.js +2 -2
  42. package/dist/registry/definitions/line.js.map +1 -1
  43. package/dist/registry/definitions/list.js +3 -4
  44. package/dist/registry/definitions/list.js.map +1 -1
  45. package/dist/registry/definitions/shape.js +2 -2
  46. package/dist/registry/definitions/shape.js.map +1 -1
  47. package/dist/registry/definitions/stack.js +3 -4
  48. package/dist/registry/definitions/stack.js.map +1 -1
  49. package/dist/registry/definitions/svg.js +2 -2
  50. package/dist/registry/definitions/svg.js.map +1 -1
  51. package/dist/registry/definitions/table.js +2 -2
  52. package/dist/registry/definitions/table.js.map +1 -1
  53. package/dist/registry/definitions/text.js +2 -2
  54. package/dist/registry/definitions/text.js.map +1 -1
  55. package/dist/registry/index.js.map +1 -1
  56. package/dist/registry/nodeMetadata.js +208 -0
  57. package/dist/registry/nodeMetadata.js.map +1 -0
  58. package/dist/registry/nodeRegistry.js +3 -0
  59. package/dist/registry/nodeRegistry.js.map +1 -1
  60. package/dist/registry/xmlChildRules.js +55 -0
  61. package/dist/registry/xmlChildRules.js.map +1 -0
  62. package/dist/renderPptx/nodes/arrow.js +7 -28
  63. package/dist/renderPptx/nodes/arrow.js.map +1 -1
  64. package/dist/renderPptx/nodes/chart.js +2 -7
  65. package/dist/renderPptx/nodes/chart.js.map +1 -1
  66. package/dist/renderPptx/nodes/flow.js +6 -13
  67. package/dist/renderPptx/nodes/flow.js.map +1 -1
  68. package/dist/renderPptx/nodes/icon.js +4 -2
  69. package/dist/renderPptx/nodes/icon.js.map +1 -1
  70. package/dist/renderPptx/nodes/image.js +5 -13
  71. package/dist/renderPptx/nodes/image.js.map +1 -1
  72. package/dist/renderPptx/nodes/line.js +9 -33
  73. package/dist/renderPptx/nodes/line.js.map +1 -1
  74. package/dist/renderPptx/nodes/list.js +8 -20
  75. package/dist/renderPptx/nodes/list.js.map +1 -1
  76. package/dist/renderPptx/nodes/matrix.js +10 -11
  77. package/dist/renderPptx/nodes/matrix.js.map +1 -1
  78. package/dist/renderPptx/nodes/processArrow.js +9 -16
  79. package/dist/renderPptx/nodes/processArrow.js.map +1 -1
  80. package/dist/renderPptx/nodes/pyramid.js +5 -7
  81. package/dist/renderPptx/nodes/pyramid.js.map +1 -1
  82. package/dist/renderPptx/nodes/shape.js +7 -20
  83. package/dist/renderPptx/nodes/shape.js.map +1 -1
  84. package/dist/renderPptx/nodes/svg.js +2 -5
  85. package/dist/renderPptx/nodes/svg.js.map +1 -1
  86. package/dist/renderPptx/nodes/table.js +2 -5
  87. package/dist/renderPptx/nodes/table.js.map +1 -1
  88. package/dist/renderPptx/nodes/text.js +4 -1
  89. package/dist/renderPptx/nodes/text.js.map +1 -1
  90. package/dist/renderPptx/nodes/timeline.js +20 -22
  91. package/dist/renderPptx/nodes/timeline.js.map +1 -1
  92. package/dist/renderPptx/nodes/tree.js +5 -5
  93. package/dist/renderPptx/nodes/tree.js.map +1 -1
  94. package/dist/renderPptx/renderPptx.js +13 -29
  95. package/dist/renderPptx/renderPptx.js.map +1 -1
  96. package/dist/renderPptx/textOptions.js +32 -8
  97. package/dist/renderPptx/textOptions.js.map +1 -1
  98. package/dist/renderPptx/units.js +11 -1
  99. package/dist/renderPptx/units.js.map +1 -1
  100. package/dist/renderPptx/utils/backgroundBorder.js +103 -57
  101. package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
  102. package/dist/renderPptx/utils/contentArea.js +26 -9
  103. package/dist/renderPptx/utils/contentArea.js.map +1 -1
  104. package/dist/renderPptx/utils/scaleToFit.js +17 -1
  105. package/dist/renderPptx/utils/scaleToFit.js.map +1 -1
  106. package/dist/renderPptx/utils/straightLine.js +41 -0
  107. package/dist/renderPptx/utils/straightLine.js.map +1 -0
  108. package/dist/renderPptx/utils/visualStyle.js +113 -0
  109. package/dist/renderPptx/utils/visualStyle.js.map +1 -0
  110. package/dist/shared/boxSpacing.js +63 -0
  111. package/dist/shared/boxSpacing.js.map +1 -0
  112. package/dist/shared/walkTree.js +1 -7
  113. package/dist/shared/walkTree.js.map +1 -1
  114. package/dist/toPositioned/toPositioned.js +1 -1
  115. package/dist/toPositioned/toPositioned.js.map +1 -1
  116. package/dist/types.d.ts +1127 -95
  117. package/dist/types.d.ts.map +1 -1
  118. package/dist/types.js +47 -17
  119. package/dist/types.js.map +1 -1
  120. package/package.json +4 -3
@@ -1,5 +1,4 @@
1
- import { pxToIn, pxToPt } from "../units.js";
2
- import { resolveArrowType } from "./line.js";
1
+ import { addStraightLine } from "../utils/straightLine.js";
3
2
  //#region src/renderPptx/nodes/arrow.ts
4
3
  function renderArrowNode(node, ctx) {
5
4
  const fromBounds = ctx.idPositionMap.get(node.from);
@@ -12,32 +11,12 @@ function renderArrowNode(node, ctx) {
12
11
  ctx.buildContext.diagnostics.add("ARROW_REF_NOT_FOUND", `Arrow: "to" ID "${node.to}" not found`);
13
12
  return;
14
13
  }
15
- const x1 = fromBounds.x + fromBounds.w / 2;
16
- const y1 = fromBounds.y + fromBounds.h / 2;
17
- const x2 = toBounds.x + toBounds.w / 2;
18
- const y2 = toBounds.y + toBounds.h / 2;
19
- const minX = Math.min(x1, x2);
20
- const minY = Math.min(y1, y2);
21
- const lineW = Math.abs(x2 - x1);
22
- const lineH = Math.abs(y2 - y1);
23
- const flipH = x2 < x1;
24
- const flipV = y2 < y1;
25
- const { color, lineWidth, dashType, beginArrow, endArrow } = node;
26
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
27
- x: pxToIn(minX),
28
- y: pxToIn(minY),
29
- w: pxToIn(lineW),
30
- h: pxToIn(lineH),
31
- flipH,
32
- flipV,
33
- line: {
34
- color: color ?? "000000",
35
- width: lineWidth !== void 0 ? pxToPt(lineWidth) : 1,
36
- dashType,
37
- beginArrowType: resolveArrowType(beginArrow),
38
- endArrowType: resolveArrowType(endArrow)
39
- }
40
- });
14
+ addStraightLine(ctx, {
15
+ x1: fromBounds.x + fromBounds.w / 2,
16
+ y1: fromBounds.y + fromBounds.h / 2,
17
+ x2: toBounds.x + toBounds.w / 2,
18
+ y2: toBounds.y + toBounds.h / 2
19
+ }, node);
41
20
  }
42
21
  //#endregion
43
22
  export { renderArrowNode };
@@ -1 +1 @@
1
- {"version":3,"file":"arrow.js","names":[],"sources":["../../../src/renderPptx/nodes/arrow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { resolveArrowType } from \"./line.ts\";\n\ntype ArrowPositionedNode = Extract<PositionedNode, { type: \"arrow\" }>;\n\nexport function renderArrowNode(\n node: ArrowPositionedNode,\n ctx: RenderContext,\n): void {\n const fromBounds = ctx.idPositionMap.get(node.from);\n const toBounds = ctx.idPositionMap.get(node.to);\n\n if (!fromBounds) {\n ctx.buildContext.diagnostics.add(\n \"ARROW_REF_NOT_FOUND\",\n `Arrow: \"from\" ID \"${node.from}\" not found`,\n );\n return;\n }\n if (!toBounds) {\n ctx.buildContext.diagnostics.add(\n \"ARROW_REF_NOT_FOUND\",\n `Arrow: \"to\" ID \"${node.to}\" not found`,\n );\n return;\n }\n\n const x1 = fromBounds.x + fromBounds.w / 2;\n const y1 = fromBounds.y + fromBounds.h / 2;\n const x2 = toBounds.x + toBounds.w / 2;\n const y2 = toBounds.y + toBounds.h / 2;\n\n const minX = Math.min(x1, x2);\n const minY = Math.min(y1, y2);\n const lineW = Math.abs(x2 - x1);\n const lineH = Math.abs(y2 - y1);\n const flipH = x2 < x1;\n const flipV = y2 < y1;\n\n const { color, lineWidth, dashType, beginArrow, endArrow } = node;\n\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(minX),\n y: pxToIn(minY),\n w: pxToIn(lineW),\n h: pxToIn(lineH),\n flipH,\n flipV,\n line: {\n color: color ?? \"000000\",\n width: lineWidth !== undefined ? pxToPt(lineWidth) : 1,\n dashType,\n beginArrowType: resolveArrowType(beginArrow),\n endArrowType: resolveArrowType(endArrow),\n },\n });\n}\n"],"mappings":";;;AAOA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,aAAa,IAAI,cAAc,IAAI,KAAK,IAAI;CAClD,MAAM,WAAW,IAAI,cAAc,IAAI,KAAK,EAAE;CAE9C,IAAI,CAAC,YAAY;EACf,IAAI,aAAa,YAAY,IAC3B,uBACA,qBAAqB,KAAK,KAAK,YACjC;EACA;CACF;CACA,IAAI,CAAC,UAAU;EACb,IAAI,aAAa,YAAY,IAC3B,uBACA,mBAAmB,KAAK,GAAG,YAC7B;EACA;CACF;CAEA,MAAM,KAAK,WAAW,IAAI,WAAW,IAAI;CACzC,MAAM,KAAK,WAAW,IAAI,WAAW,IAAI;CACzC,MAAM,KAAK,SAAS,IAAI,SAAS,IAAI;CACrC,MAAM,KAAK,SAAS,IAAI,SAAS,IAAI;CAErC,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,KAAK;CAEnB,MAAM,EAAE,OAAO,WAAW,UAAU,YAAY,aAAa;CAE7D,IAAI,MAAM,SAAS,IAAI,KAAK,UAAU,MAAM;EAC1C,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,KAAK;EACf,GAAG,OAAO,KAAK;EACf;EACA;EACA,MAAM;GACJ,OAAO,SAAS;GAChB,OAAO,cAAc,KAAA,IAAY,OAAO,SAAS,IAAI;GACrD;GACA,gBAAgB,iBAAiB,UAAU;GAC3C,cAAc,iBAAiB,QAAQ;EACzC;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"arrow.js","names":[],"sources":["../../../src/renderPptx/nodes/arrow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { addStraightLine } from \"../utils/straightLine.ts\";\n\ntype ArrowPositionedNode = Extract<PositionedNode, { type: \"arrow\" }>;\n\nexport function renderArrowNode(\n node: ArrowPositionedNode,\n ctx: RenderContext,\n): void {\n const fromBounds = ctx.idPositionMap.get(node.from);\n const toBounds = ctx.idPositionMap.get(node.to);\n\n if (!fromBounds) {\n ctx.buildContext.diagnostics.add(\n \"ARROW_REF_NOT_FOUND\",\n `Arrow: \"from\" ID \"${node.from}\" not found`,\n );\n return;\n }\n if (!toBounds) {\n ctx.buildContext.diagnostics.add(\n \"ARROW_REF_NOT_FOUND\",\n `Arrow: \"to\" ID \"${node.to}\" not found`,\n );\n return;\n }\n\n // 参照ノードの中心同士を結ぶ\n addStraightLine(\n ctx,\n {\n x1: fromBounds.x + fromBounds.w / 2,\n y1: fromBounds.y + fromBounds.h / 2,\n x2: toBounds.x + toBounds.w / 2,\n y2: toBounds.y + toBounds.h / 2,\n },\n node,\n );\n}\n"],"mappings":";;AAMA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,aAAa,IAAI,cAAc,IAAI,KAAK,IAAI;CAClD,MAAM,WAAW,IAAI,cAAc,IAAI,KAAK,EAAE;CAE9C,IAAI,CAAC,YAAY;EACf,IAAI,aAAa,YAAY,IAC3B,uBACA,qBAAqB,KAAK,KAAK,YACjC;EACA;CACF;CACA,IAAI,CAAC,UAAU;EACb,IAAI,aAAa,YAAY,IAC3B,uBACA,mBAAmB,KAAK,GAAG,YAC7B;EACA;CACF;CAGA,gBACE,KACA;EACE,IAAI,WAAW,IAAI,WAAW,IAAI;EAClC,IAAI,WAAW,IAAI,WAAW,IAAI;EAClC,IAAI,SAAS,IAAI,SAAS,IAAI;EAC9B,IAAI,SAAS,IAAI,SAAS,IAAI;CAChC,GACA,IACF;AACF"}
@@ -1,5 +1,4 @@
1
- import { pxToIn } from "../units.js";
2
- import { getContentArea } from "../utils/contentArea.js";
1
+ import { getContentAreaIn } from "../utils/contentArea.js";
3
2
  //#region src/renderPptx/nodes/chart.ts
4
3
  function renderChartNode(node, ctx) {
5
4
  const chartData = node.data.map((d) => ({
@@ -7,12 +6,8 @@ function renderChartNode(node, ctx) {
7
6
  labels: d.labels,
8
7
  values: d.values
9
8
  }));
10
- const content = getContentArea(node);
11
9
  const chartOptions = {
12
- x: pxToIn(content.x),
13
- y: pxToIn(content.y),
14
- w: pxToIn(content.w),
15
- h: pxToIn(content.h),
10
+ ...getContentAreaIn(node),
16
11
  showLegend: node.showLegend ?? false,
17
12
  showTitle: node.showTitle ?? false,
18
13
  title: node.title,
@@ -1 +1 @@
1
- {"version":3,"file":"chart.js","names":[],"sources":["../../../src/renderPptx/nodes/chart.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn } from \"../units.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\n\ntype ChartPositionedNode = Extract<PositionedNode, { type: \"chart\" }>;\n\nexport function renderChartNode(\n node: ChartPositionedNode,\n ctx: RenderContext,\n): void {\n const chartData = node.data.map((d) => ({\n name: d.name,\n labels: d.labels,\n values: d.values,\n }));\n\n const content = getContentArea(node);\n const chartOptions: Record<string, unknown> = {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n showLegend: node.showLegend ?? false,\n showTitle: node.showTitle ?? false,\n title: node.title,\n chartColors: node.chartColors,\n };\n\n // radar専用オプション\n if (node.chartType === \"radar\" && node.radarStyle) {\n chartOptions.radarStyle = node.radarStyle;\n }\n\n ctx.slide.addChart(node.chartType, chartData, chartOptions);\n}\n"],"mappings":";;;AAOA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,YAAY,KAAK,KAAK,KAAK,OAAO;EACtC,MAAM,EAAE;EACR,QAAQ,EAAE;EACV,QAAQ,EAAE;CACZ,EAAE;CAEF,MAAM,UAAU,eAAe,IAAI;CACnC,MAAM,eAAwC;EAC5C,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,YAAY,KAAK,cAAc;EAC/B,WAAW,KAAK,aAAa;EAC7B,OAAO,KAAK;EACZ,aAAa,KAAK;CACpB;CAGA,IAAI,KAAK,cAAc,WAAW,KAAK,YACrC,aAAa,aAAa,KAAK;CAGjC,IAAI,MAAM,SAAS,KAAK,WAAW,WAAW,YAAY;AAC5D"}
1
+ {"version":3,"file":"chart.js","names":[],"sources":["../../../src/renderPptx/nodes/chart.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { getContentAreaIn } from \"../utils/contentArea.ts\";\n\ntype ChartPositionedNode = Extract<PositionedNode, { type: \"chart\" }>;\n\nexport function renderChartNode(\n node: ChartPositionedNode,\n ctx: RenderContext,\n): void {\n const chartData = node.data.map((d) => ({\n name: d.name,\n labels: d.labels,\n values: d.values,\n }));\n\n const chartOptions: Record<string, unknown> = {\n ...getContentAreaIn(node),\n showLegend: node.showLegend ?? false,\n showTitle: node.showTitle ?? false,\n title: node.title,\n chartColors: node.chartColors,\n };\n\n // radar専用オプション\n if (node.chartType === \"radar\" && node.radarStyle) {\n chartOptions.radarStyle = node.radarStyle;\n }\n\n ctx.slide.addChart(node.chartType, chartData, chartOptions);\n}\n"],"mappings":";;AAMA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,YAAY,KAAK,KAAK,KAAK,OAAO;EACtC,MAAM,EAAE;EACR,QAAQ,EAAE;EACV,QAAQ,EAAE;CACZ,EAAE;CAEF,MAAM,eAAwC;EAC5C,GAAG,iBAAiB,IAAI;EACxB,YAAY,KAAK,cAAc;EAC/B,WAAW,KAAK,aAAa;EAC7B,OAAO,KAAK;EACZ,aAAa,KAAK;CACpB;CAGA,IAAI,KAAK,cAAc,WAAW,KAAK,YACrC,aAAa,aAAa,KAAK;CAGjC,IAAI,MAAM,SAAS,KAAK,WAAW,WAAW,YAAY;AAC5D"}
@@ -1,7 +1,8 @@
1
1
  import { pxToIn, pxToPt } from "../units.js";
2
- import { getContentArea } from "../utils/contentArea.js";
2
+ import { withContentBounds } from "../utils/contentArea.js";
3
+ import { stripHash } from "../utils/visualStyle.js";
3
4
  import { measureFlow } from "../../calcYogaLayout/measureCompositeNodes.js";
4
- import { calcScaleFactor } from "../utils/scaleToFit.js";
5
+ import { resolveScaledContentArea } from "../utils/scaleToFit.js";
5
6
  //#region src/renderPptx/nodes/flow.ts
6
7
  function renderFlowNode(node, ctx) {
7
8
  const direction = node.direction ?? "horizontal";
@@ -10,21 +11,13 @@ function renderFlowNode(node, ctx) {
10
11
  const nodeGap = node.nodeGap ?? 80;
11
12
  const connectorStyle = node.connectorStyle ?? {};
12
13
  const defaultColor = "1D4ED8";
13
- const content = getContentArea(node);
14
- const intrinsic = measureFlow(node);
15
- const scaleFactor = calcScaleFactor(content.w, content.h, intrinsic.width, intrinsic.height, "flow", ctx.buildContext.diagnostics);
14
+ const { content, scaleFactor } = resolveScaledContentArea(node, measureFlow(node), ctx);
16
15
  const scaledNodeWidth = nodeWidth * scaleFactor;
17
16
  const scaledNodeHeight = nodeHeight * scaleFactor;
18
17
  const scaledNodeGap = nodeGap * scaleFactor;
19
18
  const layouts = /* @__PURE__ */ new Map();
20
19
  const nodeCount = node.nodes.length;
21
- const contentNode = {
22
- ...node,
23
- x: content.x,
24
- y: content.y,
25
- w: content.w,
26
- h: content.h
27
- };
20
+ const contentNode = withContentBounds(node, content);
28
21
  if (direction === "horizontal") calculateHorizontalLayout(contentNode, layouts, nodeCount, scaledNodeWidth, scaledNodeHeight, scaledNodeGap, scaleFactor);
29
22
  else calculateVerticalLayout(contentNode, layouts, nodeCount, scaledNodeWidth, scaledNodeHeight, scaledNodeGap, scaleFactor);
30
23
  for (const conn of node.connections) {
@@ -44,7 +37,7 @@ function renderFlowNode(node, ctx) {
44
37
  h: pxToIn(labelH),
45
38
  fontSize: pxToPt(10 * scaleFactor),
46
39
  fontFace: "Noto Sans JP",
47
- color: "64748B",
40
+ color: stripHash(conn.labelColor) ?? stripHash(connectorStyle.labelColor) ?? "64748B",
48
41
  align: "center",
49
42
  valign: "middle"
50
43
  });
@@ -1 +1 @@
1
- {"version":3,"file":"flow.js","names":[],"sources":["../../../src/renderPptx/nodes/flow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { measureFlow } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { calcScaleFactor } from \"../utils/scaleToFit.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\n\ntype FlowPositionedNode = Extract<PositionedNode, { type: \"flow\" }>;\n\ninterface FlowNodeLayout {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n item: FlowPositionedNode[\"nodes\"][0];\n}\n\nexport function renderFlowNode(\n node: FlowPositionedNode,\n ctx: RenderContext,\n): void {\n const direction = node.direction ?? \"horizontal\";\n const nodeWidth = node.nodeWidth ?? 120;\n const nodeHeight = node.nodeHeight ?? 60;\n const nodeGap = node.nodeGap ?? 80;\n const connectorStyle = node.connectorStyle ?? {};\n const defaultColor = \"1D4ED8\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const content = getContentArea(node);\n const intrinsic = measureFlow(node);\n const scaleFactor = calcScaleFactor(\n content.w,\n content.h,\n intrinsic.width,\n intrinsic.height,\n \"flow\",\n ctx.buildContext.diagnostics,\n );\n\n const scaledNodeWidth = nodeWidth * scaleFactor;\n const scaledNodeHeight = nodeHeight * scaleFactor;\n const scaledNodeGap = nodeGap * scaleFactor;\n\n const layouts = new Map<string, FlowNodeLayout>();\n const nodeCount = node.nodes.length;\n\n // コンテンツ領域を使用するための仮想ノードを作成\n const contentNode = {\n ...node,\n x: content.x,\n y: content.y,\n w: content.w,\n h: content.h,\n };\n\n // ノードのレイアウトを計算\n if (direction === \"horizontal\") {\n calculateHorizontalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n } else {\n calculateVerticalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n }\n\n // 接続線を描画(ノードより先に描画して背面に配置)\n for (const conn of node.connections) {\n const fromLayout = layouts.get(conn.from);\n const toLayout = layouts.get(conn.to);\n\n if (!fromLayout || !toLayout) continue;\n\n const lineColor = conn.color ?? connectorStyle.color ?? \"333333\";\n const lineWidth = (connectorStyle.width ?? 2) * scaleFactor;\n const arrowType = connectorStyle.arrowType ?? \"triangle\";\n\n drawConnection(\n ctx,\n direction,\n fromLayout,\n toLayout,\n lineColor,\n lineWidth,\n arrowType,\n );\n\n // ラベルを描画\n if (conn.label) {\n const labelX =\n (fromLayout.x +\n fromLayout.width / 2 +\n toLayout.x +\n toLayout.width / 2) /\n 2;\n const labelY =\n (fromLayout.y +\n fromLayout.height / 2 +\n toLayout.y +\n toLayout.height / 2) /\n 2;\n\n const labelW = 60 * scaleFactor;\n const labelH = 20 * scaleFactor;\n\n ctx.slide.addText(conn.label, {\n x: pxToIn(labelX - labelW / 2),\n y: pxToIn(labelY - labelH / 2),\n w: pxToIn(labelW),\n h: pxToIn(labelH),\n fontSize: pxToPt(10 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: \"64748B\",\n align: \"center\",\n valign: \"middle\",\n });\n }\n }\n\n // ノードを描画\n for (const item of node.nodes) {\n const layout = layouts.get(item.id);\n if (!layout) continue;\n\n const fillColor = item.color ?? defaultColor;\n const textColor = item.textColor ?? \"FFFFFF\";\n\n // 図形を描画\n ctx.slide.addText(item.text, {\n x: pxToIn(layout.x),\n y: pxToIn(layout.y),\n w: pxToIn(layout.width),\n h: pxToIn(layout.height),\n shape: item.shape,\n fill: { color: fillColor },\n line: { color: \"333333\", width: pxToPt(1 * scaleFactor) },\n fontSize: pxToPt(14 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: textColor,\n align: \"center\",\n valign: \"middle\",\n });\n }\n}\n\nfunction calculateHorizontalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalWidth = nodeCount * nodeWidth + (nodeCount - 1) * nodeGap;\n const startX = node.x + (node.w - totalWidth) / 2;\n const centerY = node.y + node.h / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: startX + index * (nodeWidth + nodeGap) + (nodeWidth - w) / 2,\n y: centerY - h / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction calculateVerticalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalHeight = nodeCount * nodeHeight + (nodeCount - 1) * nodeGap;\n const startY = node.y + (node.h - totalHeight) / 2;\n const centerX = node.x + node.w / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: centerX - w / 2,\n y: startY + index * (nodeHeight + nodeGap) + (nodeHeight - h) / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction drawConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n fromLayout: FlowNodeLayout,\n toLayout: FlowNodeLayout,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n let startX: number, startY: number, endX: number, endY: number;\n\n if (direction === \"horizontal\") {\n // 水平: 右端から左端へ\n startX = fromLayout.x + fromLayout.width;\n startY = fromLayout.y + fromLayout.height / 2;\n endX = toLayout.x;\n endY = toLayout.y + toLayout.height / 2;\n } else {\n // 垂直: 下端から上端へ\n startX = fromLayout.x + fromLayout.width / 2;\n startY = fromLayout.y + fromLayout.height;\n endX = toLayout.x + toLayout.width / 2;\n endY = toLayout.y;\n }\n\n // 直線接続(シンプルなケース)\n const isHorizontalLine = Math.abs(startY - endY) < 1;\n const isVerticalLine = Math.abs(startX - endX) < 1;\n\n if (isHorizontalLine || isVerticalLine) {\n // 直線で描画\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(Math.min(startY, endY)),\n w: pxToIn(Math.abs(endX - startX)),\n h: pxToIn(Math.abs(endY - startY)),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // L字型接続\n drawLShapedConnection(\n ctx,\n direction,\n startX,\n startY,\n endX,\n endY,\n lineColor,\n lineWidth,\n arrowType,\n );\n }\n}\n\nfunction drawLShapedConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n const midX = (startX + endX) / 2;\n const midY = (startY + endY) / 2;\n\n if (direction === \"horizontal\") {\n // 水平→垂直→水平\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: pxToIn(midX - startX),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(Math.min(startY, endY)),\n w: 0,\n h: pxToIn(Math.abs(endY - startY)),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(endY),\n w: pxToIn(endX - midX),\n h: 0,\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // 垂直→水平→垂直\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: 0,\n h: pxToIn(midY - startY),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(midY),\n w: pxToIn(Math.abs(endX - startX)),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(endX),\n y: pxToIn(midY),\n w: 0,\n h: pxToIn(endY - midY),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flow.js","names":[],"sources":["../../../src/renderPptx/nodes/flow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { stripHash } from \"../utils/visualStyle.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { measureFlow } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { resolveScaledContentArea } from \"../utils/scaleToFit.ts\";\nimport { withContentBounds } from \"../utils/contentArea.ts\";\n\ntype FlowPositionedNode = Extract<PositionedNode, { type: \"flow\" }>;\n\ninterface FlowNodeLayout {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n item: FlowPositionedNode[\"nodes\"][0];\n}\n\nexport function renderFlowNode(\n node: FlowPositionedNode,\n ctx: RenderContext,\n): void {\n const direction = node.direction ?? \"horizontal\";\n const nodeWidth = node.nodeWidth ?? 120;\n const nodeHeight = node.nodeHeight ?? 60;\n const nodeGap = node.nodeGap ?? 80;\n const connectorStyle = node.connectorStyle ?? {};\n const defaultColor = \"1D4ED8\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const { content, scaleFactor } = resolveScaledContentArea(\n node,\n measureFlow(node),\n ctx,\n );\n\n const scaledNodeWidth = nodeWidth * scaleFactor;\n const scaledNodeHeight = nodeHeight * scaleFactor;\n const scaledNodeGap = nodeGap * scaleFactor;\n\n const layouts = new Map<string, FlowNodeLayout>();\n const nodeCount = node.nodes.length;\n\n // コンテンツ領域を使用するための仮想ノードを作成\n const contentNode = withContentBounds(node, content);\n\n // ノードのレイアウトを計算\n if (direction === \"horizontal\") {\n calculateHorizontalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n } else {\n calculateVerticalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n }\n\n // 接続線を描画(ノードより先に描画して背面に配置)\n for (const conn of node.connections) {\n const fromLayout = layouts.get(conn.from);\n const toLayout = layouts.get(conn.to);\n\n if (!fromLayout || !toLayout) continue;\n\n const lineColor = conn.color ?? connectorStyle.color ?? \"333333\";\n const lineWidth = (connectorStyle.width ?? 2) * scaleFactor;\n const arrowType = connectorStyle.arrowType ?? \"triangle\";\n\n drawConnection(\n ctx,\n direction,\n fromLayout,\n toLayout,\n lineColor,\n lineWidth,\n arrowType,\n );\n\n // ラベルを描画\n if (conn.label) {\n const labelX =\n (fromLayout.x +\n fromLayout.width / 2 +\n toLayout.x +\n toLayout.width / 2) /\n 2;\n const labelY =\n (fromLayout.y +\n fromLayout.height / 2 +\n toLayout.y +\n toLayout.height / 2) /\n 2;\n\n const labelW = 60 * scaleFactor;\n const labelH = 20 * scaleFactor;\n\n ctx.slide.addText(conn.label, {\n x: pxToIn(labelX - labelW / 2),\n y: pxToIn(labelY - labelH / 2),\n w: pxToIn(labelW),\n h: pxToIn(labelH),\n fontSize: pxToPt(10 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color:\n stripHash(conn.labelColor) ??\n stripHash(connectorStyle.labelColor) ??\n \"64748B\",\n align: \"center\",\n valign: \"middle\",\n });\n }\n }\n\n // ノードを描画\n for (const item of node.nodes) {\n const layout = layouts.get(item.id);\n if (!layout) continue;\n\n const fillColor = item.color ?? defaultColor;\n const textColor = item.textColor ?? \"FFFFFF\";\n\n // 図形を描画\n ctx.slide.addText(item.text, {\n x: pxToIn(layout.x),\n y: pxToIn(layout.y),\n w: pxToIn(layout.width),\n h: pxToIn(layout.height),\n shape: item.shape,\n fill: { color: fillColor },\n line: { color: \"333333\", width: pxToPt(1 * scaleFactor) },\n fontSize: pxToPt(14 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: textColor,\n align: \"center\",\n valign: \"middle\",\n });\n }\n}\n\nfunction calculateHorizontalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalWidth = nodeCount * nodeWidth + (nodeCount - 1) * nodeGap;\n const startX = node.x + (node.w - totalWidth) / 2;\n const centerY = node.y + node.h / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: startX + index * (nodeWidth + nodeGap) + (nodeWidth - w) / 2,\n y: centerY - h / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction calculateVerticalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalHeight = nodeCount * nodeHeight + (nodeCount - 1) * nodeGap;\n const startY = node.y + (node.h - totalHeight) / 2;\n const centerX = node.x + node.w / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: centerX - w / 2,\n y: startY + index * (nodeHeight + nodeGap) + (nodeHeight - h) / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction drawConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n fromLayout: FlowNodeLayout,\n toLayout: FlowNodeLayout,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n let startX: number, startY: number, endX: number, endY: number;\n\n if (direction === \"horizontal\") {\n // 水平: 右端から左端へ\n startX = fromLayout.x + fromLayout.width;\n startY = fromLayout.y + fromLayout.height / 2;\n endX = toLayout.x;\n endY = toLayout.y + toLayout.height / 2;\n } else {\n // 垂直: 下端から上端へ\n startX = fromLayout.x + fromLayout.width / 2;\n startY = fromLayout.y + fromLayout.height;\n endX = toLayout.x + toLayout.width / 2;\n endY = toLayout.y;\n }\n\n // 直線接続(シンプルなケース)\n const isHorizontalLine = Math.abs(startY - endY) < 1;\n const isVerticalLine = Math.abs(startX - endX) < 1;\n\n if (isHorizontalLine || isVerticalLine) {\n // 直線で描画\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(Math.min(startY, endY)),\n w: pxToIn(Math.abs(endX - startX)),\n h: pxToIn(Math.abs(endY - startY)),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // L字型接続\n drawLShapedConnection(\n ctx,\n direction,\n startX,\n startY,\n endX,\n endY,\n lineColor,\n lineWidth,\n arrowType,\n );\n }\n}\n\nfunction drawLShapedConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n const midX = (startX + endX) / 2;\n const midY = (startY + endY) / 2;\n\n if (direction === \"horizontal\") {\n // 水平→垂直→水平\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: pxToIn(midX - startX),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(Math.min(startY, endY)),\n w: 0,\n h: pxToIn(Math.abs(endY - startY)),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(endY),\n w: pxToIn(endX - midX),\n h: 0,\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // 垂直→水平→垂直\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: 0,\n h: pxToIn(midY - startY),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(midY),\n w: pxToIn(Math.abs(endX - startX)),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(endX),\n y: pxToIn(midY),\n w: 0,\n h: pxToIn(endY - midY),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -16,7 +16,8 @@ function renderIconNode(node, ctx) {
16
16
  color: colorValue,
17
17
  width: 1.5
18
18
  },
19
- rectRadius: isCircle ? void 0 : .1
19
+ rectRadius: isCircle ? void 0 : .1,
20
+ rotate: node.rotate
20
21
  };
21
22
  ctx.slide.addShape(shapeType, shapeOptions);
22
23
  }
@@ -25,7 +26,8 @@ function renderIconNode(node, ctx) {
25
26
  x: pxToIn(node.iconX ?? node.x),
26
27
  y: pxToIn(node.iconY ?? node.y),
27
28
  w: pxToIn(node.iconW ?? node.w),
28
- h: pxToIn(node.iconH ?? node.h)
29
+ h: pxToIn(node.iconH ?? node.h),
30
+ rotate: node.rotate
29
31
  });
30
32
  }
31
33
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"icon.js","names":[],"sources":["../../../src/renderPptx/nodes/icon.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn } from \"../units.ts\";\n\ntype IconPositionedNode = Extract<PositionedNode, { type: \"icon\" }>;\n\nexport function renderIconNode(\n node: IconPositionedNode,\n ctx: RenderContext,\n): void {\n // variant 指定時は背景図形を描画\n if (node.variant) {\n const isCircle = node.variant.startsWith(\"circle\");\n const isFilled = node.variant.endsWith(\"-filled\");\n const bgColor = node.bgColor ?? \"#E0E0E0\";\n const colorValue = bgColor.replace(/^#/, \"\");\n\n const shapeType = isCircle ? \"ellipse\" : \"roundRect\";\n const shapeOptions: Record<string, unknown> = {\n x: pxToIn(node.bgX ?? node.x),\n y: pxToIn(node.bgY ?? node.y),\n w: pxToIn(node.bgW ?? node.w),\n h: pxToIn(node.bgH ?? node.h),\n fill: isFilled ? { color: colorValue } : { type: \"none\" as const },\n line: isFilled ? undefined : { color: colorValue, width: 1.5 },\n rectRadius: isCircle ? undefined : 0.1,\n };\n\n ctx.slide.addShape(shapeType, shapeOptions);\n }\n\n ctx.slide.addImage({\n data: node.iconImageData,\n x: pxToIn(node.iconX ?? node.x),\n y: pxToIn(node.iconY ?? node.y),\n w: pxToIn(node.iconW ?? node.w),\n h: pxToIn(node.iconH ?? node.h),\n });\n}\n"],"mappings":";;AAMA,SAAgB,eACd,MACA,KACM;CAEN,IAAI,KAAK,SAAS;EAChB,MAAM,WAAW,KAAK,QAAQ,WAAW,QAAQ;EACjD,MAAM,WAAW,KAAK,QAAQ,SAAS,SAAS;EAEhD,MAAM,cADU,KAAK,WAAW,UAAA,CACL,QAAQ,MAAM,EAAE;EAE3C,MAAM,YAAY,WAAW,YAAY;EACzC,MAAM,eAAwC;GAC5C,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,MAAM,WAAW,EAAE,OAAO,WAAW,IAAI,EAAE,MAAM,OAAgB;GACjE,MAAM,WAAW,KAAA,IAAY;IAAE,OAAO;IAAY,OAAO;GAAI;GAC7D,YAAY,WAAW,KAAA,IAAY;EACrC;EAEA,IAAI,MAAM,SAAS,WAAW,YAAY;CAC5C;CAEA,IAAI,MAAM,SAAS;EACjB,MAAM,KAAK;EACX,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;CAChC,CAAC;AACH"}
1
+ {"version":3,"file":"icon.js","names":[],"sources":["../../../src/renderPptx/nodes/icon.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn } from \"../units.ts\";\n\ntype IconPositionedNode = Extract<PositionedNode, { type: \"icon\" }>;\n\nexport function renderIconNode(\n node: IconPositionedNode,\n ctx: RenderContext,\n): void {\n // variant 指定時は背景図形を描画\n if (node.variant) {\n const isCircle = node.variant.startsWith(\"circle\");\n const isFilled = node.variant.endsWith(\"-filled\");\n const bgColor = node.bgColor ?? \"#E0E0E0\";\n const colorValue = bgColor.replace(/^#/, \"\");\n\n const shapeType = isCircle ? \"ellipse\" : \"roundRect\";\n const shapeOptions: Record<string, unknown> = {\n x: pxToIn(node.bgX ?? node.x),\n y: pxToIn(node.bgY ?? node.y),\n w: pxToIn(node.bgW ?? node.w),\n h: pxToIn(node.bgH ?? node.h),\n fill: isFilled ? { color: colorValue } : { type: \"none\" as const },\n line: isFilled ? undefined : { color: colorValue, width: 1.5 },\n rectRadius: isCircle ? undefined : 0.1,\n rotate: node.rotate,\n };\n\n ctx.slide.addShape(shapeType, shapeOptions);\n }\n\n ctx.slide.addImage({\n data: node.iconImageData,\n x: pxToIn(node.iconX ?? node.x),\n y: pxToIn(node.iconY ?? node.y),\n w: pxToIn(node.iconW ?? node.w),\n h: pxToIn(node.iconH ?? node.h),\n rotate: node.rotate,\n });\n}\n"],"mappings":";;AAMA,SAAgB,eACd,MACA,KACM;CAEN,IAAI,KAAK,SAAS;EAChB,MAAM,WAAW,KAAK,QAAQ,WAAW,QAAQ;EACjD,MAAM,WAAW,KAAK,QAAQ,SAAS,SAAS;EAEhD,MAAM,cADU,KAAK,WAAW,UAAA,CACL,QAAQ,MAAM,EAAE;EAE3C,MAAM,YAAY,WAAW,YAAY;EACzC,MAAM,eAAwC;GAC5C,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,MAAM,WAAW,EAAE,OAAO,WAAW,IAAI,EAAE,MAAM,OAAgB;GACjE,MAAM,WAAW,KAAA,IAAY;IAAE,OAAO;IAAY,OAAO;GAAI;GAC7D,YAAY,WAAW,KAAA,IAAY;GACnC,QAAQ,KAAK;EACf;EAEA,IAAI,MAAM,SAAS,WAAW,YAAY;CAC5C;CAEA,IAAI,MAAM,SAAS;EACjB,MAAM,KAAK;EACX,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,QAAQ,KAAK;CACf,CAAC;AACH"}
@@ -1,21 +1,13 @@
1
- import { pxToIn } from "../units.js";
1
+ import { pxToIn, rectPxToIn } from "../units.js";
2
2
  import { getContentArea } from "../utils/contentArea.js";
3
+ import { convertShadow } from "../utils/visualStyle.js";
3
4
  //#region src/renderPptx/nodes/image.ts
4
5
  function renderImageNode(node, ctx) {
5
6
  const content = getContentArea(node);
6
7
  const imageOptions = {
7
- x: pxToIn(content.x),
8
- y: pxToIn(content.y),
9
- w: pxToIn(content.w),
10
- h: pxToIn(content.h),
11
- shadow: node.shadow ? {
12
- type: node.shadow.type ?? "outer",
13
- opacity: node.shadow.opacity,
14
- blur: node.shadow.blur,
15
- angle: node.shadow.angle,
16
- offset: node.shadow.offset,
17
- color: node.shadow.color
18
- } : void 0
8
+ ...rectPxToIn(content),
9
+ shadow: convertShadow(node.shadow),
10
+ rotate: node.rotate
19
11
  };
20
12
  if (node.sizing) imageOptions.sizing = {
21
13
  type: node.sizing.type,
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","names":[],"sources":["../../../src/renderPptx/nodes/image.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn } from \"../units.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\n\ntype ImagePositionedNode = Extract<PositionedNode, { type: \"image\" }>;\n\nexport function renderImageNode(\n node: ImagePositionedNode,\n ctx: RenderContext,\n): void {\n const content = getContentArea(node);\n const imageOptions: Record<string, unknown> = {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n shadow: node.shadow\n ? {\n type: node.shadow.type ?? (\"outer\" as const),\n opacity: node.shadow.opacity,\n blur: node.shadow.blur,\n angle: node.shadow.angle,\n offset: node.shadow.offset,\n color: node.shadow.color,\n }\n : undefined,\n };\n\n if (node.sizing) {\n imageOptions.sizing = {\n type: node.sizing.type,\n w: pxToIn(node.sizing.w ?? content.w),\n h: pxToIn(node.sizing.h ?? content.h),\n ...(node.sizing.x !== undefined && { x: pxToIn(node.sizing.x) }),\n ...(node.sizing.y !== undefined && { y: pxToIn(node.sizing.y) }),\n };\n }\n\n if (node.imageData) {\n // Base64 データがある場合は data プロパティを使用(リモート画像)\n ctx.slide.addImage({ ...imageOptions, data: node.imageData });\n } else {\n // ローカルパスの場合は path プロパティを使用\n ctx.slide.addImage({ ...imageOptions, path: node.src });\n }\n}\n"],"mappings":";;;AAOA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,UAAU,eAAe,IAAI;CACnC,MAAM,eAAwC;EAC5C,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,GAAG,OAAO,QAAQ,CAAC;EACnB,QAAQ,KAAK,SACT;GACE,MAAM,KAAK,OAAO,QAAS;GAC3B,SAAS,KAAK,OAAO;GACrB,MAAM,KAAK,OAAO;GAClB,OAAO,KAAK,OAAO;GACnB,QAAQ,KAAK,OAAO;GACpB,OAAO,KAAK,OAAO;EACrB,IACA,KAAA;CACN;CAEA,IAAI,KAAK,QACP,aAAa,SAAS;EACpB,MAAM,KAAK,OAAO;EAClB,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;EAC9D,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;CAChE;CAGF,IAAI,KAAK,WAEP,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAU,CAAC;MAG5D,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAI,CAAC;AAE1D"}
1
+ {"version":3,"file":"image.js","names":[],"sources":["../../../src/renderPptx/nodes/image.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, rectPxToIn } from \"../units.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\nimport { convertShadow } from \"../utils/visualStyle.ts\";\n\ntype ImagePositionedNode = Extract<PositionedNode, { type: \"image\" }>;\n\nexport function renderImageNode(\n node: ImagePositionedNode,\n ctx: RenderContext,\n): void {\n const content = getContentArea(node);\n const imageOptions: Record<string, unknown> = {\n ...rectPxToIn(content),\n shadow: convertShadow(node.shadow),\n rotate: node.rotate,\n };\n\n if (node.sizing) {\n imageOptions.sizing = {\n type: node.sizing.type,\n w: pxToIn(node.sizing.w ?? content.w),\n h: pxToIn(node.sizing.h ?? content.h),\n ...(node.sizing.x !== undefined && { x: pxToIn(node.sizing.x) }),\n ...(node.sizing.y !== undefined && { y: pxToIn(node.sizing.y) }),\n };\n }\n\n if (node.imageData) {\n // Base64 データがある場合は data プロパティを使用(リモート画像)\n ctx.slide.addImage({ ...imageOptions, data: node.imageData });\n } else {\n // ローカルパスの場合は path プロパティを使用\n ctx.slide.addImage({ ...imageOptions, path: node.src });\n }\n}\n"],"mappings":";;;;AAQA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,UAAU,eAAe,IAAI;CACnC,MAAM,eAAwC;EAC5C,GAAG,WAAW,OAAO;EACrB,QAAQ,cAAc,KAAK,MAAM;EACjC,QAAQ,KAAK;CACf;CAEA,IAAI,KAAK,QACP,aAAa,SAAS;EACpB,MAAM,KAAK,OAAO;EAClB,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;EAC9D,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;CAChE;CAGF,IAAI,KAAK,WAEP,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAU,CAAC;MAG5D,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAI,CAAC;AAE1D"}
@@ -1,39 +1,15 @@
1
- import { pxToIn, pxToPt } from "../units.js";
1
+ import { addStraightLine } from "../utils/straightLine.js";
2
2
  //#region src/renderPptx/nodes/line.ts
3
- /**
4
- * boolean | LineArrowOptions から pptxgenjs の arrow type を取得
5
- */
6
- function resolveArrowType(arrow) {
7
- if (arrow === void 0) return;
8
- if (arrow === false) return "none";
9
- if (arrow === true) return "triangle";
10
- return arrow.type ?? "triangle";
11
- }
12
3
  function renderLineNode(node, ctx) {
13
- const { x1, y1, x2, y2, color, lineWidth, dashType, beginArrow, endArrow } = node;
14
- const minX = Math.min(x1, x2);
15
- const minY = Math.min(y1, y2);
16
- const lineW = Math.abs(x2 - x1);
17
- const lineH = Math.abs(y2 - y1);
18
- const flipH = x2 < x1;
19
- const flipV = y2 < y1;
20
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
21
- x: pxToIn(minX),
22
- y: pxToIn(minY),
23
- w: pxToIn(lineW),
24
- h: pxToIn(lineH),
25
- flipH,
26
- flipV,
27
- line: {
28
- color: color ?? "000000",
29
- width: lineWidth !== void 0 ? pxToPt(lineWidth) : 1,
30
- dashType,
31
- beginArrowType: resolveArrowType(beginArrow),
32
- endArrowType: resolveArrowType(endArrow)
33
- }
34
- });
4
+ const { x1, y1, x2, y2 } = node;
5
+ addStraightLine(ctx, {
6
+ x1,
7
+ y1,
8
+ x2,
9
+ y2
10
+ }, node);
35
11
  }
36
12
  //#endregion
37
- export { renderLineNode, resolveArrowType };
13
+ export { renderLineNode };
38
14
 
39
15
  //# sourceMappingURL=line.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"line.js","names":[],"sources":["../../../src/renderPptx/nodes/line.ts"],"sourcesContent":["import type { PositionedNode, LineArrow } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\n\ntype LinePositionedNode = Extract<PositionedNode, { type: \"line\" }>;\n\n/**\n * boolean | LineArrowOptions から pptxgenjs の arrow type を取得\n */\nexport function resolveArrowType(\n arrow: LineArrow | undefined,\n): \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined {\n if (arrow === undefined) {\n return undefined;\n }\n if (arrow === false) {\n return \"none\";\n }\n if (arrow === true) {\n return \"triangle\"; // デフォルト\n }\n return arrow.type ?? \"triangle\";\n}\n\nexport function renderLineNode(\n node: LinePositionedNode,\n ctx: RenderContext,\n): void {\n const { x1, y1, x2, y2, color, lineWidth, dashType, beginArrow, endArrow } =\n node;\n\n // pptxgenjs の line シェイプは x, y, w, h で描画\n // x, y は左上座標、w, h で方向と長さを指定\n const minX = Math.min(x1, x2);\n const minY = Math.min(y1, y2);\n const lineW = Math.abs(x2 - x1);\n const lineH = Math.abs(y2 - y1);\n\n // 線の方向を判定して flip を決定\n // flipH: 右から左へ向かう線\n // flipV: 下から上へ向かう線\n const flipH = x2 < x1;\n const flipV = y2 < y1;\n\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(minX),\n y: pxToIn(minY),\n w: pxToIn(lineW),\n h: pxToIn(lineH),\n flipH,\n flipV,\n line: {\n color: color ?? \"000000\",\n width: lineWidth !== undefined ? pxToPt(lineWidth) : 1,\n dashType: dashType,\n beginArrowType: resolveArrowType(beginArrow),\n endArrowType: resolveArrowType(endArrow),\n },\n });\n}\n"],"mappings":";;;;;AASA,SAAgB,iBACd,OAC4E;CAC5E,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,UAAU,OACZ,OAAO;CAET,IAAI,UAAU,MACZ,OAAO;CAET,OAAO,MAAM,QAAQ;AACvB;AAEA,SAAgB,eACd,MACA,KACM;CACN,MAAM,EAAE,IAAI,IAAI,IAAI,IAAI,OAAO,WAAW,UAAU,YAAY,aAC9D;CAIF,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAK9B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,KAAK;CAEnB,IAAI,MAAM,SAAS,IAAI,KAAK,UAAU,MAAM;EAC1C,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,KAAK;EACf,GAAG,OAAO,KAAK;EACf;EACA;EACA,MAAM;GACJ,OAAO,SAAS;GAChB,OAAO,cAAc,KAAA,IAAY,OAAO,SAAS,IAAI;GAC3C;GACV,gBAAgB,iBAAiB,UAAU;GAC3C,cAAc,iBAAiB,QAAQ;EACzC;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"line.js","names":[],"sources":["../../../src/renderPptx/nodes/line.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { addStraightLine } from \"../utils/straightLine.ts\";\n\ntype LinePositionedNode = Extract<PositionedNode, { type: \"line\" }>;\n\nexport function renderLineNode(\n node: LinePositionedNode,\n ctx: RenderContext,\n): void {\n const { x1, y1, x2, y2 } = node;\n addStraightLine(ctx, { x1, y1, x2, y2 }, node);\n}\n"],"mappings":";;AAMA,SAAgB,eACd,MACA,KACM;CACN,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO;CAC3B,gBAAgB,KAAK;EAAE;EAAI;EAAI;EAAI;CAAG,GAAG,IAAI;AAC/C"}
@@ -1,5 +1,5 @@
1
- import { pxToIn, pxToPt } from "../units.js";
2
- import { getContentArea } from "../utils/contentArea.js";
1
+ import { pxToPt } from "../units.js";
2
+ import { getContentAreaIn } from "../utils/contentArea.js";
3
3
  import { convertStrike, convertUnderline } from "../textOptions.js";
4
4
  //#region src/renderPptx/nodes/list.ts
5
5
  function resolveStyle(li, parent) {
@@ -68,14 +68,11 @@ function renderUlNode(node, ctx) {
68
68
  const fontSizePx = node.fontSize ?? 24;
69
69
  const fontFamily = node.fontFamily ?? "Noto Sans JP";
70
70
  const lineHeight = node.lineHeight ?? 1.3;
71
- const content = getContentArea(node);
71
+ const contentIn = getContentAreaIn(node);
72
72
  if (hasItemStyleOverride(node.items)) {
73
73
  const textItems = buildListTextItems(node.items, node, true);
74
74
  ctx.slide.addText(textItems, {
75
- x: pxToIn(content.x),
76
- y: pxToIn(content.y),
77
- w: pxToIn(content.w),
78
- h: pxToIn(content.h),
75
+ ...contentIn,
79
76
  align: node.textAlign ?? "left",
80
77
  valign: "top",
81
78
  margin: 0,
@@ -84,10 +81,7 @@ function renderUlNode(node, ctx) {
84
81
  } else {
85
82
  const text = node.items.map((li) => li.text).join("\n");
86
83
  ctx.slide.addText(text, {
87
- x: pxToIn(content.x),
88
- y: pxToIn(content.y),
89
- w: pxToIn(content.w),
90
- h: pxToIn(content.h),
84
+ ...contentIn,
91
85
  fontSize: pxToPt(fontSizePx),
92
86
  fontFace: fontFamily,
93
87
  align: node.textAlign ?? "left",
@@ -108,17 +102,14 @@ function renderOlNode(node, ctx) {
108
102
  const fontSizePx = node.fontSize ?? 24;
109
103
  const fontFamily = node.fontFamily ?? "Noto Sans JP";
110
104
  const lineHeight = node.lineHeight ?? 1.3;
111
- const content = getContentArea(node);
105
+ const contentIn = getContentAreaIn(node);
112
106
  const bulletOptions = { type: "number" };
113
107
  if (node.numberType !== void 0) bulletOptions.numberType = node.numberType;
114
108
  if (node.numberStartAt !== void 0) bulletOptions.numberStartAt = node.numberStartAt;
115
109
  if (hasItemStyleOverride(node.items)) {
116
110
  const textItems = buildListTextItems(node.items, node, bulletOptions);
117
111
  ctx.slide.addText(textItems, {
118
- x: pxToIn(content.x),
119
- y: pxToIn(content.y),
120
- w: pxToIn(content.w),
121
- h: pxToIn(content.h),
112
+ ...contentIn,
122
113
  align: node.textAlign ?? "left",
123
114
  valign: "top",
124
115
  margin: 0,
@@ -127,10 +118,7 @@ function renderOlNode(node, ctx) {
127
118
  } else {
128
119
  const text = node.items.map((li) => li.text).join("\n");
129
120
  ctx.slide.addText(text, {
130
- x: pxToIn(content.x),
131
- y: pxToIn(content.y),
132
- w: pxToIn(content.w),
133
- h: pxToIn(content.h),
121
+ ...contentIn,
134
122
  fontSize: pxToPt(fontSizePx),
135
123
  fontFace: fontFamily,
136
124
  align: node.textAlign ?? "left",
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","names":[],"sources":["../../../src/renderPptx/nodes/list.ts"],"sourcesContent":["import type { PositionedNode, LiNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { convertUnderline, convertStrike } from \"../textOptions.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\n\ntype UlPositionedNode = Extract<PositionedNode, { type: \"ul\" }>;\ntype OlPositionedNode = Extract<PositionedNode, { type: \"ol\" }>;\n\nfunction resolveStyle(li: LiNode, parent: UlPositionedNode | OlPositionedNode) {\n return {\n fontSize: li.fontSize ?? parent.fontSize ?? 24,\n color: li.color ?? parent.color,\n bold: li.bold ?? parent.bold,\n italic: li.italic ?? parent.italic,\n underline: li.underline ?? parent.underline,\n strike: li.strike ?? parent.strike,\n highlight: li.highlight ?? parent.highlight,\n fontFamily: li.fontFamily ?? parent.fontFamily ?? \"Noto Sans JP\",\n };\n}\n\nfunction buildListTextItems(\n items: LiNode[],\n parent: UlPositionedNode | OlPositionedNode,\n bullet: boolean | Record<string, unknown>,\n) {\n const textItems: { text: string; options: Record<string, unknown> }[] = [];\n for (let i = 0; i < items.length; i++) {\n const li = items[i];\n const style = resolveStyle(li, parent);\n const isLast = i === items.length - 1;\n const baseOptions = {\n fontSize: pxToPt(style.fontSize),\n fontFace: style.fontFamily,\n color: style.color,\n underline: convertUnderline(style.underline),\n strike: convertStrike(style.strike),\n highlight: style.highlight,\n };\n\n if (li.runs && li.runs.length > 0) {\n for (let j = 0; j < li.runs.length; j++) {\n const run = li.runs[j];\n const isLastRun = j === li.runs.length - 1;\n let text = run.text;\n if (isLastRun && !isLast) text += \"\\n\";\n textItems.push({\n text,\n options: {\n ...baseOptions,\n fontFace: run.fontFamily ?? style.fontFamily,\n color: run.color ?? style.color,\n bold: run.bold ?? style.bold,\n italic: run.italic ?? style.italic,\n underline: convertUnderline(run.underline ?? style.underline),\n strike: convertStrike(run.strike ?? style.strike),\n highlight: run.highlight ?? style.highlight,\n bullet: j === 0 ? bullet : false,\n ...(run.href ? { hyperlink: { url: run.href } } : {}),\n },\n });\n }\n } else {\n textItems.push({\n text: isLast ? li.text : li.text + \"\\n\",\n options: {\n ...baseOptions,\n bold: style.bold,\n italic: style.italic,\n bullet,\n },\n });\n }\n }\n return textItems;\n}\n\nfunction hasItemStyleOverride(items: LiNode[]): boolean {\n return items.some(\n (li) =>\n li.fontSize !== undefined ||\n li.color !== undefined ||\n li.bold !== undefined ||\n li.italic !== undefined ||\n li.underline !== undefined ||\n li.strike !== undefined ||\n li.highlight !== undefined ||\n li.fontFamily !== undefined ||\n li.runs !== undefined,\n );\n}\n\nexport function renderUlNode(node: UlPositionedNode, ctx: RenderContext): void {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const lineHeight = node.lineHeight ?? 1.3;\n const content = getContentArea(node);\n\n if (hasItemStyleOverride(node.items)) {\n // Li に個別スタイルがある場合は配列形式を使用\n const textItems = buildListTextItems(node.items, node, true);\n\n ctx.slide.addText(textItems, {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n });\n } else {\n // Li にスタイルオーバーライドがない場合は単一文字列形式を使用\n const text = node.items.map((li) => li.text).join(\"\\n\");\n\n ctx.slide.addText(text, {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n fontSize: pxToPt(fontSizePx),\n fontFace: fontFamily,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n highlight: node.highlight,\n bullet: true,\n });\n }\n}\n\nexport function renderOlNode(node: OlPositionedNode, ctx: RenderContext): void {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const lineHeight = node.lineHeight ?? 1.3;\n const content = getContentArea(node);\n\n const bulletOptions: Record<string, unknown> = { type: \"number\" };\n if (node.numberType !== undefined) {\n bulletOptions.numberType = node.numberType;\n }\n if (node.numberStartAt !== undefined) {\n bulletOptions.numberStartAt = node.numberStartAt;\n }\n\n if (hasItemStyleOverride(node.items)) {\n const textItems = buildListTextItems(node.items, node, bulletOptions);\n\n ctx.slide.addText(textItems, {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n });\n } else {\n const text = node.items.map((li) => li.text).join(\"\\n\");\n\n ctx.slide.addText(text, {\n x: pxToIn(content.x),\n y: pxToIn(content.y),\n w: pxToIn(content.w),\n h: pxToIn(content.h),\n fontSize: pxToPt(fontSizePx),\n fontFace: fontFamily,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n highlight: node.highlight,\n bullet: bulletOptions,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"list.js","names":[],"sources":["../../../src/renderPptx/nodes/list.ts"],"sourcesContent":["import type { PositionedNode, LiNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToPt } from \"../units.ts\";\nimport { convertUnderline, convertStrike } from \"../textOptions.ts\";\nimport { getContentAreaIn } from \"../utils/contentArea.ts\";\n\ntype UlPositionedNode = Extract<PositionedNode, { type: \"ul\" }>;\ntype OlPositionedNode = Extract<PositionedNode, { type: \"ol\" }>;\n\nfunction resolveStyle(li: LiNode, parent: UlPositionedNode | OlPositionedNode) {\n return {\n fontSize: li.fontSize ?? parent.fontSize ?? 24,\n color: li.color ?? parent.color,\n bold: li.bold ?? parent.bold,\n italic: li.italic ?? parent.italic,\n underline: li.underline ?? parent.underline,\n strike: li.strike ?? parent.strike,\n highlight: li.highlight ?? parent.highlight,\n fontFamily: li.fontFamily ?? parent.fontFamily ?? \"Noto Sans JP\",\n };\n}\n\nfunction buildListTextItems(\n items: LiNode[],\n parent: UlPositionedNode | OlPositionedNode,\n bullet: boolean | Record<string, unknown>,\n) {\n const textItems: { text: string; options: Record<string, unknown> }[] = [];\n for (let i = 0; i < items.length; i++) {\n const li = items[i];\n const style = resolveStyle(li, parent);\n const isLast = i === items.length - 1;\n const baseOptions = {\n fontSize: pxToPt(style.fontSize),\n fontFace: style.fontFamily,\n color: style.color,\n underline: convertUnderline(style.underline),\n strike: convertStrike(style.strike),\n highlight: style.highlight,\n };\n\n if (li.runs && li.runs.length > 0) {\n for (let j = 0; j < li.runs.length; j++) {\n const run = li.runs[j];\n const isLastRun = j === li.runs.length - 1;\n let text = run.text;\n if (isLastRun && !isLast) text += \"\\n\";\n textItems.push({\n text,\n options: {\n ...baseOptions,\n fontFace: run.fontFamily ?? style.fontFamily,\n color: run.color ?? style.color,\n bold: run.bold ?? style.bold,\n italic: run.italic ?? style.italic,\n underline: convertUnderline(run.underline ?? style.underline),\n strike: convertStrike(run.strike ?? style.strike),\n highlight: run.highlight ?? style.highlight,\n bullet: j === 0 ? bullet : false,\n ...(run.href ? { hyperlink: { url: run.href } } : {}),\n },\n });\n }\n } else {\n textItems.push({\n text: isLast ? li.text : li.text + \"\\n\",\n options: {\n ...baseOptions,\n bold: style.bold,\n italic: style.italic,\n bullet,\n },\n });\n }\n }\n return textItems;\n}\n\nfunction hasItemStyleOverride(items: LiNode[]): boolean {\n return items.some(\n (li) =>\n li.fontSize !== undefined ||\n li.color !== undefined ||\n li.bold !== undefined ||\n li.italic !== undefined ||\n li.underline !== undefined ||\n li.strike !== undefined ||\n li.highlight !== undefined ||\n li.fontFamily !== undefined ||\n li.runs !== undefined,\n );\n}\n\nexport function renderUlNode(node: UlPositionedNode, ctx: RenderContext): void {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const lineHeight = node.lineHeight ?? 1.3;\n const contentIn = getContentAreaIn(node);\n\n if (hasItemStyleOverride(node.items)) {\n // Li に個別スタイルがある場合は配列形式を使用\n const textItems = buildListTextItems(node.items, node, true);\n\n ctx.slide.addText(textItems, {\n ...contentIn,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n });\n } else {\n // Li にスタイルオーバーライドがない場合は単一文字列形式を使用\n const text = node.items.map((li) => li.text).join(\"\\n\");\n\n ctx.slide.addText(text, {\n ...contentIn,\n fontSize: pxToPt(fontSizePx),\n fontFace: fontFamily,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n highlight: node.highlight,\n bullet: true,\n });\n }\n}\n\nexport function renderOlNode(node: OlPositionedNode, ctx: RenderContext): void {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const lineHeight = node.lineHeight ?? 1.3;\n const contentIn = getContentAreaIn(node);\n\n const bulletOptions: Record<string, unknown> = { type: \"number\" };\n if (node.numberType !== undefined) {\n bulletOptions.numberType = node.numberType;\n }\n if (node.numberStartAt !== undefined) {\n bulletOptions.numberStartAt = node.numberStartAt;\n }\n\n if (hasItemStyleOverride(node.items)) {\n const textItems = buildListTextItems(node.items, node, bulletOptions);\n\n ctx.slide.addText(textItems, {\n ...contentIn,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n });\n } else {\n const text = node.items.map((li) => li.text).join(\"\\n\");\n\n ctx.slide.addText(text, {\n ...contentIn,\n fontSize: pxToPt(fontSizePx),\n fontFace: fontFamily,\n align: node.textAlign ?? \"left\",\n valign: \"top\" as const,\n margin: 0,\n lineSpacingMultiple: lineHeight,\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n highlight: node.highlight,\n bullet: bulletOptions,\n });\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { pxToIn, pxToPt } from "../units.js";
2
- import { getContentArea } from "../utils/contentArea.js";
2
+ import { stripHash } from "../utils/visualStyle.js";
3
3
  import { measureMatrix } from "../../calcYogaLayout/measureCompositeNodes.js";
4
- import { calcScaleFactor } from "../utils/scaleToFit.js";
4
+ import { resolveScaledContentArea } from "../utils/scaleToFit.js";
5
5
  //#region src/renderPptx/nodes/matrix.ts
6
6
  function renderMatrixNode(node, ctx) {
7
7
  const items = node.items;
@@ -11,9 +11,9 @@ function renderMatrixNode(node, ctx) {
11
11
  const baseItemSize = 24;
12
12
  const baseLineWidth = 2;
13
13
  const axisColor = "E2E8F0";
14
- const content = getContentArea(node);
15
- const intrinsic = measureMatrix(node);
16
- const scaleFactor = calcScaleFactor(content.w, content.h, intrinsic.width, intrinsic.height, "matrix", ctx.buildContext.diagnostics);
14
+ const axisLabelColor = stripHash(node.axisLabelColor) ?? "64748B";
15
+ const itemLabelColor = stripHash(node.itemLabelColor) ?? "1E293B";
16
+ const { content, scaleFactor } = resolveScaledContentArea(node, measureMatrix(node), ctx);
17
17
  const itemSize = baseItemSize * scaleFactor;
18
18
  const lineWidth = baseLineWidth * scaleFactor;
19
19
  const axisMargin = 60 * scaleFactor;
@@ -52,7 +52,7 @@ function renderMatrixNode(node, ctx) {
52
52
  h: pxToIn(axisLabelH),
53
53
  fontSize: pxToPt(12 * scaleFactor),
54
54
  fontFace: "Noto Sans JP",
55
- color: "64748B",
55
+ color: axisLabelColor,
56
56
  align: "center",
57
57
  valign: "top"
58
58
  });
@@ -65,12 +65,12 @@ function renderMatrixNode(node, ctx) {
65
65
  h: pxToIn(yLabelH),
66
66
  fontSize: pxToPt(12 * scaleFactor),
67
67
  fontFace: "Noto Sans JP",
68
- color: "64748B",
68
+ color: axisLabelColor,
69
69
  align: "center",
70
70
  valign: "middle",
71
71
  rotate: 270
72
72
  });
73
- if (quadrants) renderQuadrantLabels(ctx, quadrants, areaX, areaY, areaW, areaH, centerX, centerY, scaleFactor);
73
+ if (quadrants) renderQuadrantLabels(ctx, quadrants, areaX, areaY, areaW, areaH, centerX, centerY, scaleFactor, stripHash(node.quadrantLabelColor) ?? "94A3B8");
74
74
  const itemLabelW = 100 * scaleFactor;
75
75
  const itemLabelH = 18 * scaleFactor;
76
76
  for (const item of items) {
@@ -92,16 +92,15 @@ function renderMatrixNode(node, ctx) {
92
92
  h: pxToIn(itemLabelH),
93
93
  fontSize: pxToPt(11 * scaleFactor),
94
94
  fontFace: "Noto Sans JP",
95
- color: "1E293B",
95
+ color: stripHash(item.textColor) ?? itemLabelColor,
96
96
  bold: true,
97
97
  align: "center",
98
98
  valign: "bottom"
99
99
  });
100
100
  }
101
101
  }
102
- function renderQuadrantLabels(ctx, quadrants, areaX, areaY, areaW, areaH, centerX, centerY, scaleFactor) {
102
+ function renderQuadrantLabels(ctx, quadrants, areaX, areaY, areaW, areaH, centerX, centerY, scaleFactor, quadrantColor) {
103
103
  const quadrantFontSize = 11 * scaleFactor;
104
- const quadrantColor = "94A3B8";
105
104
  const quadrantInset = 10 * scaleFactor;
106
105
  const quadrantW = areaW / 2 - 20 * scaleFactor;
107
106
  const quadrantH = 48 * scaleFactor;
@@ -1 +1 @@
1
- {"version":3,"file":"matrix.js","names":[],"sources":["../../../src/renderPptx/nodes/matrix.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { measureMatrix } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { calcScaleFactor } from \"../utils/scaleToFit.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\n\ntype MatrixPositionedNode = Extract<PositionedNode, { type: \"matrix\" }>;\n\nexport function renderMatrixNode(\n node: MatrixPositionedNode,\n ctx: RenderContext,\n): void {\n const items = node.items;\n const axes = node.axes;\n const quadrants = node.quadrants;\n\n const defaultItemColor = \"1D4ED8\"; // blue\n const baseItemSize = 24; // px\n const baseLineWidth = 2; // px\n const axisColor = \"E2E8F0\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const content = getContentArea(node);\n const intrinsic = measureMatrix(node);\n const scaleFactor = calcScaleFactor(\n content.w,\n content.h,\n intrinsic.width,\n intrinsic.height,\n \"matrix\",\n ctx.buildContext.diagnostics,\n );\n\n const itemSize = baseItemSize * scaleFactor;\n const lineWidth = baseLineWidth * scaleFactor;\n\n // マトリクスの描画領域(軸ラベル用の余白を考慮)\n const axisMargin = 60 * scaleFactor; // 軸ラベル用の余白\n const areaX = content.x + axisMargin;\n const areaY = content.y + axisMargin;\n const areaW = content.w - axisMargin * 2;\n const areaH = content.h - axisMargin * 2;\n\n // 中心座標\n const centerX = areaX + areaW / 2;\n const centerY = areaY + areaH / 2;\n\n // === 1. 十字線(軸線)を描画 ===\n // 横線(X軸)\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(areaX),\n y: pxToIn(centerY),\n w: pxToIn(areaW),\n h: 0,\n line: { color: axisColor, width: pxToPt(lineWidth) },\n });\n\n // 縦線(Y軸)\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(centerX),\n y: pxToIn(areaY),\n w: 0,\n h: pxToIn(areaH),\n line: { color: axisColor, width: pxToPt(lineWidth) },\n });\n\n // === 2. 軸ラベルを描画 ===\n const axisLabelW = 120 * scaleFactor;\n const axisLabelH = 24 * scaleFactor;\n\n // X軸ラベル(下部中央)\n ctx.slide.addText(axes.x, {\n x: pxToIn(centerX - axisLabelW / 2),\n y: pxToIn(areaY + areaH + 8 * scaleFactor),\n w: pxToIn(axisLabelW),\n h: pxToIn(axisLabelH),\n fontSize: pxToPt(12 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: \"64748B\",\n align: \"center\",\n valign: \"top\",\n });\n\n // Y軸ラベル(左部中央)270° 回転で下から上読み。w が視覚的な高さになるため CJK 5 文字以上も収まる幅を確保\n const yLabelW = 100 * scaleFactor;\n const yLabelH = 20 * scaleFactor;\n ctx.slide.addText(axes.y, {\n x: pxToIn(content.x + axisMargin / 2 - yLabelW / 2),\n y: pxToIn(centerY - yLabelH / 2),\n w: pxToIn(yLabelW),\n h: pxToIn(yLabelH),\n fontSize: pxToPt(12 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: \"64748B\",\n align: \"center\",\n valign: \"middle\",\n rotate: 270,\n });\n\n // === 3. 象限ラベルを描画 ===\n if (quadrants) {\n renderQuadrantLabels(\n ctx,\n quadrants,\n areaX,\n areaY,\n areaW,\n areaH,\n centerX,\n centerY,\n scaleFactor,\n );\n }\n\n // === 4. アイテムをプロット ===\n const itemLabelW = 100 * scaleFactor;\n const itemLabelH = 18 * scaleFactor;\n\n for (const item of items) {\n // 座標変換: (0,0)=左下, (1,1)=右上\n // x: 0 -> areaX, 1 -> areaX + areaW\n // y: 0 -> areaY + areaH, 1 -> areaY (反転)\n const itemX = areaX + item.x * areaW;\n const itemY = areaY + (1 - item.y) * areaH; // Y軸反転\n const itemColor = item.color ?? defaultItemColor;\n\n // 円を描画\n ctx.slide.addShape(ctx.pptx.ShapeType.ellipse, {\n x: pxToIn(itemX - itemSize / 2),\n y: pxToIn(itemY - itemSize / 2),\n w: pxToIn(itemSize),\n h: pxToIn(itemSize),\n fill: { color: itemColor },\n line: { type: \"none\" as const },\n });\n\n // ラベルを描画(円の上)\n ctx.slide.addText(item.label, {\n x: pxToIn(itemX - itemLabelW / 2),\n y: pxToIn(itemY - itemSize / 2 - 20 * scaleFactor),\n w: pxToIn(itemLabelW),\n h: pxToIn(itemLabelH),\n fontSize: pxToPt(11 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: \"1E293B\",\n bold: true,\n align: \"center\",\n valign: \"bottom\",\n });\n }\n}\n\nfunction renderQuadrantLabels(\n ctx: RenderContext,\n quadrants: NonNullable<MatrixPositionedNode[\"quadrants\"]>,\n areaX: number,\n areaY: number,\n areaW: number,\n areaH: number,\n centerX: number,\n centerY: number,\n scaleFactor: number,\n): void {\n const quadrantFontSize = 11 * scaleFactor;\n const quadrantColor = \"94A3B8\"; // slate-400\n const quadrantInset = 10 * scaleFactor;\n const quadrantW = areaW / 2 - 20 * scaleFactor;\n const quadrantH = 48 * scaleFactor;\n\n // 左上\n ctx.slide.addText(quadrants.topLeft, {\n x: pxToIn(areaX + quadrantInset),\n y: pxToIn(areaY + quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"left\",\n valign: \"top\",\n });\n\n // 右上\n ctx.slide.addText(quadrants.topRight, {\n x: pxToIn(centerX + quadrantInset),\n y: pxToIn(areaY + quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"right\",\n valign: \"top\",\n });\n\n // 左下\n ctx.slide.addText(quadrants.bottomLeft, {\n x: pxToIn(areaX + quadrantInset),\n y: pxToIn(centerY + areaH / 2 - quadrantH - quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"left\",\n valign: \"bottom\",\n });\n\n // 右下\n ctx.slide.addText(quadrants.bottomRight, {\n x: pxToIn(centerX + quadrantInset),\n y: pxToIn(centerY + areaH / 2 - quadrantH - quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"right\",\n valign: \"bottom\",\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"matrix.js","names":[],"sources":["../../../src/renderPptx/nodes/matrix.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { stripHash } from \"../utils/visualStyle.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { measureMatrix } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { resolveScaledContentArea } from \"../utils/scaleToFit.ts\";\n\ntype MatrixPositionedNode = Extract<PositionedNode, { type: \"matrix\" }>;\n\nexport function renderMatrixNode(\n node: MatrixPositionedNode,\n ctx: RenderContext,\n): void {\n const items = node.items;\n const axes = node.axes;\n const quadrants = node.quadrants;\n\n const defaultItemColor = \"1D4ED8\"; // blue\n const baseItemSize = 24; // px\n const baseLineWidth = 2; // px\n const axisColor = \"E2E8F0\";\n const axisLabelColor = stripHash(node.axisLabelColor) ?? \"64748B\";\n const itemLabelColor = stripHash(node.itemLabelColor) ?? \"1E293B\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const { content, scaleFactor } = resolveScaledContentArea(\n node,\n measureMatrix(node),\n ctx,\n );\n\n const itemSize = baseItemSize * scaleFactor;\n const lineWidth = baseLineWidth * scaleFactor;\n\n // マトリクスの描画領域(軸ラベル用の余白を考慮)\n const axisMargin = 60 * scaleFactor; // 軸ラベル用の余白\n const areaX = content.x + axisMargin;\n const areaY = content.y + axisMargin;\n const areaW = content.w - axisMargin * 2;\n const areaH = content.h - axisMargin * 2;\n\n // 中心座標\n const centerX = areaX + areaW / 2;\n const centerY = areaY + areaH / 2;\n\n // === 1. 十字線(軸線)を描画 ===\n // 横線(X軸)\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(areaX),\n y: pxToIn(centerY),\n w: pxToIn(areaW),\n h: 0,\n line: { color: axisColor, width: pxToPt(lineWidth) },\n });\n\n // 縦線(Y軸)\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(centerX),\n y: pxToIn(areaY),\n w: 0,\n h: pxToIn(areaH),\n line: { color: axisColor, width: pxToPt(lineWidth) },\n });\n\n // === 2. 軸ラベルを描画 ===\n const axisLabelW = 120 * scaleFactor;\n const axisLabelH = 24 * scaleFactor;\n\n // X軸ラベル(下部中央)\n ctx.slide.addText(axes.x, {\n x: pxToIn(centerX - axisLabelW / 2),\n y: pxToIn(areaY + areaH + 8 * scaleFactor),\n w: pxToIn(axisLabelW),\n h: pxToIn(axisLabelH),\n fontSize: pxToPt(12 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: axisLabelColor,\n align: \"center\",\n valign: \"top\",\n });\n\n // Y軸ラベル(左部中央)270° 回転で下から上読み。w が視覚的な高さになるため CJK 5 文字以上も収まる幅を確保\n const yLabelW = 100 * scaleFactor;\n const yLabelH = 20 * scaleFactor;\n ctx.slide.addText(axes.y, {\n x: pxToIn(content.x + axisMargin / 2 - yLabelW / 2),\n y: pxToIn(centerY - yLabelH / 2),\n w: pxToIn(yLabelW),\n h: pxToIn(yLabelH),\n fontSize: pxToPt(12 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: axisLabelColor,\n align: \"center\",\n valign: \"middle\",\n rotate: 270,\n });\n\n // === 3. 象限ラベルを描画 ===\n if (quadrants) {\n renderQuadrantLabels(\n ctx,\n quadrants,\n areaX,\n areaY,\n areaW,\n areaH,\n centerX,\n centerY,\n scaleFactor,\n stripHash(node.quadrantLabelColor) ?? \"94A3B8\",\n );\n }\n\n // === 4. アイテムをプロット ===\n const itemLabelW = 100 * scaleFactor;\n const itemLabelH = 18 * scaleFactor;\n\n for (const item of items) {\n // 座標変換: (0,0)=左下, (1,1)=右上\n // x: 0 -> areaX, 1 -> areaX + areaW\n // y: 0 -> areaY + areaH, 1 -> areaY (反転)\n const itemX = areaX + item.x * areaW;\n const itemY = areaY + (1 - item.y) * areaH; // Y軸反転\n const itemColor = item.color ?? defaultItemColor;\n\n // 円を描画\n ctx.slide.addShape(ctx.pptx.ShapeType.ellipse, {\n x: pxToIn(itemX - itemSize / 2),\n y: pxToIn(itemY - itemSize / 2),\n w: pxToIn(itemSize),\n h: pxToIn(itemSize),\n fill: { color: itemColor },\n line: { type: \"none\" as const },\n });\n\n // ラベルを描画(円の上)\n ctx.slide.addText(item.label, {\n x: pxToIn(itemX - itemLabelW / 2),\n y: pxToIn(itemY - itemSize / 2 - 20 * scaleFactor),\n w: pxToIn(itemLabelW),\n h: pxToIn(itemLabelH),\n fontSize: pxToPt(11 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: stripHash(item.textColor) ?? itemLabelColor,\n bold: true,\n align: \"center\",\n valign: \"bottom\",\n });\n }\n}\n\nfunction renderQuadrantLabels(\n ctx: RenderContext,\n quadrants: NonNullable<MatrixPositionedNode[\"quadrants\"]>,\n areaX: number,\n areaY: number,\n areaW: number,\n areaH: number,\n centerX: number,\n centerY: number,\n scaleFactor: number,\n quadrantColor: string,\n): void {\n const quadrantFontSize = 11 * scaleFactor;\n const quadrantInset = 10 * scaleFactor;\n const quadrantW = areaW / 2 - 20 * scaleFactor;\n const quadrantH = 48 * scaleFactor;\n\n // 左上\n ctx.slide.addText(quadrants.topLeft, {\n x: pxToIn(areaX + quadrantInset),\n y: pxToIn(areaY + quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"left\",\n valign: \"top\",\n });\n\n // 右上\n ctx.slide.addText(quadrants.topRight, {\n x: pxToIn(centerX + quadrantInset),\n y: pxToIn(areaY + quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"right\",\n valign: \"top\",\n });\n\n // 左下\n ctx.slide.addText(quadrants.bottomLeft, {\n x: pxToIn(areaX + quadrantInset),\n y: pxToIn(centerY + areaH / 2 - quadrantH - quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"left\",\n valign: \"bottom\",\n });\n\n // 右下\n ctx.slide.addText(quadrants.bottomRight, {\n x: pxToIn(centerX + quadrantInset),\n y: pxToIn(centerY + areaH / 2 - quadrantH - quadrantInset),\n w: pxToIn(quadrantW),\n h: pxToIn(quadrantH),\n fontSize: pxToPt(quadrantFontSize),\n fontFace: \"Noto Sans JP\",\n color: quadrantColor,\n align: \"right\",\n valign: \"bottom\",\n });\n}\n"],"mappings":"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"}