ts-visio 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -7
- package/dist/Page.d.ts +33 -2
- package/dist/Page.js +70 -3
- package/dist/Shape.d.ts +45 -2
- package/dist/Shape.js +77 -2
- package/dist/ShapeModifier.d.ts +59 -2
- package/dist/ShapeModifier.js +309 -5
- package/dist/ShapeReader.d.ts +12 -0
- package/dist/ShapeReader.js +59 -3
- package/dist/VisioDocument.d.ts +10 -0
- package/dist/VisioDocument.js +15 -0
- package/dist/VisioPackage.d.ts +1 -0
- package/dist/VisioPackage.js +7 -0
- package/dist/core/PageManager.d.ts +7 -0
- package/dist/core/PageManager.js +63 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -1
- package/dist/shapes/ConnectorBuilder.d.ts +2 -1
- package/dist/shapes/ConnectorBuilder.js +14 -4
- package/dist/shapes/ForeignShapeBuilder.js +2 -2
- package/dist/shapes/GeometryBuilder.d.ts +42 -0
- package/dist/shapes/GeometryBuilder.js +177 -0
- package/dist/shapes/ShapeBuilder.js +14 -16
- package/dist/types/VisioTypes.d.ts +65 -0
- package/dist/types/VisioTypes.js +10 -1
- package/dist/utils/StyleHelpers.d.ts +21 -0
- package/dist/utils/StyleHelpers.js +51 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,18 +8,24 @@
|
|
|
8
8
|
A Node.js library to strict-type interact with Visio (`.vsdx`) files.
|
|
9
9
|
Built using specific schema-level abstractions to handle the complex internal structure of Visio documents (ShapeSheets, Pages, Masters).
|
|
10
10
|
|
|
11
|
-
> **Status**: Work In Progress (TDD).
|
|
12
|
-
|
|
13
11
|
## Features
|
|
14
12
|
|
|
15
|
-
- **Read VSDX**: Open and parse `.vsdx` files (
|
|
13
|
+
- **Read VSDX**: Open and parse `.vsdx` files (zipped XML).
|
|
16
14
|
- **Strict Typing**: Interact with `VisioPage`, `VisioShape`, and `VisioConnect` objects.
|
|
17
15
|
- **ShapeSheet Access**: Read `Cells`, `Rows`, and `Sections` directly.
|
|
18
16
|
- **Connections**: Analyze connectivity between shapes.
|
|
19
17
|
- **Modular Architecture**: Use specialized components for loading, page management, shape reading, and modification.
|
|
20
18
|
- **Modify Content**: Update text content of shapes.
|
|
21
|
-
- **Create Shapes**:
|
|
22
|
-
- **Connect Shapes**:
|
|
19
|
+
- **Create Shapes**: Rectangles, ellipses, diamonds, rounded rectangles, triangles, parallelograms.
|
|
20
|
+
- **Connect Shapes**: Dynamic connectors with arrow styles, line styling, and routing (straight / orthogonal / curved).
|
|
21
|
+
- **Text Styling**: Font size, font family, bold, color, horizontal/vertical alignment.
|
|
22
|
+
- **Shape Transformations**: Rotate, flip (X/Y), and resize shapes via a fluent API.
|
|
23
|
+
- **Deletion**: Remove shapes and pages cleanly (including orphaned connectors and relationships).
|
|
24
|
+
- **Lookup API**: Find shapes by ID, predicate, or look up pages by name.
|
|
25
|
+
- **Read-Back API**: Read custom properties, hyperlinks, and layer assignments from existing shapes.
|
|
26
|
+
- **Page Size & Orientation**: Set canvas dimensions with named sizes (`Letter`, `A4`, …) or raw inches; rotate between portrait and landscape.
|
|
27
|
+
|
|
28
|
+
Feature gaps are being tracked in [FEATURES.md](./FEATURES.md).
|
|
23
29
|
|
|
24
30
|
## Installation
|
|
25
31
|
|
|
@@ -63,9 +69,13 @@ const shape = await page.addShape({
|
|
|
63
69
|
y: 1,
|
|
64
70
|
width: 3,
|
|
65
71
|
height: 1,
|
|
66
|
-
fillColor: "#ff0000",
|
|
72
|
+
fillColor: "#ff0000", // Hex fill color
|
|
67
73
|
fontColor: "#ffffff",
|
|
68
|
-
bold: true
|
|
74
|
+
bold: true,
|
|
75
|
+
fontSize: 14, // Points
|
|
76
|
+
fontFamily: "Segoe UI",
|
|
77
|
+
horzAlign: "center", // "left" | "center" | "right" | "justify"
|
|
78
|
+
verticalAlign: "middle" // "top" | "middle" | "bottom"
|
|
69
79
|
});
|
|
70
80
|
|
|
71
81
|
// Modify text
|
|
@@ -345,6 +355,141 @@ await lane1.addMember(startShape);
|
|
|
345
355
|
await lane2.addMember(serverShape);
|
|
346
356
|
```
|
|
347
357
|
|
|
358
|
+
#### 19. Shape Transformations
|
|
359
|
+
Rotate, flip, and resize shapes using a fluent API.
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const shape = await page.addShape({ text: "Widget", x: 3, y: 3, width: 2, height: 1 });
|
|
363
|
+
|
|
364
|
+
// Rotate 45 degrees (clockwise)
|
|
365
|
+
await shape.rotate(45);
|
|
366
|
+
console.log(shape.angle); // 45
|
|
367
|
+
|
|
368
|
+
// Mirror horizontally or vertically
|
|
369
|
+
await shape.flipX();
|
|
370
|
+
await shape.flipY(false); // un-flip
|
|
371
|
+
|
|
372
|
+
// Resize (keeps the pin point centred)
|
|
373
|
+
await shape.resize(4, 2);
|
|
374
|
+
console.log(shape.width, shape.height); // 4, 2
|
|
375
|
+
|
|
376
|
+
// Chainable
|
|
377
|
+
await shape.rotate(90).then(s => s.resize(3, 1));
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### 20. Deleting Shapes and Pages
|
|
381
|
+
Remove shapes or entire pages. Orphaned connectors and relationships are cleaned up automatically.
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
// Delete a shape
|
|
385
|
+
await shape.delete();
|
|
386
|
+
|
|
387
|
+
// Delete a page (removes page file, rels, and all back-page references)
|
|
388
|
+
await doc.deletePage(page2);
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### 21. Lookup API
|
|
392
|
+
Find shapes and pages without iterating manually.
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
// Find a shape by its numeric ID (searches nested groups too)
|
|
396
|
+
const target = await page.getShapeById("42");
|
|
397
|
+
|
|
398
|
+
// Find all shapes matching a predicate
|
|
399
|
+
const servers = await page.findShapes(s => s.text.startsWith("Server"));
|
|
400
|
+
|
|
401
|
+
// Look up a page by name (exact, case-sensitive)
|
|
402
|
+
const detailPage = doc.getPage("Architecture Diagram");
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### 22. Reading Shape Data Back
|
|
406
|
+
Retrieve custom properties, hyperlinks, and layer assignments that were previously written.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// Custom properties (shape data)
|
|
410
|
+
const props = shape.getProperties();
|
|
411
|
+
console.log(props["IP"].value); // "192.168.1.10"
|
|
412
|
+
console.log(props["Port"].type); // VisioPropType.Number
|
|
413
|
+
|
|
414
|
+
// Hyperlinks
|
|
415
|
+
const links = shape.getHyperlinks();
|
|
416
|
+
// [ { address: "https://example.com", description: "Docs", newWindow: false } ]
|
|
417
|
+
|
|
418
|
+
// Layer indices
|
|
419
|
+
const indices = shape.getLayerIndices(); // e.g. [0, 2]
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### 23. Non-Rectangular Geometry
|
|
423
|
+
Use the `geometry` prop on `addShape()` to create common flowchart primitives without touching XML.
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
// Ellipse / circle
|
|
427
|
+
await page.addShape({ text: "Start", x: 1, y: 5, width: 2, height: 2, geometry: 'ellipse' });
|
|
428
|
+
|
|
429
|
+
// Decision diamond
|
|
430
|
+
await page.addShape({ text: "Yes?", x: 4, y: 5, width: 2, height: 2, geometry: 'diamond' });
|
|
431
|
+
|
|
432
|
+
// Rounded rectangle (optional corner radius in inches)
|
|
433
|
+
await page.addShape({ text: "Process", x: 7, y: 5, width: 3, height: 2,
|
|
434
|
+
geometry: 'rounded-rectangle', cornerRadius: 0.2 });
|
|
435
|
+
|
|
436
|
+
// Right-pointing triangle
|
|
437
|
+
await page.addShape({ text: "Extract", x: 1, y: 2, width: 2, height: 2, geometry: 'triangle' });
|
|
438
|
+
|
|
439
|
+
// Parallelogram (Data / IO shape)
|
|
440
|
+
await page.addShape({ text: "Input", x: 4, y: 2, width: 3, height: 1.5, geometry: 'parallelogram' });
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Supported values: `'rectangle'` (default), `'ellipse'`, `'diamond'`, `'rounded-rectangle'`, `'triangle'`, `'parallelogram'`.
|
|
444
|
+
|
|
445
|
+
#### 24. Connector Styling
|
|
446
|
+
Control line appearance and routing algorithm on any connector.
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
import { ArrowHeads } from 'ts-visio/utils/StyleHelpers';
|
|
450
|
+
|
|
451
|
+
// Styled connector with crow's foot arrow and custom line
|
|
452
|
+
await shape1.connectTo(shape2, ArrowHeads.One, ArrowHeads.CrowsFoot, {
|
|
453
|
+
lineColor: '#cc0000', // Hex stroke color
|
|
454
|
+
lineWeight: 1.5, // Stroke width in points
|
|
455
|
+
linePattern: 2, // 1=solid, 2=dash, 3=dot, 4=dash-dot
|
|
456
|
+
routing: 'curved', // 'straight' | 'orthogonal' (default) | 'curved'
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// Via page.connectShapes()
|
|
460
|
+
await page.connectShapes(a, b, undefined, undefined, { routing: 'straight' });
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
#### 25. Page Size & Orientation
|
|
464
|
+
Control the canvas dimensions using named paper sizes or raw inch values.
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
import { PageSizes } from 'ts-visio';
|
|
468
|
+
|
|
469
|
+
// Use a named paper size (portrait by default)
|
|
470
|
+
page.setNamedSize('A4'); // 8.268" × 11.693"
|
|
471
|
+
page.setNamedSize('Letter', 'landscape'); // 11" × 8.5"
|
|
472
|
+
|
|
473
|
+
// Set arbitrary dimensions in inches
|
|
474
|
+
page.setSize(13.33, 7.5); // 13.33" × 7.5" widescreen
|
|
475
|
+
|
|
476
|
+
// Rotate the existing canvas without changing the paper size
|
|
477
|
+
page.setOrientation('landscape'); // swaps width and height if needed
|
|
478
|
+
page.setOrientation('portrait');
|
|
479
|
+
|
|
480
|
+
// Read current dimensions
|
|
481
|
+
console.log(page.pageWidth); // e.g. 11
|
|
482
|
+
console.log(page.pageHeight); // e.g. 8.5
|
|
483
|
+
console.log(page.orientation); // 'landscape' | 'portrait'
|
|
484
|
+
|
|
485
|
+
// All size methods are chainable
|
|
486
|
+
page.setNamedSize('A3').setOrientation('landscape');
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Available named sizes in `PageSizes`: `Letter`, `Legal`, `Tabloid`, `A3`, `A4`, `A5`.
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
348
493
|
## Examples
|
|
349
494
|
|
|
350
495
|
Check out the [examples](./examples) directory for complete scripts.
|
package/dist/Page.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VisioPage } from './types/VisioTypes';
|
|
1
|
+
import { VisioPage, ConnectorStyle, PageOrientation, PageSizeName } from './types/VisioTypes';
|
|
2
2
|
import { VisioPackage } from './VisioPackage';
|
|
3
3
|
import { ShapeModifier } from './ShapeModifier';
|
|
4
4
|
import { NewShapeProps } from './types/VisioTypes';
|
|
@@ -17,9 +17,40 @@ export declare class Page {
|
|
|
17
17
|
constructor(internalPage: VisioPage, pkg: VisioPackage, media?: MediaManager, rels?: RelsManager, modifier?: ShapeModifier);
|
|
18
18
|
get id(): string;
|
|
19
19
|
get name(): string;
|
|
20
|
+
/** Width of the page canvas in inches. */
|
|
21
|
+
get pageWidth(): number;
|
|
22
|
+
/** Height of the page canvas in inches. */
|
|
23
|
+
get pageHeight(): number;
|
|
24
|
+
/** Current page orientation derived from the canvas dimensions. */
|
|
25
|
+
get orientation(): PageOrientation;
|
|
26
|
+
/**
|
|
27
|
+
* Set the page canvas size in inches.
|
|
28
|
+
* @example page.setSize(11, 8.5) // landscape letter
|
|
29
|
+
*/
|
|
30
|
+
setSize(width: number, height: number): this;
|
|
31
|
+
/**
|
|
32
|
+
* Convenience: change the page to a named standard size (portrait by default).
|
|
33
|
+
* @example page.setNamedSize('A4')
|
|
34
|
+
*/
|
|
35
|
+
setNamedSize(sizeName: PageSizeName, orientation?: PageOrientation): this;
|
|
36
|
+
/**
|
|
37
|
+
* Rotate the canvas between portrait and landscape without changing the paper size.
|
|
38
|
+
* Swaps width and height when the current orientation does not match the requested one.
|
|
39
|
+
*/
|
|
40
|
+
setOrientation(orientation: PageOrientation): this;
|
|
20
41
|
getShapes(): Shape[];
|
|
42
|
+
/**
|
|
43
|
+
* Find a shape by its ID anywhere on the page, including shapes nested inside groups.
|
|
44
|
+
* Returns undefined if no shape with that ID exists.
|
|
45
|
+
*/
|
|
46
|
+
getShapeById(id: string): Shape | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Return all shapes on the page (including nested group children) that satisfy
|
|
49
|
+
* the predicate. Equivalent to getAllShapes().filter(predicate).
|
|
50
|
+
*/
|
|
51
|
+
findShapes(predicate: (shape: Shape) => boolean): Shape[];
|
|
21
52
|
addShape(props: NewShapeProps, parentId?: string): Promise<Shape>;
|
|
22
|
-
connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string): Promise<void>;
|
|
53
|
+
connectShapes(fromShape: Shape, toShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<void>;
|
|
23
54
|
addImage(data: Buffer, name: string, x: number, y: number, width: number, height: number): Promise<Shape>;
|
|
24
55
|
addContainer(props: NewShapeProps): Promise<Shape>;
|
|
25
56
|
addList(props: NewShapeProps, direction?: 'vertical' | 'horizontal'): Promise<Shape>;
|
package/dist/Page.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Page = void 0;
|
|
4
|
+
const VisioTypes_1 = require("./types/VisioTypes");
|
|
4
5
|
const ShapeReader_1 = require("./ShapeReader");
|
|
5
6
|
const ShapeModifier_1 = require("./ShapeModifier");
|
|
6
7
|
const Shape_1 = require("./Shape");
|
|
@@ -26,6 +27,51 @@ class Page {
|
|
|
26
27
|
get name() {
|
|
27
28
|
return this.internalPage.Name;
|
|
28
29
|
}
|
|
30
|
+
/** Width of the page canvas in inches. */
|
|
31
|
+
get pageWidth() {
|
|
32
|
+
return this.modifier.getPageDimensions(this.id).width;
|
|
33
|
+
}
|
|
34
|
+
/** Height of the page canvas in inches. */
|
|
35
|
+
get pageHeight() {
|
|
36
|
+
return this.modifier.getPageDimensions(this.id).height;
|
|
37
|
+
}
|
|
38
|
+
/** Current page orientation derived from the canvas dimensions. */
|
|
39
|
+
get orientation() {
|
|
40
|
+
return this.pageWidth > this.pageHeight ? 'landscape' : 'portrait';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the page canvas size in inches.
|
|
44
|
+
* @example page.setSize(11, 8.5) // landscape letter
|
|
45
|
+
*/
|
|
46
|
+
setSize(width, height) {
|
|
47
|
+
this.modifier.setPageSize(this.id, width, height);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convenience: change the page to a named standard size (portrait by default).
|
|
52
|
+
* @example page.setNamedSize('A4')
|
|
53
|
+
*/
|
|
54
|
+
setNamedSize(sizeName, orientation = 'portrait') {
|
|
55
|
+
const { width, height } = VisioTypes_1.PageSizes[sizeName];
|
|
56
|
+
return orientation === 'landscape'
|
|
57
|
+
? this.setSize(height, width)
|
|
58
|
+
: this.setSize(width, height);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Rotate the canvas between portrait and landscape without changing the paper size.
|
|
62
|
+
* Swaps width and height when the current orientation does not match the requested one.
|
|
63
|
+
*/
|
|
64
|
+
setOrientation(orientation) {
|
|
65
|
+
const w = this.pageWidth;
|
|
66
|
+
const h = this.pageHeight;
|
|
67
|
+
if (orientation === 'landscape' && h > w) {
|
|
68
|
+
this.modifier.setPageSize(this.id, h, w);
|
|
69
|
+
}
|
|
70
|
+
else if (orientation === 'portrait' && w > h) {
|
|
71
|
+
this.modifier.setPageSize(this.id, h, w);
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
29
75
|
getShapes() {
|
|
30
76
|
const reader = new ShapeReader_1.ShapeReader(this.pkg);
|
|
31
77
|
try {
|
|
@@ -33,11 +79,32 @@ class Page {
|
|
|
33
79
|
return internalShapes.map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier));
|
|
34
80
|
}
|
|
35
81
|
catch (e) {
|
|
36
|
-
// If page file doesn't exist or is empty, return empty array
|
|
37
82
|
console.warn(`Could not read shapes for page ${this.id}:`, e);
|
|
38
83
|
return [];
|
|
39
84
|
}
|
|
40
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Find a shape by its ID anywhere on the page, including shapes nested inside groups.
|
|
88
|
+
* Returns undefined if no shape with that ID exists.
|
|
89
|
+
*/
|
|
90
|
+
getShapeById(id) {
|
|
91
|
+
const reader = new ShapeReader_1.ShapeReader(this.pkg);
|
|
92
|
+
const internal = reader.readShapeById(this.pagePath, id);
|
|
93
|
+
if (!internal)
|
|
94
|
+
return undefined;
|
|
95
|
+
return new Shape_1.Shape(internal, this.id, this.pkg, this.modifier);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Return all shapes on the page (including nested group children) that satisfy
|
|
99
|
+
* the predicate. Equivalent to getAllShapes().filter(predicate).
|
|
100
|
+
*/
|
|
101
|
+
findShapes(predicate) {
|
|
102
|
+
const reader = new ShapeReader_1.ShapeReader(this.pkg);
|
|
103
|
+
const all = reader.readAllShapes(this.pagePath);
|
|
104
|
+
return all
|
|
105
|
+
.map(s => new Shape_1.Shape(s, this.id, this.pkg, this.modifier))
|
|
106
|
+
.filter(predicate);
|
|
107
|
+
}
|
|
41
108
|
async addShape(props, parentId) {
|
|
42
109
|
const newId = await this.modifier.addShape(this.id, props, parentId);
|
|
43
110
|
// Return a fresh Shape object representing the new shape
|
|
@@ -57,8 +124,8 @@ class Page {
|
|
|
57
124
|
});
|
|
58
125
|
return new Shape_1.Shape(internalStub, this.id, this.pkg, this.modifier);
|
|
59
126
|
}
|
|
60
|
-
async connectShapes(fromShape, toShape, beginArrow, endArrow) {
|
|
61
|
-
await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow);
|
|
127
|
+
async connectShapes(fromShape, toShape, beginArrow, endArrow, style) {
|
|
128
|
+
await this.modifier.addConnector(this.id, fromShape.id, toShape.id, beginArrow, endArrow, style);
|
|
62
129
|
}
|
|
63
130
|
async addImage(data, name, x, y, width, height) {
|
|
64
131
|
// 1. Upload Media
|
package/dist/Shape.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VisioShape } from './types/VisioTypes';
|
|
1
|
+
import { VisioShape, ConnectorStyle } from './types/VisioTypes';
|
|
2
2
|
import { VisioPackage } from './VisioPackage';
|
|
3
3
|
import { ShapeModifier, ShapeStyle } from './ShapeModifier';
|
|
4
4
|
import { VisioPropType } from './types/VisioTypes';
|
|
@@ -9,6 +9,12 @@ export interface ShapeData {
|
|
|
9
9
|
hidden?: boolean;
|
|
10
10
|
type?: VisioPropType;
|
|
11
11
|
}
|
|
12
|
+
export interface ShapeHyperlink {
|
|
13
|
+
address?: string;
|
|
14
|
+
subAddress?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
newWindow: boolean;
|
|
17
|
+
}
|
|
12
18
|
export declare class Shape {
|
|
13
19
|
private internalShape;
|
|
14
20
|
private pageId;
|
|
@@ -23,7 +29,8 @@ export declare class Shape {
|
|
|
23
29
|
get height(): number;
|
|
24
30
|
get x(): number;
|
|
25
31
|
get y(): number;
|
|
26
|
-
|
|
32
|
+
delete(): Promise<void>;
|
|
33
|
+
connectTo(targetShape: Shape, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<this>;
|
|
27
34
|
setStyle(style: ShapeStyle): Promise<this>;
|
|
28
35
|
placeRightOf(targetShape: Shape, options?: {
|
|
29
36
|
gap: number;
|
|
@@ -37,6 +44,41 @@ export declare class Shape {
|
|
|
37
44
|
}): this;
|
|
38
45
|
setPropertyValue(name: string, value: string | number | boolean | Date): this;
|
|
39
46
|
addData(key: string, data: ShapeData): this;
|
|
47
|
+
/**
|
|
48
|
+
* Read back all custom property (shape data) entries written to this shape.
|
|
49
|
+
* Returns a map of property key → ShapeData. Values are coerced to the
|
|
50
|
+
* declared Visio type (Number, Boolean, Date, or String).
|
|
51
|
+
*/
|
|
52
|
+
getProperties(): Record<string, ShapeData>;
|
|
53
|
+
/**
|
|
54
|
+
* Read back all hyperlinks attached to this shape.
|
|
55
|
+
*/
|
|
56
|
+
getHyperlinks(): ShapeHyperlink[];
|
|
57
|
+
/**
|
|
58
|
+
* Read back the layer indices this shape is assigned to.
|
|
59
|
+
* Returns an empty array if the shape has no layer assignment.
|
|
60
|
+
*/
|
|
61
|
+
getLayerIndices(): number[];
|
|
62
|
+
/** Current rotation angle in degrees (0 if no Angle cell is set). */
|
|
63
|
+
get angle(): number;
|
|
64
|
+
/**
|
|
65
|
+
* Rotate the shape to an absolute angle (degrees, clockwise).
|
|
66
|
+
* Replaces any existing rotation.
|
|
67
|
+
*/
|
|
68
|
+
rotate(degrees: number): Promise<this>;
|
|
69
|
+
/**
|
|
70
|
+
* Resize the shape to the given width and height (in inches).
|
|
71
|
+
* Updates LocPinX/LocPinY to keep the centre-pin at width/2, height/2.
|
|
72
|
+
*/
|
|
73
|
+
resize(width: number, height: number): Promise<this>;
|
|
74
|
+
/**
|
|
75
|
+
* Flip the shape horizontally. Pass `false` to un-flip.
|
|
76
|
+
*/
|
|
77
|
+
flipX(enabled?: boolean): Promise<this>;
|
|
78
|
+
/**
|
|
79
|
+
* Flip the shape vertically. Pass `false` to un-flip.
|
|
80
|
+
*/
|
|
81
|
+
flipY(enabled?: boolean): Promise<this>;
|
|
40
82
|
addMember(memberShape: Shape): Promise<this>;
|
|
41
83
|
addListItem(item: Shape): Promise<this>;
|
|
42
84
|
resizeToFit(padding?: number): Promise<this>;
|
|
@@ -67,4 +109,5 @@ export declare class Shape {
|
|
|
67
109
|
*/
|
|
68
110
|
addToLayer(layer: Layer | number): Promise<this>;
|
|
69
111
|
private setLocalCoord;
|
|
112
|
+
private setLocalRawCell;
|
|
70
113
|
}
|
package/dist/Shape.js
CHANGED
|
@@ -39,8 +39,11 @@ class Shape {
|
|
|
39
39
|
get y() {
|
|
40
40
|
return this.internalShape.Cells['PinY'] ? Number(this.internalShape.Cells['PinY'].V) : 0;
|
|
41
41
|
}
|
|
42
|
-
async
|
|
43
|
-
await this.modifier.
|
|
42
|
+
async delete() {
|
|
43
|
+
await this.modifier.deleteShape(this.pageId, this.id);
|
|
44
|
+
}
|
|
45
|
+
async connectTo(targetShape, beginArrow, endArrow, style) {
|
|
46
|
+
await this.modifier.addConnector(this.pageId, this.id, targetShape.id, beginArrow, endArrow, style);
|
|
44
47
|
return this;
|
|
45
48
|
}
|
|
46
49
|
async setStyle(style) {
|
|
@@ -96,6 +99,72 @@ class Shape {
|
|
|
96
99
|
this.setPropertyValue(key, data.value);
|
|
97
100
|
return this;
|
|
98
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Read back all custom property (shape data) entries written to this shape.
|
|
104
|
+
* Returns a map of property key → ShapeData. Values are coerced to the
|
|
105
|
+
* declared Visio type (Number, Boolean, Date, or String).
|
|
106
|
+
*/
|
|
107
|
+
getProperties() {
|
|
108
|
+
return this.modifier.getShapeProperties(this.pageId, this.id);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Read back all hyperlinks attached to this shape.
|
|
112
|
+
*/
|
|
113
|
+
getHyperlinks() {
|
|
114
|
+
return this.modifier.getShapeHyperlinks(this.pageId, this.id);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Read back the layer indices this shape is assigned to.
|
|
118
|
+
* Returns an empty array if the shape has no layer assignment.
|
|
119
|
+
*/
|
|
120
|
+
getLayerIndices() {
|
|
121
|
+
return this.modifier.getShapeLayerIndices(this.pageId, this.id);
|
|
122
|
+
}
|
|
123
|
+
/** Current rotation angle in degrees (0 if no Angle cell is set). */
|
|
124
|
+
get angle() {
|
|
125
|
+
const cell = this.internalShape.Cells['Angle'];
|
|
126
|
+
return cell ? (parseFloat(cell.V) * 180) / Math.PI : 0;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Rotate the shape to an absolute angle (degrees, clockwise).
|
|
130
|
+
* Replaces any existing rotation.
|
|
131
|
+
*/
|
|
132
|
+
async rotate(degrees) {
|
|
133
|
+
await this.modifier.rotateShape(this.pageId, this.id, degrees);
|
|
134
|
+
const radians = (degrees * Math.PI) / 180;
|
|
135
|
+
this.setLocalCoord('Angle', radians);
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Resize the shape to the given width and height (in inches).
|
|
140
|
+
* Updates LocPinX/LocPinY to keep the centre-pin at width/2, height/2.
|
|
141
|
+
*/
|
|
142
|
+
async resize(width, height) {
|
|
143
|
+
if (width <= 0 || height <= 0)
|
|
144
|
+
throw new Error('Shape dimensions must be positive');
|
|
145
|
+
await this.modifier.resizeShape(this.pageId, this.id, width, height);
|
|
146
|
+
this.setLocalCoord('Width', width);
|
|
147
|
+
this.setLocalCoord('Height', height);
|
|
148
|
+
this.setLocalCoord('LocPinX', width / 2);
|
|
149
|
+
this.setLocalCoord('LocPinY', height / 2);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Flip the shape horizontally. Pass `false` to un-flip.
|
|
154
|
+
*/
|
|
155
|
+
async flipX(enabled = true) {
|
|
156
|
+
this.modifier.setShapeFlip(this.pageId, this.id, 'x', enabled);
|
|
157
|
+
this.setLocalRawCell('FlipX', enabled ? '1' : '0');
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Flip the shape vertically. Pass `false` to un-flip.
|
|
162
|
+
*/
|
|
163
|
+
async flipY(enabled = true) {
|
|
164
|
+
this.modifier.setShapeFlip(this.pageId, this.id, 'y', enabled);
|
|
165
|
+
this.setLocalRawCell('FlipY', enabled ? '1' : '0');
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
99
168
|
async addMember(memberShape) {
|
|
100
169
|
await this.modifier.addRelationship(this.pageId, this.id, memberShape.id, 'Container');
|
|
101
170
|
return this;
|
|
@@ -165,5 +234,11 @@ class Shape {
|
|
|
165
234
|
else
|
|
166
235
|
this.internalShape.Cells[name] = { V: v, N: name };
|
|
167
236
|
}
|
|
237
|
+
setLocalRawCell(name, value) {
|
|
238
|
+
if (this.internalShape.Cells[name])
|
|
239
|
+
this.internalShape.Cells[name].V = value;
|
|
240
|
+
else
|
|
241
|
+
this.internalShape.Cells[name] = { V: value, N: name };
|
|
242
|
+
}
|
|
168
243
|
}
|
|
169
244
|
exports.Shape = Shape;
|
package/dist/ShapeModifier.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { VisioPackage } from './VisioPackage';
|
|
2
|
-
import {
|
|
2
|
+
import { HorzAlign, VertAlign } from './utils/StyleHelpers';
|
|
3
|
+
import { NewShapeProps, ConnectorStyle } from './types/VisioTypes';
|
|
4
|
+
import type { ShapeData, ShapeHyperlink } from './Shape';
|
|
3
5
|
export declare class ShapeModifier {
|
|
4
6
|
private pkg;
|
|
5
7
|
addContainer(pageId: string, props: NewShapeProps): Promise<string>;
|
|
@@ -29,11 +31,30 @@ export declare class ShapeModifier {
|
|
|
29
31
|
private saveParsed;
|
|
30
32
|
private performSave;
|
|
31
33
|
flush(): void;
|
|
32
|
-
addConnector(pageId: string, fromShapeId: string, toShapeId: string, beginArrow?: string, endArrow?: string): Promise<string>;
|
|
34
|
+
addConnector(pageId: string, fromShapeId: string, toShapeId: string, beginArrow?: string, endArrow?: string, style?: ConnectorStyle): Promise<string>;
|
|
33
35
|
addShape(pageId: string, props: NewShapeProps, parentId?: string): Promise<string>;
|
|
36
|
+
deleteShape(pageId: string, shapeId: string): Promise<void>;
|
|
37
|
+
private removeShapeFromTree;
|
|
34
38
|
updateShapeText(pageId: string, shapeId: string, newText: string): Promise<void>;
|
|
35
39
|
updateShapeStyle(pageId: string, shapeId: string, style: ShapeStyle): Promise<void>;
|
|
36
40
|
updateShapeDimensions(pageId: string, shapeId: string, w: number, h: number): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Set the rotation angle of a shape. Degrees are converted to radians
|
|
43
|
+
* for storage in the Angle cell (Visio's native unit).
|
|
44
|
+
*/
|
|
45
|
+
rotateShape(pageId: string, shapeId: string, degrees: number): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Set the flip state for a shape along the X or Y axis.
|
|
48
|
+
* FlipX mirrors left-to-right; FlipY mirrors top-to-bottom.
|
|
49
|
+
*/
|
|
50
|
+
setShapeFlip(pageId: string, shapeId: string, axis: 'x' | 'y', enabled: boolean): void;
|
|
51
|
+
/**
|
|
52
|
+
* Resize a shape, keeping it centred on its current PinX/PinY.
|
|
53
|
+
* Updates Width, Height, LocPinX, LocPinY, and the cached @_V on any
|
|
54
|
+
* Geometry cells whose @_F formula references Width or Height, so that
|
|
55
|
+
* non-Visio renderers see consistent values.
|
|
56
|
+
*/
|
|
57
|
+
resizeShape(pageId: string, shapeId: string, width: number, height: number): Promise<void>;
|
|
37
58
|
updateShapePosition(pageId: string, shapeId: string, x: number, y: number): Promise<void>;
|
|
38
59
|
addPropertyDefinition(pageId: string, shapeId: string, name: string, type: number, options?: {
|
|
39
60
|
label?: string;
|
|
@@ -67,9 +88,45 @@ export declare class ShapeModifier {
|
|
|
67
88
|
}>;
|
|
68
89
|
assignLayer(pageId: string, shapeId: string, layerIndex: number): Promise<void>;
|
|
69
90
|
updateLayerProperty(pageId: string, layerIndex: number, propName: string, value: string): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Read back all custom property (shape data) entries for a shape.
|
|
93
|
+
* Returns a map of property key → ShapeData, with values coerced to
|
|
94
|
+
* the declared type (Number, Boolean, Date, or String).
|
|
95
|
+
*/
|
|
96
|
+
getShapeProperties(pageId: string, shapeId: string): Record<string, ShapeData>;
|
|
97
|
+
/**
|
|
98
|
+
* Set the page canvas size. Writes PageWidth / PageHeight into the PageSheet
|
|
99
|
+
* and sets DrawingSizeType=0 (Custom) so Visio does not override the values.
|
|
100
|
+
*/
|
|
101
|
+
setPageSize(pageId: string, width: number, height: number): void;
|
|
102
|
+
/**
|
|
103
|
+
* Read the current page canvas dimensions.
|
|
104
|
+
* Returns 8.5 × 11 (US Letter) if no PageSheet cells are present.
|
|
105
|
+
*/
|
|
106
|
+
getPageDimensions(pageId: string): {
|
|
107
|
+
width: number;
|
|
108
|
+
height: number;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Read back all hyperlinks attached to a shape.
|
|
112
|
+
*/
|
|
113
|
+
getShapeHyperlinks(pageId: string, shapeId: string): ShapeHyperlink[];
|
|
114
|
+
/**
|
|
115
|
+
* Read back the layer indices a shape is assigned to.
|
|
116
|
+
* Returns an empty array if the shape has no layer assignment.
|
|
117
|
+
*/
|
|
118
|
+
getShapeLayerIndices(pageId: string, shapeId: string): number[];
|
|
70
119
|
}
|
|
71
120
|
export interface ShapeStyle {
|
|
72
121
|
fillColor?: string;
|
|
73
122
|
fontColor?: string;
|
|
74
123
|
bold?: boolean;
|
|
124
|
+
/** Font size in points (e.g. 14 for 14pt). */
|
|
125
|
+
fontSize?: number;
|
|
126
|
+
/** Font family name (e.g. "Arial"). */
|
|
127
|
+
fontFamily?: string;
|
|
128
|
+
/** Horizontal text alignment. */
|
|
129
|
+
horzAlign?: HorzAlign;
|
|
130
|
+
/** Vertical text alignment. */
|
|
131
|
+
verticalAlign?: VertAlign;
|
|
75
132
|
}
|