ts-visio 1.13.0 → 1.16.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 (46) hide show
  1. package/README.md +96 -15
  2. package/dist/Layer.d.ts +14 -0
  3. package/dist/Layer.js +14 -0
  4. package/dist/Page.d.ts +106 -9
  5. package/dist/Page.js +118 -64
  6. package/dist/Shape.d.ts +17 -2
  7. package/dist/Shape.js +15 -0
  8. package/dist/ShapeModifier.d.ts +82 -124
  9. package/dist/ShapeModifier.js +192 -821
  10. package/dist/ShapeReader.d.ts +0 -3
  11. package/dist/ShapeReader.js +6 -51
  12. package/dist/VisioDocument.d.ts +57 -1
  13. package/dist/VisioDocument.js +66 -0
  14. package/dist/core/ConnectorEditor.d.ts +12 -0
  15. package/dist/core/ConnectorEditor.js +45 -0
  16. package/dist/core/ContainerEditor.d.ts +16 -0
  17. package/dist/core/ContainerEditor.js +179 -0
  18. package/dist/core/LayerEditor.d.ts +36 -0
  19. package/dist/core/LayerEditor.js +209 -0
  20. package/dist/core/MasterManager.d.ts +64 -9
  21. package/dist/core/MasterManager.js +406 -23
  22. package/dist/core/PageManager.d.ts +2 -3
  23. package/dist/core/PageManager.js +18 -93
  24. package/dist/core/PageSheetEditor.d.ts +40 -0
  25. package/dist/core/PageSheetEditor.js +130 -0
  26. package/dist/core/PageXmlCache.d.ts +42 -0
  27. package/dist/core/PageXmlCache.js +194 -0
  28. package/dist/core/RelsManager.js +1 -6
  29. package/dist/core/VisioConstants.d.ts +10 -0
  30. package/dist/core/VisioConstants.js +29 -1
  31. package/dist/core/VisioValidator.js +2 -24
  32. package/dist/diagrams/SchemaDiagram.d.ts +22 -0
  33. package/dist/diagrams/SchemaDiagram.js +36 -0
  34. package/dist/diagrams/SwimlanePattern.d.ts +14 -0
  35. package/dist/diagrams/SwimlanePattern.js +19 -0
  36. package/dist/diagrams/TablePattern.d.ts +11 -0
  37. package/dist/diagrams/TablePattern.js +44 -0
  38. package/dist/index.d.ts +3 -7
  39. package/dist/index.js +6 -10
  40. package/dist/shapes/ContainerBuilder.js +0 -22
  41. package/dist/shapes/ShapeBuilder.js +7 -8
  42. package/dist/types/VisioTypes.d.ts +98 -4
  43. package/dist/utils/ShapeTreeUtils.d.ts +21 -0
  44. package/dist/utils/ShapeTreeUtils.js +77 -0
  45. package/dist/utils/StyleHelpers.d.ts +2 -14
  46. package/package.json +3 -1
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ts-visio
2
2
 
