@iflow-mcp/sujimoshi_drawio-mcp 0.0.0-auto
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/LICENSE +201 -0
- package/README.md +399 -0
- package/dist/Graph.d.ts +203 -0
- package/dist/Graph.d.ts.map +1 -0
- package/dist/Graph.js +314 -0
- package/dist/Graph.js.map +1 -0
- package/dist/GraphFileManager.d.ts +34 -0
- package/dist/GraphFileManager.d.ts.map +1 -0
- package/dist/GraphFileManager.js +97 -0
- package/dist/GraphFileManager.js.map +1 -0
- package/dist/Logger.d.ts +9 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +20 -0
- package/dist/Logger.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/AddNodeTool.d.ts +97 -0
- package/dist/mcp/AddNodeTool.d.ts.map +1 -0
- package/dist/mcp/AddNodeTool.js +103 -0
- package/dist/mcp/AddNodeTool.js.map +1 -0
- package/dist/mcp/EditNodeTool.d.ts +74 -0
- package/dist/mcp/EditNodeTool.d.ts.map +1 -0
- package/dist/mcp/EditNodeTool.js +66 -0
- package/dist/mcp/EditNodeTool.js.map +1 -0
- package/dist/mcp/GetDiagramInfoTool.d.ts +29 -0
- package/dist/mcp/GetDiagramInfoTool.d.ts.map +1 -0
- package/dist/mcp/GetDiagramInfoTool.js +38 -0
- package/dist/mcp/GetDiagramInfoTool.js.map +1 -0
- package/dist/mcp/LinkNodesTools.d.ts +64 -0
- package/dist/mcp/LinkNodesTools.d.ts.map +1 -0
- package/dist/mcp/LinkNodesTools.js +63 -0
- package/dist/mcp/LinkNodesTools.js.map +1 -0
- package/dist/mcp/McpServer.d.ts +24 -0
- package/dist/mcp/McpServer.d.ts.map +1 -0
- package/dist/mcp/McpServer.js +41 -0
- package/dist/mcp/McpServer.js.map +1 -0
- package/dist/mcp/NewDiagramTool.d.ts +29 -0
- package/dist/mcp/NewDiagramTool.d.ts.map +1 -0
- package/dist/mcp/NewDiagramTool.js +39 -0
- package/dist/mcp/NewDiagramTool.js.map +1 -0
- package/dist/mcp/RemoveNodesTool.d.ts +38 -0
- package/dist/mcp/RemoveNodesTool.d.ts.map +1 -0
- package/dist/mcp/RemoveNodesTool.js +48 -0
- package/dist/mcp/RemoveNodesTool.js.map +1 -0
- package/dist/mxgraph/index.d.ts +3 -0
- package/dist/mxgraph/index.d.ts.map +1 -0
- package/dist/mxgraph/index.js +10 -0
- package/dist/mxgraph/index.js.map +1 -0
- package/dist/mxgraph/jsdom.d.ts +2 -0
- package/dist/mxgraph/jsdom.d.ts.map +1 -0
- package/dist/mxgraph/jsdom.js +14 -0
- package/dist/mxgraph/jsdom.js.map +1 -0
- package/package.json +55 -0
package/dist/Graph.d.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { mxGraph } from './mxgraph/index.js';
|
|
2
|
+
export type LinkNodesParams = {
|
|
3
|
+
from: string;
|
|
4
|
+
to: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
style?: Record<string, any>;
|
|
7
|
+
undirected?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare class Graph {
|
|
10
|
+
static Kinds: {
|
|
11
|
+
Rectangle: {
|
|
12
|
+
style: {
|
|
13
|
+
rounded: number;
|
|
14
|
+
whiteSpace: string;
|
|
15
|
+
html: number;
|
|
16
|
+
};
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
};
|
|
20
|
+
Ellipse: {
|
|
21
|
+
style: {
|
|
22
|
+
ellipse: string;
|
|
23
|
+
whiteSpace: string;
|
|
24
|
+
html: number;
|
|
25
|
+
};
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
};
|
|
29
|
+
Cylinder: {
|
|
30
|
+
style: string;
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
Cloud: {
|
|
35
|
+
style: string;
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
};
|
|
39
|
+
Square: {
|
|
40
|
+
style: string;
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
};
|
|
44
|
+
Circle: {
|
|
45
|
+
style: string;
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
};
|
|
49
|
+
Step: {
|
|
50
|
+
style: string;
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
};
|
|
54
|
+
Actor: {
|
|
55
|
+
style: string;
|
|
56
|
+
width: number;
|
|
57
|
+
height: number;
|
|
58
|
+
};
|
|
59
|
+
Text: {
|
|
60
|
+
style: string;
|
|
61
|
+
width: number;
|
|
62
|
+
height: number;
|
|
63
|
+
};
|
|
64
|
+
RoundedRectangle: {
|
|
65
|
+
style: string;
|
|
66
|
+
width: number;
|
|
67
|
+
height: number;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
static normalizeKind(kind: string): string;
|
|
71
|
+
graph: typeof mxGraph;
|
|
72
|
+
container: HTMLDivElement;
|
|
73
|
+
constructor();
|
|
74
|
+
get root(): any;
|
|
75
|
+
get model(): any;
|
|
76
|
+
toStyleString(data: any): string;
|
|
77
|
+
/**
|
|
78
|
+
* Parses a style definition into a key-value object.
|
|
79
|
+
*
|
|
80
|
+
* Handles both string and object style formats:
|
|
81
|
+
* - String format: "key1=value1;key2=value2;" (semicolon-separated key=value pairs)
|
|
82
|
+
* - Object format: { key1: "value1", key2: "value2" } (plain object)
|
|
83
|
+
*
|
|
84
|
+
* For string styles, empty values (e.g., "key=") are converted to empty strings.
|
|
85
|
+
* For object styles, the input is shallow copied to avoid mutation.
|
|
86
|
+
*
|
|
87
|
+
* @param style - Style definition as either a semicolon-separated string or object
|
|
88
|
+
* @returns Object with style properties as key-value pairs
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* parseStyle("rounded=1;whiteSpace=wrap;html=1")
|
|
92
|
+
* // Returns: { rounded: "1", whiteSpace: "wrap", html: "1" }
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* parseStyle({ rounded: 1, whiteSpace: "wrap" })
|
|
96
|
+
* // Returns: { rounded: 1, whiteSpace: "wrap" }
|
|
97
|
+
*/
|
|
98
|
+
private parseStyle;
|
|
99
|
+
/**
|
|
100
|
+
* Converts a style object into a semicolon-separated style string.
|
|
101
|
+
*
|
|
102
|
+
* This function is the inverse of parseStyle(), converting a key-value object
|
|
103
|
+
* back into the string format used by mxGraph. Properties with undefined values
|
|
104
|
+
* are skipped, while properties with falsy values (empty string, 0, false) are
|
|
105
|
+
* included with just the key name (no equals sign).
|
|
106
|
+
*
|
|
107
|
+
* @param style - Object with style properties as key-value pairs
|
|
108
|
+
* @returns Semicolon-separated style string in format "key1=value1;key2;key3=value3;"
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* stringifyStyle({ rounded: "1", whiteSpace: "wrap", html: "1" })
|
|
112
|
+
* // Returns: "rounded=1;whiteSpace=wrap;html=1;"
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* stringifyStyle({ rounded: "", whiteSpace: "wrap" })
|
|
116
|
+
* // Returns: "rounded;whiteSpace=wrap;"
|
|
117
|
+
*/
|
|
118
|
+
private stringifyStyle;
|
|
119
|
+
/**
|
|
120
|
+
* Adjusts the style string for a specific node kind, applying kind-specific modifications.
|
|
121
|
+
*
|
|
122
|
+
* For RoundedRectangle nodes, this function modifies the corner radius by setting:
|
|
123
|
+
* - absoluteArcSize to '1' to enable absolute arc sizing
|
|
124
|
+
* - arcSize to the calculated value (corner_radius * 2, default to 24)
|
|
125
|
+
*
|
|
126
|
+
* @param style - The base style string to modify
|
|
127
|
+
* @param kind - The node kind (e.g., 'RoundedRectangle', 'Rectangle', etc.)
|
|
128
|
+
* @param corner_radius - The desired corner radius in pixels (only applies to RoundedRectangle)
|
|
129
|
+
* @returns The modified style string with kind-specific adjustments applied
|
|
130
|
+
*/
|
|
131
|
+
private adjustStyleByKind;
|
|
132
|
+
addNode({ id, title, parent, kind, x, y, corner_radius, ...rest }: {
|
|
133
|
+
[x: string]: any;
|
|
134
|
+
id: any;
|
|
135
|
+
title: any;
|
|
136
|
+
parent?: string;
|
|
137
|
+
kind?: string;
|
|
138
|
+
x?: number;
|
|
139
|
+
y?: number;
|
|
140
|
+
corner_radius: any;
|
|
141
|
+
}): any;
|
|
142
|
+
editNode({ id, title, kind, x, y, width, height, corner_radius }: {
|
|
143
|
+
id: any;
|
|
144
|
+
title: any;
|
|
145
|
+
kind: any;
|
|
146
|
+
x: any;
|
|
147
|
+
y: any;
|
|
148
|
+
width: any;
|
|
149
|
+
height: any;
|
|
150
|
+
corner_radius: any;
|
|
151
|
+
}): this;
|
|
152
|
+
linkNodes({ from, to, title, style, undirected }: LinkNodesParams): any;
|
|
153
|
+
removeNodes(ids: string[]): this;
|
|
154
|
+
/**
|
|
155
|
+
* Executes a given layout algorithm on the graph's root element.
|
|
156
|
+
*
|
|
157
|
+
* @param layout - An object with an `execute` method, typically an mxGraph layout instance.
|
|
158
|
+
* @param args - Additional arguments to pass to the layout's `execute` method.
|
|
159
|
+
* @returns The current Graph instance for method chaining.
|
|
160
|
+
*
|
|
161
|
+
* @remarks
|
|
162
|
+
* This method is used internally to apply various mxGraph layout algorithms
|
|
163
|
+
* (e.g., hierarchical, circle, organic) to the graph. The layout is executed
|
|
164
|
+
* on the root element of the graph, and any additional arguments are forwarded
|
|
165
|
+
* to the layout's `execute` method.
|
|
166
|
+
*/
|
|
167
|
+
private runLayout;
|
|
168
|
+
/**
|
|
169
|
+
* Applies a layout algorithm to the graph.
|
|
170
|
+
*
|
|
171
|
+
* @param params - An object containing the layout algorithm and optional options.
|
|
172
|
+
* @param params.algorithm - The name of the layout algorithm to apply. Supported values are:
|
|
173
|
+
* - 'hierarchical'
|
|
174
|
+
* - 'circle'
|
|
175
|
+
* - 'organic'
|
|
176
|
+
* - 'compact-tree'
|
|
177
|
+
* - 'radial-tree'
|
|
178
|
+
* - 'partition'
|
|
179
|
+
* - 'stack'
|
|
180
|
+
* @param params.options - Optional parameters for the layout algorithm.
|
|
181
|
+
* - For 'hierarchical', you may specify `direction` as either 'top-down' or 'left-right'.
|
|
182
|
+
*
|
|
183
|
+
* @throws {Error} If an unsupported algorithm is provided, or if an invalid direction is specified for hierarchical layout.
|
|
184
|
+
*
|
|
185
|
+
* @returns {Graph} The current Graph instance for method chaining.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* graph.applyLayout({ algorithm: 'hierarchical', options: { direction: 'left-right' } });
|
|
189
|
+
* graph.applyLayout({ algorithm: 'circle' });
|
|
190
|
+
*/
|
|
191
|
+
applyLayout({ algorithm, options }: {
|
|
192
|
+
algorithm: string;
|
|
193
|
+
options?: any;
|
|
194
|
+
}): this;
|
|
195
|
+
toXML(): any;
|
|
196
|
+
/**
|
|
197
|
+
* Static method to create a Graph instance from XML
|
|
198
|
+
* @param {string} xmlString - XML string in mxGraph format
|
|
199
|
+
* @returns {Graph} - New Graph instance loaded from XML
|
|
200
|
+
*/
|
|
201
|
+
static fromXML(xmlString: any): Graph;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=Graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graph.d.ts","sourceRoot":"","sources":["../src/Graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmL,MAAM,oBAAoB,CAAC;AAwB9N,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAA;AAED,qBAAa,KAAK;IAChB,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAWX;IAED,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM;IAKjC,KAAK,EAAE,OAAO,OAAO,CAAC;IACtB,SAAS,EAAE,cAAc,CAAC;;IAO1B,IAAI,IAAI,QAEP;IAED,IAAI,KAAK,QAER;IAED,aAAa,CAAC,IAAI,KAAA;IAOlB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,UAAU;IAWlB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,cAAc;IAQtB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAe,EAAE,IAAkB,EAAE,CAAM,EAAE,CAAM,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE;;;;;;;;;KAAA;IAUlG,QAAQ,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE;;;;;;;;;KAAA;IA4BhE,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAU,EAAE,UAAU,EAAE,EAAE,eAAe;IA2BtE,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE;IAMzB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;IAMjB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CAAC,EAAE,SAAS,EAAE,OAAY,EAAE,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,GAAG,CAAA;KAAE;IA6C7E,KAAK;IAML;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,SAAS,KAAA;CAazB"}
|
package/dist/Graph.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { mxGraph, mxCodec, mxUtils, mxHierarchicalLayout, mxConstants, mxCircleLayout, mxGeometry, mxFastOrganicLayout, mxCompactTreeLayout, mxRadialTreeLayout, mxPartitionLayout, mxStackLayout } from './mxgraph/index.js';
|
|
2
|
+
const LAYOUT_HIERARCHICAL = 'hierarchical';
|
|
3
|
+
const LAYOUT_CIRCLE = 'circle';
|
|
4
|
+
const LAYOUT_ORGANIC = 'organic';
|
|
5
|
+
const LAYOUT_COMPACT_TREE = 'compact-tree';
|
|
6
|
+
const LAYOUT_RADIAL_TREE = 'radial-tree';
|
|
7
|
+
const LAYOUT_PARTITION = 'partition';
|
|
8
|
+
const LAYOUT_STACK = 'stack';
|
|
9
|
+
const DIRECTION_TOP_DOWN = 'top-down';
|
|
10
|
+
const DIRECTION_LEFT_RIGHT = 'left-right';
|
|
11
|
+
const DIR_TO_MX_DIRECTION = {
|
|
12
|
+
[DIRECTION_TOP_DOWN]: mxConstants.DIRECTION_NORTH,
|
|
13
|
+
[DIRECTION_LEFT_RIGHT]: mxConstants.DIRECTION_WEST
|
|
14
|
+
};
|
|
15
|
+
const DEFAULT_CORNER_RADIUS = 12;
|
|
16
|
+
const KIND_ROUNDED_RECTANGLE = 'RoundedRectangle';
|
|
17
|
+
const PROP_ARC_SIZE = 'arcSize';
|
|
18
|
+
const PROP_ABSOLUTE_ARC_SIZE = 'absoluteArcSize';
|
|
19
|
+
export class Graph {
|
|
20
|
+
static normalizeKind(kind) {
|
|
21
|
+
if (kind === 'Elipse')
|
|
22
|
+
return 'Ellipse';
|
|
23
|
+
return kind;
|
|
24
|
+
}
|
|
25
|
+
constructor() {
|
|
26
|
+
this.container = document.createElement('div');
|
|
27
|
+
this.graph = new mxGraph(this.container);
|
|
28
|
+
}
|
|
29
|
+
get root() {
|
|
30
|
+
return this.graph.getDefaultParent();
|
|
31
|
+
}
|
|
32
|
+
get model() {
|
|
33
|
+
return this.graph.getModel();
|
|
34
|
+
}
|
|
35
|
+
toStyleString(data) {
|
|
36
|
+
if (typeof data === 'string')
|
|
37
|
+
return data;
|
|
38
|
+
return Object.entries(data).reduce((tmp, [key, value]) => {
|
|
39
|
+
return value === undefined ? tmp : tmp += key + (value ? `=${value}` : '') + ';';
|
|
40
|
+
}, '');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parses a style definition into a key-value object.
|
|
44
|
+
*
|
|
45
|
+
* Handles both string and object style formats:
|
|
46
|
+
* - String format: "key1=value1;key2=value2;" (semicolon-separated key=value pairs)
|
|
47
|
+
* - Object format: { key1: "value1", key2: "value2" } (plain object)
|
|
48
|
+
*
|
|
49
|
+
* For string styles, empty values (e.g., "key=") are converted to empty strings.
|
|
50
|
+
* For object styles, the input is shallow copied to avoid mutation.
|
|
51
|
+
*
|
|
52
|
+
* @param style - Style definition as either a semicolon-separated string or object
|
|
53
|
+
* @returns Object with style properties as key-value pairs
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* parseStyle("rounded=1;whiteSpace=wrap;html=1")
|
|
57
|
+
* // Returns: { rounded: "1", whiteSpace: "wrap", html: "1" }
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* parseStyle({ rounded: 1, whiteSpace: "wrap" })
|
|
61
|
+
* // Returns: { rounded: 1, whiteSpace: "wrap" }
|
|
62
|
+
*/
|
|
63
|
+
parseStyle(style) {
|
|
64
|
+
if (typeof style === 'string') {
|
|
65
|
+
return style.split(';').filter(Boolean).reduce((acc, kv) => {
|
|
66
|
+
const [k, v] = kv.split('=');
|
|
67
|
+
acc[k] = v === undefined ? '' : v;
|
|
68
|
+
return acc;
|
|
69
|
+
}, {});
|
|
70
|
+
}
|
|
71
|
+
return { ...style };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Converts a style object into a semicolon-separated style string.
|
|
75
|
+
*
|
|
76
|
+
* This function is the inverse of parseStyle(), converting a key-value object
|
|
77
|
+
* back into the string format used by mxGraph. Properties with undefined values
|
|
78
|
+
* are skipped, while properties with falsy values (empty string, 0, false) are
|
|
79
|
+
* included with just the key name (no equals sign).
|
|
80
|
+
*
|
|
81
|
+
* @param style - Object with style properties as key-value pairs
|
|
82
|
+
* @returns Semicolon-separated style string in format "key1=value1;key2;key3=value3;"
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* stringifyStyle({ rounded: "1", whiteSpace: "wrap", html: "1" })
|
|
86
|
+
* // Returns: "rounded=1;whiteSpace=wrap;html=1;"
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* stringifyStyle({ rounded: "", whiteSpace: "wrap" })
|
|
90
|
+
* // Returns: "rounded;whiteSpace=wrap;"
|
|
91
|
+
*/
|
|
92
|
+
stringifyStyle(style) {
|
|
93
|
+
return Object.entries(style).reduce((tmp, [key, value]) => {
|
|
94
|
+
return value === undefined ? tmp : tmp += key + (value ? `=${value}` : '') + ';';
|
|
95
|
+
}, '');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Adjusts the style string for a specific node kind, applying kind-specific modifications.
|
|
99
|
+
*
|
|
100
|
+
* For RoundedRectangle nodes, this function modifies the corner radius by setting:
|
|
101
|
+
* - absoluteArcSize to '1' to enable absolute arc sizing
|
|
102
|
+
* - arcSize to the calculated value (corner_radius * 2, default to 24)
|
|
103
|
+
*
|
|
104
|
+
* @param style - The base style string to modify
|
|
105
|
+
* @param kind - The node kind (e.g., 'RoundedRectangle', 'Rectangle', etc.)
|
|
106
|
+
* @param corner_radius - The desired corner radius in pixels (only applies to RoundedRectangle)
|
|
107
|
+
* @returns The modified style string with kind-specific adjustments applied
|
|
108
|
+
*/
|
|
109
|
+
adjustStyleByKind(style, kind, corner_radius) {
|
|
110
|
+
if (kind === KIND_ROUNDED_RECTANGLE) {
|
|
111
|
+
const styleObj = this.parseStyle(style);
|
|
112
|
+
if (corner_radius !== undefined) {
|
|
113
|
+
const cr = parseInt(String(corner_radius), 10);
|
|
114
|
+
styleObj[PROP_ABSOLUTE_ARC_SIZE] = '1';
|
|
115
|
+
const arcSize = !isNaN(cr) && cr >= 1 ? cr * 2 : DEFAULT_CORNER_RADIUS * 2;
|
|
116
|
+
styleObj[PROP_ARC_SIZE] = String(arcSize);
|
|
117
|
+
}
|
|
118
|
+
// console.error(`adjusted style: ${this.stringifyStyle(styleObj)}`);
|
|
119
|
+
return this.stringifyStyle(styleObj);
|
|
120
|
+
}
|
|
121
|
+
return style;
|
|
122
|
+
}
|
|
123
|
+
addNode({ id, title, parent = 'root', kind = 'Rectangle', x = 10, y = 10, corner_radius, ...rest }) {
|
|
124
|
+
const normalizedKind = Graph.normalizeKind(kind);
|
|
125
|
+
const { style, width, height } = { ...Graph.Kinds[normalizedKind], ...rest };
|
|
126
|
+
const to = parent === 'root' ? this.root : this.model.getCell(parent);
|
|
127
|
+
const node = this.graph.insertVertex(to, id, title, Number(x), Number(y), width, height);
|
|
128
|
+
node.setStyle(this.adjustStyleByKind(style, normalizedKind, corner_radius));
|
|
129
|
+
return node;
|
|
130
|
+
}
|
|
131
|
+
editNode({ id, title, kind, x, y, width, height, corner_radius }) {
|
|
132
|
+
const node = this.model.getCell(id);
|
|
133
|
+
if (!node)
|
|
134
|
+
throw new Error(`Node not found`);
|
|
135
|
+
const normalizedKind = Graph.normalizeKind(kind);
|
|
136
|
+
if (title)
|
|
137
|
+
node.setValue(title);
|
|
138
|
+
if (kind)
|
|
139
|
+
node.setStyle(Graph.Kinds[normalizedKind].style);
|
|
140
|
+
// if it's rounded, apply the corner radius
|
|
141
|
+
const isRounded = normalizedKind === KIND_ROUNDED_RECTANGLE;
|
|
142
|
+
if (isRounded && corner_radius !== undefined) {
|
|
143
|
+
const currentStyleStr = node.getStyle && node.getStyle() ? String(node.getStyle()) : '';
|
|
144
|
+
node.setStyle(this.adjustStyleByKind(currentStyleStr, normalizedKind, corner_radius));
|
|
145
|
+
}
|
|
146
|
+
// if the geometry is changed, update the geometry
|
|
147
|
+
if (x !== undefined || y !== undefined || width !== undefined || height !== undefined) {
|
|
148
|
+
const geometry = node.getGeometry();
|
|
149
|
+
node.setGeometry(new mxGeometry(x ?? geometry.x, y ?? geometry.y, width ?? geometry.width, height ?? geometry.height));
|
|
150
|
+
}
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
linkNodes({ from, to, title, style = {}, undirected }) {
|
|
154
|
+
const [fromNode, toNode] = [this.model.getCell(from), this.model.getCell(to)];
|
|
155
|
+
// Compute candidate IDs
|
|
156
|
+
const idDirect = `${from}-2-${to}`;
|
|
157
|
+
const idReverse = `${to}-2-${from}`;
|
|
158
|
+
const [a, b] = [from, to].sort();
|
|
159
|
+
const idCanonical = `${a}-2-${b}`;
|
|
160
|
+
// Build effective style
|
|
161
|
+
const effective = computeEffectiveLineStyle(style, undirected);
|
|
162
|
+
// Try to find an existing edge to update (do not rename IDs)
|
|
163
|
+
const existing = this.model.getCell(idDirect) || this.model.getCell(idReverse) || this.model.getCell(idCanonical);
|
|
164
|
+
let link = existing;
|
|
165
|
+
if (link) {
|
|
166
|
+
if (title !== undefined)
|
|
167
|
+
link.setValue(title);
|
|
168
|
+
}
|
|
169
|
+
else { // Insert new edge; use canonical id for undirected, else direct id
|
|
170
|
+
const idToUse = undirected ? idCanonical : idDirect;
|
|
171
|
+
link = this.graph.insertEdge(this.root, idToUse, title ? title : null, fromNode, toNode);
|
|
172
|
+
}
|
|
173
|
+
link.setStyle(this.toStyleString(effective));
|
|
174
|
+
return link.getId();
|
|
175
|
+
}
|
|
176
|
+
removeNodes(ids) {
|
|
177
|
+
const cells = ids.map(id => this.model.getCell(id));
|
|
178
|
+
this.graph.removeCells(cells);
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Executes a given layout algorithm on the graph's root element.
|
|
183
|
+
*
|
|
184
|
+
* @param layout - An object with an `execute` method, typically an mxGraph layout instance.
|
|
185
|
+
* @param args - Additional arguments to pass to the layout's `execute` method.
|
|
186
|
+
* @returns The current Graph instance for method chaining.
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
* This method is used internally to apply various mxGraph layout algorithms
|
|
190
|
+
* (e.g., hierarchical, circle, organic) to the graph. The layout is executed
|
|
191
|
+
* on the root element of the graph, and any additional arguments are forwarded
|
|
192
|
+
* to the layout's `execute` method.
|
|
193
|
+
*/
|
|
194
|
+
runLayout(layout, ...args) {
|
|
195
|
+
layout.execute(this.root, ...args);
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Applies a layout algorithm to the graph.
|
|
200
|
+
*
|
|
201
|
+
* @param params - An object containing the layout algorithm and optional options.
|
|
202
|
+
* @param params.algorithm - The name of the layout algorithm to apply. Supported values are:
|
|
203
|
+
* - 'hierarchical'
|
|
204
|
+
* - 'circle'
|
|
205
|
+
* - 'organic'
|
|
206
|
+
* - 'compact-tree'
|
|
207
|
+
* - 'radial-tree'
|
|
208
|
+
* - 'partition'
|
|
209
|
+
* - 'stack'
|
|
210
|
+
* @param params.options - Optional parameters for the layout algorithm.
|
|
211
|
+
* - For 'hierarchical', you may specify `direction` as either 'top-down' or 'left-right'.
|
|
212
|
+
*
|
|
213
|
+
* @throws {Error} If an unsupported algorithm is provided, or if an invalid direction is specified for hierarchical layout.
|
|
214
|
+
*
|
|
215
|
+
* @returns {Graph} The current Graph instance for method chaining.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* graph.applyLayout({ algorithm: 'hierarchical', options: { direction: 'left-right' } });
|
|
219
|
+
* graph.applyLayout({ algorithm: 'circle' });
|
|
220
|
+
*/
|
|
221
|
+
applyLayout({ algorithm, options = {} }) {
|
|
222
|
+
switch (algorithm) {
|
|
223
|
+
case LAYOUT_HIERARCHICAL: {
|
|
224
|
+
if (options.direction !== undefined &&
|
|
225
|
+
options.direction !== DIRECTION_TOP_DOWN && options.direction !== DIRECTION_LEFT_RIGHT)
|
|
226
|
+
throw new Error(`Invalid hierarchical direction: ${options.direction}. Allowed: ${DIRECTION_TOP_DOWN}, ${DIRECTION_LEFT_RIGHT}`);
|
|
227
|
+
this.runLayout(new mxHierarchicalLayout(this.graph, DIR_TO_MX_DIRECTION[options.direction]), Object.values(this.model.cells)[1]);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
case LAYOUT_CIRCLE: {
|
|
231
|
+
this.runLayout(new mxCircleLayout(this.graph));
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case LAYOUT_ORGANIC: {
|
|
235
|
+
this.runLayout(new mxFastOrganicLayout(this.graph));
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
case LAYOUT_COMPACT_TREE: {
|
|
239
|
+
this.runLayout(new mxCompactTreeLayout(this.graph));
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case LAYOUT_RADIAL_TREE: {
|
|
243
|
+
this.runLayout(new mxRadialTreeLayout(this.graph));
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case LAYOUT_PARTITION: {
|
|
247
|
+
this.runLayout(new mxPartitionLayout(this.graph));
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case LAYOUT_STACK: {
|
|
251
|
+
this.runLayout(new mxStackLayout(this.graph));
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
default: {
|
|
255
|
+
const supportedAlgorithms = [LAYOUT_HIERARCHICAL, LAYOUT_CIRCLE, LAYOUT_ORGANIC,
|
|
256
|
+
LAYOUT_COMPACT_TREE, LAYOUT_RADIAL_TREE, LAYOUT_PARTITION,
|
|
257
|
+
LAYOUT_STACK,
|
|
258
|
+
];
|
|
259
|
+
throw new Error(`Unsupported layout algorithm: ${algorithm}. Supported: ${supportedAlgorithms.join(', ')}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return this;
|
|
263
|
+
}
|
|
264
|
+
toXML() {
|
|
265
|
+
const encoder = new mxCodec();
|
|
266
|
+
const result = encoder.encode(this.model);
|
|
267
|
+
return mxUtils.getPrettyXml(result);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Static method to create a Graph instance from XML
|
|
271
|
+
* @param {string} xmlString - XML string in mxGraph format
|
|
272
|
+
* @returns {Graph} - New Graph instance loaded from XML
|
|
273
|
+
*/
|
|
274
|
+
static fromXML(xmlString) {
|
|
275
|
+
const graph = new Graph();
|
|
276
|
+
// Use the global DOMParser that was set up in mxgraph.js
|
|
277
|
+
const parsedDoc = new DOMParser().parseFromString(xmlString, 'text/xml');
|
|
278
|
+
// Create a codec with the parsed document
|
|
279
|
+
const codec = new mxCodec(parsedDoc);
|
|
280
|
+
codec.decode(parsedDoc.documentElement, graph.model);
|
|
281
|
+
return graph;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
Graph.Kinds = {
|
|
285
|
+
Rectangle: { style: { rounded: 1, whiteSpace: 'wrap', html: 1 }, width: 120, height: 60 },
|
|
286
|
+
Ellipse: { style: { ellipse: '', whiteSpace: 'wrap', html: 1 }, width: 120, height: 80 },
|
|
287
|
+
Cylinder: { style: 'shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;', width: 60, height: 80 },
|
|
288
|
+
Cloud: { style: 'ellipse;shape=cloud;whiteSpace=wrap;html=1;', width: 120, height: 80 },
|
|
289
|
+
Square: { style: 'whiteSpace=wrap;html=1;aspect=fixed;rounded=1;', width: 80, height: 80 },
|
|
290
|
+
Circle: { style: 'ellipse;whiteSpace=wrap;html=1;aspect=fixed;', width: 80, height: 80 },
|
|
291
|
+
Step: { style: 'shape=step;perimeter=stepPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', width: 120, height: 80 },
|
|
292
|
+
Actor: { style: 'shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;', width: 30, height: 60 },
|
|
293
|
+
Text: { style: 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;', width: 60, height: 30 },
|
|
294
|
+
RoundedRectangle: { style: `whiteSpace=wrap;html=1;rounded=1;absoluteArcSize=1;arcSize=${DEFAULT_CORNER_RADIUS * 2}`, width: 120, height: 60 },
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Computes the effective line style for an edge in the graph, merging the provided style
|
|
298
|
+
* with default base styles. If the edge is undirected, disables arrowheads and reverses.
|
|
299
|
+
*
|
|
300
|
+
* @param {Record<string, any>} style - Optional style overrides for the edge.
|
|
301
|
+
* @param {boolean} [undirected] - If true, creates an undirected edge (no arrows).
|
|
302
|
+
* @returns {Record<string, any>} The computed style object for the edge.
|
|
303
|
+
*/
|
|
304
|
+
function computeEffectiveLineStyle(style = {}, undirected) {
|
|
305
|
+
const base = { edgeStyle: 'none', noEdgeStyle: 1, orthogonal: 1, html: 1 };
|
|
306
|
+
const effective = { ...base, ...style };
|
|
307
|
+
if (undirected) {
|
|
308
|
+
effective.reverse = undefined;
|
|
309
|
+
effective.startArrow = 'none';
|
|
310
|
+
effective.endArrow = 'none';
|
|
311
|
+
}
|
|
312
|
+
return effective;
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=Graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graph.js","sourceRoot":"","sources":["../src/Graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Graph } from './Graph.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handles diagram file operations and SVG content parsing
|
|
4
|
+
* Works directly with file paths
|
|
5
|
+
*/
|
|
6
|
+
export declare class GraphFileManager {
|
|
7
|
+
static default: GraphFileManager;
|
|
8
|
+
/**
|
|
9
|
+
* Load a graph from a .drawio.svg file
|
|
10
|
+
*/
|
|
11
|
+
loadGraphFromSvg(filePath: string): Promise<Graph>;
|
|
12
|
+
/**
|
|
13
|
+
* Save a graph to a .drawio.svg file
|
|
14
|
+
* @param {Graph} graph - Graph instance to save
|
|
15
|
+
* @param {string} filePath - Absolute or relative path to save the .drawio.svg file
|
|
16
|
+
*/
|
|
17
|
+
saveGraphToSvg(graph: Graph, filePath: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Get diagram statistics from file
|
|
20
|
+
* @param {string} filePath - Absolute or relative path to the file
|
|
21
|
+
* @returns {Object} - Object with nodeCount and edgeCount
|
|
22
|
+
*/
|
|
23
|
+
getDiagramStats(filePath: string): Promise<{
|
|
24
|
+
nodeCount: number;
|
|
25
|
+
edgeCount: number;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Extract raw XML data from SVG content attribute for direct mxGraph loading
|
|
29
|
+
* @param {string} svgContent - Raw SVG file content
|
|
30
|
+
* @returns {string|null} - Raw mxGraph XML data or null if extraction fails
|
|
31
|
+
*/
|
|
32
|
+
extractXMLFromSVG(svgContent: string): string;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=GraphFileManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GraphFileManager.d.ts","sourceRoot":"","sources":["../src/GraphFileManager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,MAAM,CAAC,OAAO,mBAA0B;IAExC;;OAEG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM;IAYvC;;;;OAIG;IACG,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM;IA0BnD;;;;OAIG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM;;;;IAYtC;;;;OAIG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM;CAgCrC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import pako from 'pako';
|
|
4
|
+
import { Graph } from './Graph.js';
|
|
5
|
+
/**
|
|
6
|
+
* Handles diagram file operations and SVG content parsing
|
|
7
|
+
* Works directly with file paths
|
|
8
|
+
*/
|
|
9
|
+
export class GraphFileManager {
|
|
10
|
+
/**
|
|
11
|
+
* Load a graph from a .drawio.svg file
|
|
12
|
+
*/
|
|
13
|
+
async loadGraphFromSvg(filePath) {
|
|
14
|
+
// Resolve relative paths relative to process.cwd()
|
|
15
|
+
const resolvedPath = path.resolve(filePath);
|
|
16
|
+
await fs.access(resolvedPath);
|
|
17
|
+
// Load from SVG content attribute and use direct XML loading
|
|
18
|
+
const svgContent = await fs.readFile(resolvedPath, 'utf8');
|
|
19
|
+
const xmlData = this.extractXMLFromSVG(svgContent);
|
|
20
|
+
return Graph.fromXML(xmlData);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Save a graph to a .drawio.svg file
|
|
24
|
+
* @param {Graph} graph - Graph instance to save
|
|
25
|
+
* @param {string} filePath - Absolute or relative path to save the .drawio.svg file
|
|
26
|
+
*/
|
|
27
|
+
async saveGraphToSvg(graph, filePath) {
|
|
28
|
+
// Resolve relative paths relative to process.cwd()
|
|
29
|
+
const resolvedPath = path.resolve(filePath);
|
|
30
|
+
// Ensure directory exists
|
|
31
|
+
const dir = path.dirname(resolvedPath);
|
|
32
|
+
await fs.mkdir(dir, { recursive: true });
|
|
33
|
+
// Save SVG for VSCode draw.io extension (no metadata file needed!)
|
|
34
|
+
const tmp = pako.deflateRaw(encodeURIComponent(graph.toXML()));
|
|
35
|
+
var bytes = new Uint8Array(tmp);
|
|
36
|
+
var binary = '';
|
|
37
|
+
for (var i = 0; i < bytes.byteLength; i++) {
|
|
38
|
+
binary += String.fromCharCode(bytes[i]);
|
|
39
|
+
}
|
|
40
|
+
const compressed = btoa(binary);
|
|
41
|
+
const content = `<mxfile><diagram id="d" name="P">${compressed}</diagram></mxfile>`;
|
|
42
|
+
graph.container.children[0].setAttribute('content', 'replaceme');
|
|
43
|
+
const svgContent = graph.container.innerHTML.replace('replaceme', content);
|
|
44
|
+
await fs.writeFile(resolvedPath, svgContent, 'utf8');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get diagram statistics from file
|
|
48
|
+
* @param {string} filePath - Absolute or relative path to the file
|
|
49
|
+
* @returns {Object} - Object with nodeCount and edgeCount
|
|
50
|
+
*/
|
|
51
|
+
async getDiagramStats(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
const graph = await this.loadGraphFromSvg(filePath);
|
|
54
|
+
const cells = graph.model.cells;
|
|
55
|
+
const nodeCount = Object.values(cells).filter((cell) => cell && cell.vertex).length;
|
|
56
|
+
const edgeCount = Object.values(cells).filter((cell) => cell && cell.edge).length;
|
|
57
|
+
return { nodeCount, edgeCount };
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { nodeCount: 0, edgeCount: 0 };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract raw XML data from SVG content attribute for direct mxGraph loading
|
|
65
|
+
* @param {string} svgContent - Raw SVG file content
|
|
66
|
+
* @returns {string|null} - Raw mxGraph XML data or null if extraction fails
|
|
67
|
+
*/
|
|
68
|
+
extractXMLFromSVG(svgContent) {
|
|
69
|
+
// Extract the content attribute from SVG
|
|
70
|
+
const contentMatch = svgContent.match(/content="([^"]+)"/);
|
|
71
|
+
if (!contentMatch) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// Decode the content attribute
|
|
75
|
+
const encodedContent = contentMatch[1];
|
|
76
|
+
// Step 1: HTML decode
|
|
77
|
+
const htmlDecoded = encodedContent
|
|
78
|
+
.replace(/</g, '<')
|
|
79
|
+
.replace(/>/g, '>')
|
|
80
|
+
.replace(/"/g, '"')
|
|
81
|
+
.replace(/&/g, '&');
|
|
82
|
+
// Step 2: Extract base64 data from mxfile structure
|
|
83
|
+
const mxfileMatch = htmlDecoded.match(/<diagram[^>]*>([^<]+)<\/diagram>/);
|
|
84
|
+
if (!mxfileMatch) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
// Step 3: Base64 decode and decompress
|
|
88
|
+
const base64Data = mxfileMatch[1];
|
|
89
|
+
const compressedData = Buffer.from(base64Data, 'base64');
|
|
90
|
+
const decompressed = pako.inflateRaw(compressedData, { to: 'string' });
|
|
91
|
+
// Step 4: URI decode to get XML - return directly for mxGraph
|
|
92
|
+
const xmlData = decodeURIComponent(decompressed);
|
|
93
|
+
return xmlData;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
GraphFileManager.default = new GraphFileManager();
|
|
97
|
+
//# sourceMappingURL=GraphFileManager.js.map
|