3
+ [![API Docs](https://img.shields.io/badge/API%20Docs-TypeDoc-blue?style=flat-square)](https://zimmermanw84.github.io/ts-visio/)
4
+
3
5
  > [!WARNING]
4
6
  > **Under Construction**
5
7
  > This library is currently being developed with heavy assistance from AI and is primarily an experimental project. Use with caution.
@@ -14,7 +16,7 @@ Built using specific schema-level abstractions to handle the complex internal st
14
16
  - **Strict Typing**: Interact with `VisioPage`, `VisioShape`, and `VisioConnect` objects.
15
17
  - **ShapeSheet Access**: Read `Cells`, `Rows`, and `Sections` directly.
16
18
  - **Connections**: Analyze connectivity between shapes.
17
- - **Modular Architecture**: Use specialized components for loading, page management, shape reading, and modification.
19
+ - **Modular Architecture**: Clean layered architecture `VisioDocument` `Page` `Shape` is the full public surface; XML and OPC internals stay encapsulated.
18
20
  - **Modify Content**: Update text content of shapes.
19
21
  - **Create Shapes**: Rectangles, ellipses, diamonds, rounded rectangles, triangles, parallelograms.
20
22
  - **Connect Shapes**: Dynamic connectors with arrow styles, line styling, and routing (straight / orthogonal / curved).
@@ -30,6 +32,7 @@ Built using specific schema-level abstractions to handle the complex internal st
30
32
  - **Color Palette**: Register named colors in the document's color table via `doc.addColor()` and look them up by index or hex value with `doc.getColors()` / `doc.getColorIndex()`.
31
33
  - **Read Layers Back**: Enumerate existing layers from loaded files via `page.getLayers()`; delete a layer with `layer.delete()`, rename with `layer.rename()`, and read `layer.visible` / `layer.locked` state.
32
34
  - **Group Traversal**: Access nested child shapes via `shape.getChildren()`, check `shape.isGroup`, and read `shape.type`.
35
+ - **Drawing Scale**: Set a real-world unit mapping on any page (`page.setDrawingScale()`), read it back (`page.getDrawingScale()`), or reset to 1:1 (`page.clearDrawingScale()`). Supports all common imperial and metric units.
33
36
 
34
37
  Feature gaps are being tracked in [FEATURES.md](./FEATURES.md).
35
38
 
@@ -201,26 +204,53 @@ Save the modified document back to disk.
201
204
  await doc.save('updated_diagram.vsdx');
202
205
  ```
203
206
 
204
- #### 10. Using Stencils (Masters)
205
- Load a template that already contains stencils (like "Network" or "Flowchart") and drop shapes by their Master ID.
207
+ #### 10. Masters & Stencils
208
+
209
+ **Create a master from scratch** — define a reusable shape with a built-in geometry, then stamp instances onto any page:
206
210
 
207
211
  ```typescript
208
- // 1. Load a template with stencils
209
- const doc = await VisioDocument.load('template_with_masters.vsdx');
212
+ const doc = await VisioDocument.create();
210
213
  const page = doc.pages[0];
211
214
 
212
- // 2. Drop a shape using a Master ID
213
- // (You can find IDs in visio/masters/masters.xml of the template)
214
- await page.addShape({
215
- text: "Router 1",
216
- x: 2,
217
- y: 2,
218
- width: 1,
219
- height: 1,
220
- masterId: "5" // ID of the 'Router' master in the template
215
+ // Define masters (geometries: 'rectangle' | 'ellipse' | 'diamond' |
216
+ // 'rounded-rectangle' | 'triangle' | 'parallelogram')
217
+ const boxMaster = doc.createMaster('Box');
218
+ const processMaster = doc.createMaster('Process', 'ellipse');
219
+ const decisionMaster = doc.createMaster('Decision', 'diamond');
220
+
221
+ // Stamp instances — geometry + styling come from the master definition
222
+ await page.addShape({ text: 'Start', x: 1, y: 1, width: 2, height: 1, masterId: processMaster.id });
223
+ await page.addShape({ text: 'Step 1', x: 4, y: 1, width: 2, height: 1, masterId: boxMaster.id });
224
+ await page.addShape({ text: 'Branch?', x: 7, y: 1, width: 2, height: 1, masterId: decisionMaster.id });
225
+ ```
226
+
227
+ **Import masters from a `.vssx` stencil file** — bring in an entire stencil and use any of its masters:
228
+
229
+ ```typescript
230
+ const doc = await VisioDocument.create();
231
+
232
+ // Path to a .vssx file, or pass a Buffer / ArrayBuffer directly
233
+ const stencilMasters = await doc.importMastersFromStencil('./Network_Shapes.vssx');
234
+ const router = stencilMasters.find(m => m.name === 'Router')!;
235
+
236
+ await doc.pages[0].addShape({
237
+ text: 'Router 1', x: 2, y: 2, width: 1, height: 1,
238
+ masterId: router.id,
221
239
  });
240
+ ```
222
241
 
223
- // The library automatically handles the relationships so the file stays valid.
242
+ **List masters already in the document** useful after loading a `.vsdx` that was created in Visio:
243
+
244
+ ```typescript
245
+ const doc = await VisioDocument.load('existing_diagram.vsdx');
246
+ const masters = doc.getMasters();
247
+ // [{ id: '1', name: 'Box', nameU: 'Box', xmlPath: 'visio/masters/master1.xml' }, ...]
248
+
249
+ // Find and reuse a master by name
250
+ const routerMaster = masters.find(m => m.name === 'Router');
251
+ if (routerMaster) {
252
+ await doc.pages[0].addShape({ text: 'Router 2', x: 5, y: 5, width: 1, height: 1, masterId: routerMaster.id });
253
+ }
224
254
  ```
225
255
 
226
256
  #### 11. Multi-Page Documents
@@ -682,6 +712,16 @@ const styles = doc.getStyles();
682
712
  `StyleProps` supports: `fillColor`, `lineColor`, `lineWeight` (pt), `linePattern`, `fontColor`, `fontSize` (pt), `bold`, `italic`, `underline`, `strikethrough`, `fontFamily`, `horzAlign`, `verticalAlign`, `spaceBefore`, `spaceAfter`, `lineSpacing`, `textMarginTop/Bottom/Left/Right` (in).
683
713
  Local shape properties always override inherited stylesheet values.
684
714
 
715
+ The alignment and style types are exported for use in typed consumers:
716
+
717
+ ```typescript
718
+ import type { HorzAlign, VertAlign, ShapeStyle } from 'ts-visio';
719
+
720
+ const style: ShapeStyle = { horzAlign: 'center', verticalAlign: 'middle', bold: true };
721
+ const align: HorzAlign = 'justify'; // 'left' | 'center' | 'right' | 'justify'
722
+ const valign: VertAlign = 'bottom'; // 'top' | 'middle' | 'bottom'
723
+ ```
724
+
685
725
  #### 30. Reading Connectors Back
686
726
  Enumerate connectors on a page — including those loaded from an existing `.vsdx` file — and inspect or delete them.
687
727
 
@@ -789,6 +829,47 @@ for (const g of groups) {
789
829
 
790
830
  `getChildren()` returns `[]` for non-group shapes. Children are full `Shape` instances — all existing methods (`setStyle()`, `getProperties()`, `delete()`, etc.) work on them.
791
831
 
832
+ #### 33. Drawing Scale
833
+ Map page coordinates to real-world units. One `pageScale` `pageUnit` on the paper equals `drawingScale` `drawingUnit` in reality. Visio uses this to display rulers, grids, and shape dimensions in real-world terms.
834
+
835
+ ```typescript
836
+ import type { LengthUnit, DrawingScaleInfo } from 'ts-visio';
837
+
838
+ // 1 inch on paper = 10 feet in the real world (architectural)
839
+ page.setDrawingScale(1, 'in', 10, 'ft');
840
+
841
+ // 1:100 metric (1 cm on paper = 100 cm = 1 m in reality)
842
+ page.setDrawingScale(1, 'cm', 100, 'cm');
843
+
844
+ // Engineering: 1 inch = 20 feet
845
+ page.setDrawingScale(1, 'in', 20, 'ft');
846
+
847
+ // Read the current scale back
848
+ const scale: DrawingScaleInfo | null = page.getDrawingScale();
849
+ if (scale) {
850
+ console.log(`${scale.pageScale} ${scale.pageUnit} = ${scale.drawingScale} ${scale.drawingUnit}`);
851
+ // → "1 in = 10 ft"
852
+ }
853
+
854
+ // Returns null when no custom scale is set
855
+ const freshPage = doc.pages[0];
856
+ console.log(freshPage.getDrawingScale()); // null
857
+
858
+ // Reset to 1:1 (no scale)
859
+ page.clearDrawingScale();
860
+ console.log(page.getDrawingScale()); // null
861
+
862
+ // All methods are chainable
863
+ page.setDrawingScale(1, 'mm', 1000, 'mm')
864
+ .setNamedSize('A1'); // combine with page size changes
865
+ ```
866
+
867
+ Supported `LengthUnit` values:
868
+ - Imperial: `'in'` (inches), `'ft'` (feet), `'yd'` (yards), `'mi'` (miles)
869
+ - Metric: `'mm'`, `'cm'`, `'m'`, `'km'`
870
+
871
+ The drawing scale does not affect the internal coordinate system — shape positions and sizes are still specified in page-inches. The scale is purely a display/annotation mapping applied by Visio's ruler and grid.
872
+
792
873
  ---
793
874
 
794
875
  ## Examples
package/dist/Layer.d.ts CHANGED
@@ -1,5 +1,19 @@
1
1
  import { VisioPackage } from './VisioPackage';
2
2
  import { ShapeModifier } from './ShapeModifier';
3
+ /**
4
+ * A named display layer on a Visio page.
5
+ *
6
+ * Layers control the visibility and printability of groups of shapes.
7
+ * Obtain instances via `page.getLayers()` or `page.addLayer()`.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const annotations = await page.addLayer('Annotations');
12
+ * ann.setVisible(false); // hide all shapes on this layer
13
+ * ```
14
+ *
15
+ * @category Layers
16
+ */
3
17
  export declare class Layer {
4
18
  name: string;
5
19
  index: number;
package/dist/Layer.js CHANGED
@@ -2,6 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Layer = void 0;
4
4
  const ShapeModifier_1 = require("./ShapeModifier");
5
+ /**
6
+ * A named display layer on a Visio page.
7
+ *
8
+ * Layers control the visibility and printability of groups of shapes.
9
+ * Obtain instances via `page.getLayers()` or `page.addLayer()`.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const annotations = await page.addLayer('Annotations');
14
+ * ann.setVisible(false); // hide all shapes on this layer
15
+ * ```
16
+ *
17
+ * @category Layers
18
+ */
5
19
  class Layer {
6
20
  constructor(name, index, pageId, pkg, modifier, _visible = true, _locked = false) {
7
21
  this.name = name;
package/dist/Page.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { VisioPage, ConnectorStyle, PageOrientation, PageSizeName, ConnectionTarget } from './types/VisioTypes';
1
+ import { VisioPage, ConnectorStyle, PageOrientation, PageSizeName, ConnectionTarget, DrawingScaleInfo, LengthUnit } from './types/VisioTypes';
2
2
  import { Connector } from './Connector';
3
3
  import { VisioPackage } from './VisioPackage';
4
4
  import { ShapeModifier } from './ShapeModifier';
@@ -7,6 +7,21 @@ import { Shape } from './Shape';
7
7
  import { MediaManager } from './core/MediaManager';
8
8
  import { RelsManager } from './core/RelsManager';
9
9
  import { Layer } from './Layer';
10
+ /**
11
+ * Represents a single page (tab) inside a Visio document.
12
+ *
13
+ * Obtain a `Page` instance from {@link VisioDocument.pages},
14
+ * {@link VisioDocument.addPage}, or {@link VisioDocument.getPage}.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const doc = await VisioDocument.create();
19
+ * const page = doc.pages[0];
20
+ * await page.addShape({ text: 'Hello', x: 1, y: 1, width: 2, height: 1 });
21
+ * ```
22
+ *
23
+ * @category Pages
24
+ */
10
25
  export declare class Page {
11
26
  private internalPage;
12
27
  private pkg;
@@ -39,6 +54,10 @@ export declare class Page {
39
54
  * Swaps width and height when the current orientation does not match the requested one.
40
55
  */
41
56
  setOrientation(orientation: PageOrientation): this;
57
+ /**
58
+ * Return all top-level shapes on the page.
59
+ * Group children are not included; use {@link findShapes} to search the entire shape tree.
60
+ */
42
61
  getShapes(): Shape[];
43
62
  /**
44
63
  * Find a shape by its ID anywhere on the page, including shapes nested inside groups.
@@ -50,6 +69,29 @@ export declare class Page {
50
69
  * the predicate. Equivalent to getAllShapes().filter(predicate).
51
70
  */
52
71
  findShapes(predicate: (shape: Shape) => boolean): Shape[];
72
+ /**
73
+ * Add a new shape to the page and return a {@link Shape} handle to it.
74
+ *
75
+ * @param props Visual and text properties for the new shape.
76
+ * All geometry fields (`x`, `y`, `width`, `height`) are in inches.
77
+ * @param parentId Optional ID of an existing group shape to nest the new shape inside.
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Plain rectangle
82
+ * const box = await page.addShape({ text: 'Server', x: 2, y: 3, width: 2, height: 1 });
83
+ *
84
+ * // Ellipse with styling
85
+ * await page.addShape({
86
+ * text: 'Start', x: 1, y: 1, width: 1.5, height: 1.5,
87
+ * geometry: 'ellipse', fillColor: '#4472C4', fontColor: '#ffffff',
88
+ * });
89
+ *
90
+ * // Master instance (shape defined by a reusable master)
91
+ * const m = doc.createMaster('Router', 'ellipse');
92
+ * await page.addShape({ text: '', x: 4, y: 2, width: 1, height: 1, masterId: m.id });
93
+ * ```
94
+ */
53
95
  addShape(props: NewShapeProps, parentId?: string): Promise<Shape>;
54
96
  /**
55
97
  * Return all connector shapes on the page.
@@ -57,19 +99,50 @@ export declare class Page {
57
99
  * and a `delete()` method to remove the connector.
58
100
  */
59
101
  getConnectors(): Connector[];
102
+ /**
103
+ * Draw a connector (line/arrow) between two shapes on this page.
104
+ *
105
+ * @param fromShape Source shape.
106
+ * @param toShape Target shape.
107
+ * @param beginArrow Arrow head at the source end (use {@link ArrowHeads} constants).
108
+ * @param endArrow Arrow head at the target end (use {@link ArrowHeads} constants).
109
+ * @param style Line color, weight, pattern, and routing style.
110
+ * @param fromPort Named connection point on the source shape (e.g. `'Right'`).
111
+ * @param toPort Named connection point on the target shape (e.g. `'Left'`).
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * import { ArrowHeads } from 'ts-visio';
116
+ * const a = await page.addShape({ text: 'A', x: 1, y: 1, width: 1, height: 1 });
117
+ * const b = await page.addShape({ text: 'B', x: 4, y: 1, width: 1, height: 1 });
118
+ * await page.connectShapes(a, b, ArrowHeads.None, ArrowHeads.OpenArrow,
119
+ * { lineColor: '#333333', routing: 'orthogonal' });
120
+ * ```
121
+ */
60
122
  connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle, fromPort?: ConnectionTarget, toPort?: ConnectionTarget): Promise<void>;
123
+ /**
124
+ * Embed an image on the page and return the resulting Foreign shape.
125
+ *
126
+ * @param data Raw image bytes (PNG, JPEG, GIF, BMP, or TIFF).
127
+ * @param name Filename used to store the image inside the archive (e.g. `'logo.png'`).
128
+ * @param x Horizontal pin position in inches.
129
+ * @param y Vertical pin position in inches.
130
+ * @param width Display width in inches.
131
+ * @param height Display height in inches.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * import fs from 'fs';
136
+ * const imgBuffer = fs.readFileSync('./logo.png');
137
+ * await page.addImage(imgBuffer, 'logo.png', 1, 1, 2, 1);
138
+ * ```
139
+ */
61
140
  addImage(data: Buffer, name: string, x: number, y: number, width: number, height: number): Promise<Shape>;
62
141
  addContainer(props: NewShapeProps): Promise<Shape>;
63
142
  addList(props: NewShapeProps, direction?: 'vertical' | 'horizontal'): Promise<Shape>;
64
- /**
65
- * Creates a Swimlane Pool (which is technically a Vertical List of Containers).
66
- * @param props Visual properties
67
- */
143
+ /** Creates a Swimlane Pool (a vertical List of Containers). */
68
144
  addSwimlanePool(props: NewShapeProps): Promise<Shape>;
69
- /**
70
- * Creates a Swimlane Lane (which is technically a Container).
71
- * @param props Visual properties
72
- */
145
+ /** Creates a Swimlane Lane (a Container inside a pool). */
73
146
  addSwimlaneLane(props: NewShapeProps): Promise<Shape>;
74
147
  addTable(x: number, y: number, title: string, columns: string[]): Promise<Shape>;
75
148
  addLayer(name: string, options?: {
@@ -86,6 +159,30 @@ export declare class Page {
86
159
  * // [{ name: 'Background', index: 0, visible: true, locked: false }, ...]
87
160
  */
88
161
  getLayers(): Layer[];
162
+ /**
163
+ * Return the current drawing scale, or `null` if no custom scale is set (1:1).
164
+ *
165
+ * @example
166
+ * const scale = page.getDrawingScale();
167
+ * // { pageScale: 1, pageUnit: 'in', drawingScale: 10, drawingUnit: 'ft' }
168
+ */
169
+ getDrawingScale(): DrawingScaleInfo | null;
170
+ /**
171
+ * Set a custom drawing scale for the page.
172
+ * One `pageScale` `pageUnit` on paper equals `drawingScale` `drawingUnit` in the real world.
173
+ *
174
+ * @example
175
+ * // 1 inch on paper = 10 feet in the real world
176
+ * page.setDrawingScale(1, 'in', 10, 'ft');
177
+ *
178
+ * // 1:100 metric
179
+ * page.setDrawingScale(1, 'cm', 100, 'cm');
180
+ */
181
+ setDrawingScale(pageScale: number, pageUnit: LengthUnit, drawingScale: number, drawingUnit: LengthUnit): this;
182
+ /**
183
+ * Remove any custom drawing scale, reverting the page to a 1:1 ratio.
184
+ */
185
+ clearDrawingScale(): this;
89
186
  /** @internal Used by VisioDocument.renamePage() to keep in-memory state in sync. */
90
187
  _updateName(newName: string): void;
91
188
  }
package/dist/Page.js CHANGED
@@ -10,6 +10,23 @@ const MediaManager_1 = require("./core/MediaManager");
10
10
  const RelsManager_1 = require("./core/RelsManager");
11
11
  const StubHelpers_1 = require("./utils/StubHelpers");
12
12
  const Layer_1 = require("./Layer");
13
+ const TablePattern_1 = require("./diagrams/TablePattern");
14
+ const SwimlanePattern_1 = require("./diagrams/SwimlanePattern");
15
+ /**
16
+ * Represents a single page (tab) inside a Visio document.
17
+ *
18
+ * Obtain a `Page` instance from {@link VisioDocument.pages},
19
+ * {@link VisioDocument.addPage}, or {@link VisioDocument.getPage}.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const doc = await VisioDocument.create();
24
+ * const page = doc.pages[0];
25
+ * await page.addShape({ text: 'Hello', x: 1, y: 1, width: 2, height: 1 });
26
+ * ```
27
+ *
28
+ * @category Pages
29
+ */
13
30
  class Page {
14
31
  constructor(internalPage, pkg, media, rels, modifier) {
15
32
  this.internalPage = internalPage;
@@ -73,6 +90,10 @@ class Page {
73
90
  }
74
91
  return this;
75
92
  }
93
+ /**
94
+ * Return all top-level shapes on the page.
95
+ * Group children are not included; use {@link findShapes} to search the entire shape tree.
96
+ */
76
97
  getShapes() {
77
98
  const reader = new ShapeReader_1.ShapeReader(this.pkg);
78
99
  try {
@@ -106,6 +127,29 @@ class Page {
106
127
  .map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier))
107
128
  .filter(predicate);
108
129
  }
130
+ /**
131
+ * Add a new shape to the page and return a {@link Shape} handle to it.
132
+ *
133
+ * @param props Visual and text properties for the new shape.
134
+ * All geometry fields (`x`, `y`, `width`, `height`) are in inches.
135
+ * @param parentId Optional ID of an existing group shape to nest the new shape inside.
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // Plain rectangle
140
+ * const box = await page.addShape({ text: 'Server', x: 2, y: 3, width: 2, height: 1 });
141
+ *
142
+ * // Ellipse with styling
143
+ * await page.addShape({
144
+ * text: 'Start', x: 1, y: 1, width: 1.5, height: 1.5,
145
+ * geometry: 'ellipse', fillColor: '#4472C4', fontColor: '#ffffff',
146
+ * });
147
+ *
148
+ * // Master instance (shape defined by a reusable master)
149
+ * const m = doc.createMaster('Router', 'ellipse');
150
+ * await page.addShape({ text: '', x: 4, y: 2, width: 1, height: 1, masterId: m.id });
151
+ * ```
152
+ */
109
153
  async addShape(props, parentId) {
110
154
  const newId = await this.modifier.addShape(this.id, props, parentId);
111
155
  // Return a fresh Shape object representing the new shape
@@ -142,15 +186,49 @@ class Page {
142
186
  return [];
143
187
  }
144
188
  }
189
+ /**
190
+ * Draw a connector (line/arrow) between two shapes on this page.
191
+ *
192
+ * @param fromShape Source shape.
193
+ * @param toShape Target shape.
194
+ * @param beginArrow Arrow head at the source end (use {@link ArrowHeads} constants).
195
+ * @param endArrow Arrow head at the target end (use {@link ArrowHeads} constants).
196
+ * @param style Line color, weight, pattern, and routing style.
197
+ * @param fromPort Named connection point on the source shape (e.g. `'Right'`).
198
+ * @param toPort Named connection point on the target shape (e.g. `'Left'`).
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * import { ArrowHeads } from 'ts-visio';
203
+ * const a = await page.addShape({ text: 'A', x: 1, y: 1, width: 1, height: 1 });
204
+ * const b = await page.addShape({ text: 'B', x: 4, y: 1, width: 1, height: 1 });
205
+ * await page.connectShapes(a, b, ArrowHeads.None, ArrowHeads.OpenArrow,
206
+ * { lineColor: '#333333', routing: 'orthogonal' });
207
+ * ```
208
+ */
145
209
  async connectShapes(fromShape, toShape, beginArrow, endArrow, style, fromPort, toPort) {
146
210
  await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow, style, fromPort, toPort);
147
211
  }
212
+ /**
213
+ * Embed an image on the page and return the resulting Foreign shape.
214
+ *
215
+ * @param data Raw image bytes (PNG, JPEG, GIF, BMP, or TIFF).
216
+ * @param name Filename used to store the image inside the archive (e.g. `'logo.png'`).
217
+ * @param x Horizontal pin position in inches.
218
+ * @param y Vertical pin position in inches.
219
+ * @param width Display width in inches.
220
+ * @param height Display height in inches.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * import fs from 'fs';
225
+ * const imgBuffer = fs.readFileSync('./logo.png');
226
+ * await page.addImage(imgBuffer, 'logo.png', 1, 1, 2, 1);
227
+ * ```
228
+ */
148
229
  async addImage(data, name, x, y, width, height) {
149
- // 1. Upload Media
150
230
  const mediaPath = this.media.addMedia(name, data);
151
- // 2. Link Page to Media (use resolved path so loaded files work correctly)
152
231
  const rId = await this.rels.addImageRelationship(this.pagePath, mediaPath);
153
- // 3. Create Shape
154
232
  const newId = await this.modifier.addShape(this.id, {
155
233
  text: '',
156
234
  x, y, width, height,
@@ -197,72 +275,16 @@ class Page {
197
275
  });
198
276
  return new Shape_1.Shape(internalStub, this.id, this.pkg, this.modifier);
199
277
  }
200
- /**
201
- * Creates a Swimlane Pool (which is technically a Vertical List of Containers).
202
- * @param props Visual properties
203
- */
278
+ /** Creates a Swimlane Pool (a vertical List of Containers). */
204
279
  async addSwimlanePool(props) {
205
- // A Pool is just a vertical list
206
- return this.addList(props, 'vertical');
280
+ return SwimlanePattern_1.SwimlanePattern.addPool(this, props);
207
281
  }
208
- /**
209
- * Creates a Swimlane Lane (which is technically a Container).
210
- * @param props Visual properties
211
- */
282
+ /** Creates a Swimlane Lane (a Container inside a pool). */
212
283
  async addSwimlaneLane(props) {
213
- // A Lane is just a container
214
- return this.addContainer(props);
284
+ return SwimlanePattern_1.SwimlanePattern.addLane(this, props);
215
285
  }
216
286
  async addTable(x, y, title, columns) {
217
- // ... (previous implementation)
218
- // Dimensions
219
- const width = 3;
220
- const headerHeight = 0.5;
221
- const lineItemHeight = 0.25;
222
- const bodyHeight = Math.max(0.5, columns.length * lineItemHeight + 0.1); // Min height
223
- const totalHeight = headerHeight + bodyHeight;
224
- // 1. Create Main Group Shape (Transparent container)
225
- // Group Logic:
226
- // Positioned at (x, y) on the Page.
227
- // Size encapsulates both header and body.
228
- const groupShape = await this.addShape({
229
- text: '', // No text on container
230
- x: x,
231
- y: y,
232
- width: width,
233
- height: totalHeight,
234
- type: 'Group'
235
- });
236
- // 2. Header Shape (Inside Group)
237
- // Coords relative to Group (Bottom-Left is 0,0)
238
- // Header is at top. Center X is Width/2.
239
- // Center Y = BodyHeight + (HeaderHeight/2)
240
- const headerCenterY = bodyHeight + (headerHeight / 2);
241
- await this.addShape({
242
- text: title,
243
- x: width / 2, // Relative PinX
244
- y: headerCenterY, // Relative PinY
245
- width: width,
246
- height: headerHeight,
247
- fillColor: '#DDDDDD',
248
- bold: true
249
- }, groupShape.id);
250
- // 3. Body Shape (Inside Group)
251
- // Bottom part. Center X is Width/2.
252
- // Center Y = BodyHeight/2
253
- const bodyCenterY = bodyHeight / 2;
254
- const bodyText = columns.join('\n');
255
- await this.addShape({
256
- text: bodyText,
257
- x: width / 2, // Relative PinX
258
- y: bodyCenterY, // Relative PinY
259
- width: width,
260
- height: bodyHeight,
261
- fillColor: '#FFFFFF',
262
- fontColor: '#000000'
263
- }, groupShape.id);
264
- // Return the Group Shape
265
- return groupShape;
287
+ return TablePattern_1.TablePattern.add(this, x, y, title, columns);
266
288
  }
267
289
  async addLayer(name, options) {
268
290
  const info = await this.modifier.addLayer(this.id, name, options);
@@ -280,6 +302,38 @@ class Page {
280
302
  const infos = this.modifier.getPageLayers(this.id);
281
303
  return infos.map(l => new Layer_1.Layer(l.name, l.index, this.id, this.pkg, this.modifier, l.visible, l.locked));
282
304
  }
305
+ /**
306
+ * Return the current drawing scale, or `null` if no custom scale is set (1:1).
307
+ *
308
+ * @example
309
+ * const scale = page.getDrawingScale();
310
+ * // { pageScale: 1, pageUnit: 'in', drawingScale: 10, drawingUnit: 'ft' }
311
+ */
312
+ getDrawingScale() {
313
+ return this.modifier.getDrawingScale(this.id);
314
+ }
315
+ /**
316
+ * Set a custom drawing scale for the page.
317
+ * One `pageScale` `pageUnit` on paper equals `drawingScale` `drawingUnit` in the real world.
318
+ *
319
+ * @example
320
+ * // 1 inch on paper = 10 feet in the real world
321
+ * page.setDrawingScale(1, 'in', 10, 'ft');
322
+ *
323
+ * // 1:100 metric
324
+ * page.setDrawingScale(1, 'cm', 100, 'cm');
325
+ */
326
+ setDrawingScale(pageScale, pageUnit, drawingScale, drawingUnit) {
327
+ this.modifier.setDrawingScale(this.id, pageScale, pageUnit, drawingScale, drawingUnit);
328
+ return this;
329
+ }
330
+ /**
331
+ * Remove any custom drawing scale, reverting the page to a 1:1 ratio.
332
+ */
333
+ clearDrawingScale() {
334
+ this.modifier.clearDrawingScale(this.id);
335
+ return this;
336
+ }
283
337
  /** @internal Used by VisioDocument.renamePage() to keep in-memory state in sync. */
284
338
  _updateName(newName) {
285
339
  this.internalPage.Name = newName;
package/dist/Shape.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { VisioShape, ConnectorStyle, ConnectionTarget, ConnectionPointDef } from './types/VisioTypes';
1
+ import { VisioShape, ConnectorStyle, ConnectionTarget, ConnectionPointDef, ShapeStyle } from './types/VisioTypes';
2
2
  import { VisioPackage } from './VisioPackage';
3
- import { ShapeModifier, ShapeStyle } from './ShapeModifier';
3
+ import { ShapeModifier } from './ShapeModifier';
4
4
  import { VisioPropType } from './types/VisioTypes';
5
5
  import { Layer } from './Layer';
6
6
  export interface ShapeData {
@@ -15,6 +15,21 @@ export interface ShapeHyperlink {
15
15
  description?: string;
16
16
  newWindow: boolean;
17
17
  }
18
+ /**
19
+ * A handle to a single shape on a Visio page.
20
+ *
21
+ * Obtain instances via {@link Page.addShape}, {@link Page.getShapes},
22
+ * {@link Page.getShapeById}, or {@link Page.findShapes}.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const shape = await page.addShape({ text: 'Box', x: 1, y: 1, width: 2, height: 1 });
27
+ * await shape.setStyle({ fillColor: '#4472C4', fontColor: '#ffffff', bold: true });
28
+ * console.log(shape.id, shape.x, shape.y);
29
+ * ```
30
+ *
31
+ * @category Shapes
32
+ */
18
33
  export declare class Shape {
19
34
  private internalShape;
20
35
  private pageId;
package/dist/Shape.js CHANGED
@@ -8,6 +8,21 @@ const VisioConstants_1 = require("./core/VisioConstants");
8
8
  function fmtCoord(n) {
9
9
  return parseFloat(n.toFixed(10)).toString();
10
10
  }
11
+ /**
12
+ * A handle to a single shape on a Visio page.
13
+ *
14
+ * Obtain instances via {@link Page.addShape}, {@link Page.getShapes},
15
+ * {@link Page.getShapeById}, or {@link Page.findShapes}.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const shape = await page.addShape({ text: 'Box', x: 1, y: 1, width: 2, height: 1 });
20
+ * await shape.setStyle({ fillColor: '#4472C4', fontColor: '#ffffff', bold: true });
21
+ * console.log(shape.id, shape.x, shape.y);
22
+ * ```
23
+ *
24
+ * @category Shapes
25
+ */
11
26
  class Shape {
12
27
  constructor(internalShape, pageId, pkg, modifier) {
13
28
  this.internalShape = internalShape;