@hpcc-js/graph 3.7.4 → 3.7.5
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 +43 -43
- package/README.md +256 -256
- package/dist/assets/dagre-B-z4SP0u.js.map +1 -1
- package/dist/assets/graphviz-BK7FEJlA.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +7 -7
- package/src/AdjacencyGraph.ts +224 -224
- package/src/Edge.css +22 -22
- package/src/Edge.ts +257 -257
- package/src/Graph.css +18 -18
- package/src/Graph.ts +1077 -1077
- package/src/GraphData.ts +187 -187
- package/src/GraphLayouts.ts +214 -214
- package/src/Sankey.css +44 -44
- package/src/Sankey.ts +304 -304
- package/src/Subgraph.css +9 -9
- package/src/Subgraph.ts +165 -165
- package/src/Vertex.css +2 -2
- package/src/Vertex.ts +282 -282
- package/src/__package__.ts +3 -3
- package/src/__tests__/data.ts +444 -444
- package/src/__tests__/index.ts +1 -1
- package/src/__tests__/test1.ts +18 -18
- package/src/__tests__/test2.ts +80 -80
- package/src/__tests__/test3.ts +46 -46
- package/src/__tests__/test4.ts +66 -66
- package/src/__tests__/test5.ts +85 -85
- package/src/common/graphT.css +38 -38
- package/src/common/graphT.ts +1363 -1363
- package/src/common/index.ts +3 -3
- package/src/common/layouts/circle.ts +37 -37
- package/src/common/layouts/dagre.ts +145 -145
- package/src/common/layouts/dagreWorker.ts +24 -24
- package/src/common/layouts/forceDirected.ts +117 -117
- package/src/common/layouts/forceDirectedWorker.ts +22 -22
- package/src/common/layouts/geoForceDirected.ts +112 -112
- package/src/common/layouts/graphviz.ts +137 -137
- package/src/common/layouts/graphvizWorker.ts +27 -27
- package/src/common/layouts/index.ts +7 -7
- package/src/common/layouts/layout.ts +147 -147
- package/src/common/layouts/null.ts +39 -39
- package/src/common/layouts/placeholders.ts +113 -113
- package/src/common/layouts/tree.ts +326 -326
- package/src/common/layouts/workers/dagre.ts +46 -46
- package/src/common/layouts/workers/dagreOptions.ts +35 -35
- package/src/common/layouts/workers/forceDirected.ts +38 -38
- package/src/common/layouts/workers/forceDirectedOptions.ts +30 -30
- package/src/common/layouts/workers/graphviz.ts +225 -225
- package/src/common/layouts/workers/graphvizOptions.ts +70 -70
- package/src/common/liteMap.ts +72 -72
- package/src/common/liteSVGZooom.ts +61 -61
- package/src/common/sankeyGraph.css +44 -44
- package/src/common/sankeyGraph.ts +345 -345
- package/src/html/annotation.ts +71 -71
- package/src/html/component.ts +18 -18
- package/src/html/edge.ts +15 -15
- package/src/html/graphHtml.ts +11 -11
- package/src/html/graphHtmlT.ts +117 -117
- package/src/html/icon.ts +64 -64
- package/src/html/image.ts +26 -26
- package/src/html/imageChar.ts +18 -18
- package/src/html/index.ts +8 -8
- package/src/html/intersection.ts +110 -110
- package/src/html/shape.ts +141 -141
- package/src/html/text.ts +59 -59
- package/src/html/textBox.ts +45 -45
- package/src/html/vertex.ts +67 -67
- package/src/index.ts +10 -10
- package/src/react/dataGraph.ts +345 -345
- package/src/react/graphReact.ts +177 -177
- package/src/react/graphReactT.ts +44 -44
- package/src/react/index.ts +4 -4
- package/src/react/subgraph.tsx +30 -30
- package/src/react/vertex.tsx +31 -31
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
import { Graphviz } from "@hpcc-js/wasm-graphviz";
|
|
2
|
-
import { Cluster, Data, Engine, isCluster, Layout, LayoutJSON, LayoutSVG, Link, Node, Options } from "./graphvizOptions.js";
|
|
3
|
-
|
|
4
|
-
const clusterTpl = (cluster: Cluster): string => {
|
|
5
|
-
const childTpls: string[] = [];
|
|
6
|
-
cluster.children.forEach(child => {
|
|
7
|
-
if (isCluster(child)) {
|
|
8
|
-
childTpls.push(clusterTpl(child));
|
|
9
|
-
} else {
|
|
10
|
-
childTpls.push(nodeTpl(child));
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
return `subgraph cluster_${cluster.id} {
|
|
14
|
-
id="${cluster.id}";
|
|
15
|
-
label="${cluster.text}";
|
|
16
|
-
margin=16;
|
|
17
|
-
${childTpls.join("\n")}
|
|
18
|
-
}`;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const nodeTpl = (vc: Node): string => `${vc.id} [id="${vc.id}" label="${vc.text}" width=${pxToInch(vc.width)} height=${pxToInch(vc.height)}]`;
|
|
22
|
-
|
|
23
|
-
const linkTpl = (s, t, id, label) => `${s} -> ${t} [id="${id}", label="${label}"]`;
|
|
24
|
-
|
|
25
|
-
type GVPos = {
|
|
26
|
-
x: number;
|
|
27
|
-
y: number;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type GVBox = {
|
|
31
|
-
x: number;
|
|
32
|
-
y: number;
|
|
33
|
-
width: number;
|
|
34
|
-
height: number;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const pointToPx = (pt: number) => pt * 96 / 72;
|
|
38
|
-
const inchToPx = (inch: number) => inch * 96;
|
|
39
|
-
const pxToInch = (inch: number) => inch / 96;
|
|
40
|
-
|
|
41
|
-
function parseBB(bb?: string): GVBox {
|
|
42
|
-
const [llx, lly, urx, ury] = bb ? bb.split(",").map(p => pointToPx(+p)) : [0, 0, 0, 0];
|
|
43
|
-
const width = urx - llx;
|
|
44
|
-
const height = ury - lly;
|
|
45
|
-
return {
|
|
46
|
-
x: llx - width / 2,
|
|
47
|
-
y: lly - height / 2,
|
|
48
|
-
width,
|
|
49
|
-
height
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function parseBB2(_bb: string, page: GVBox): GVBox {
|
|
54
|
-
const bb = parseBB(_bb);
|
|
55
|
-
return {
|
|
56
|
-
x: -bb.x + page.width,
|
|
57
|
-
y: -bb.y + page.height,
|
|
58
|
-
width: bb.width,
|
|
59
|
-
height: bb.height
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function parsePos(pos: string, page: GVBox): GVPos {
|
|
64
|
-
const [x, y] = pos.split(",").map(p => pointToPx(+p));
|
|
65
|
-
return {
|
|
66
|
-
x: -x + page.width,
|
|
67
|
-
y: -y + page.height
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function parseNode(posStr: string, width: string, height: string, page: GVBox): GVBox {
|
|
72
|
-
const cpos = parsePos(posStr, page);
|
|
73
|
-
const w = inchToPx(+width);
|
|
74
|
-
const h = inchToPx(+height);
|
|
75
|
-
return {
|
|
76
|
-
x: cpos.x,
|
|
77
|
-
y: cpos.y,
|
|
78
|
-
width: w,
|
|
79
|
-
height: h
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function parseLink(l: any, page: GVBox) {
|
|
84
|
-
if (l.pos) {
|
|
85
|
-
const posStr = l.pos.substr(2);
|
|
86
|
-
const posParts = posStr.split(" ");
|
|
87
|
-
const points: Array<[number, number]> = posParts.map(p => parsePos(p, page)).map(pos => [pos.x - page.width / 2, pos.y - page.height / 2]);
|
|
88
|
-
const endpoint = points.shift();
|
|
89
|
-
return [...points, endpoint];
|
|
90
|
-
}
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function doLayoutSVG(mode: Engine, dot: string): Promise<LayoutSVG> {
|
|
95
|
-
const graphviz = await Graphviz.load();
|
|
96
|
-
try {
|
|
97
|
-
return {
|
|
98
|
-
svg: graphviz.layout(dot, "svg", mode)
|
|
99
|
-
};
|
|
100
|
-
} catch (e: any) {
|
|
101
|
-
if (e instanceof Error) {
|
|
102
|
-
return {
|
|
103
|
-
error: e.message,
|
|
104
|
-
errorDot: dot
|
|
105
|
-
};
|
|
106
|
-
} else {
|
|
107
|
-
throw e;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function doLayoutJSON(mode: Engine, dot: string): Promise<LayoutJSON> {
|
|
113
|
-
const graphviz = await Graphviz.load();
|
|
114
|
-
try {
|
|
115
|
-
return {
|
|
116
|
-
json: JSON.parse(graphviz.layout(dot, "json", mode))
|
|
117
|
-
};
|
|
118
|
-
} catch (e: any) {
|
|
119
|
-
if (e instanceof Error) {
|
|
120
|
-
return {
|
|
121
|
-
error: e.message,
|
|
122
|
-
errorDot: dot
|
|
123
|
-
};
|
|
124
|
-
} else {
|
|
125
|
-
throw e;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function graphvizLayout(data: Data, options: Options): Promise<Layout> {
|
|
131
|
-
if (data.raw) {
|
|
132
|
-
return doLayoutSVG(options.engine, data.raw);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const clusterIdx: { [id: string]: Cluster } = {};
|
|
136
|
-
const clusters: Cluster[] = [];
|
|
137
|
-
const dotClusters: string[] = [];
|
|
138
|
-
|
|
139
|
-
const nodeIdx: { [id: string]: Node } = {};
|
|
140
|
-
const nodes: Node[] = [];
|
|
141
|
-
const dotNodes: string[] = [];
|
|
142
|
-
|
|
143
|
-
const linkIdx: { [id: string]: Link } = {};
|
|
144
|
-
const links: Link[] = [];
|
|
145
|
-
const dotLinks: string[] = [];
|
|
146
|
-
|
|
147
|
-
function walk(item: Cluster | Node, top: boolean) {
|
|
148
|
-
if (isCluster(item)) {
|
|
149
|
-
clusterIdx[item.id] = item;
|
|
150
|
-
clusters.push(item);
|
|
151
|
-
item.children.forEach(child => walk(child, false));
|
|
152
|
-
if (top) {
|
|
153
|
-
dotClusters.push(clusterTpl(item));
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
nodeIdx[item.id] = item;
|
|
157
|
-
nodes.push(item);
|
|
158
|
-
if (top) {
|
|
159
|
-
dotNodes.push(nodeTpl(item));
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
data.items.forEach(item => walk(item, true));
|
|
164
|
-
|
|
165
|
-
data.links.forEach(link => {
|
|
166
|
-
linkIdx[link.id] = link;
|
|
167
|
-
links.push(link);
|
|
168
|
-
dotLinks.push(linkTpl(link.source.id, link.target.id, link.id, link.text));
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
return doLayoutJSON(options.engine, `\
|
|
172
|
-
digraph G {
|
|
173
|
-
graph [fontname=Verdana,fontsize=11.0];
|
|
174
|
-
graph [rankdir=TB];
|
|
175
|
-
node [shape=rect,fontname=Verdana,fontsize=11.0,fixedsize=true];
|
|
176
|
-
edge [fontname=Verdana,fontsize=11.0];
|
|
177
|
-
|
|
178
|
-
${dotClusters.join("\n")}
|
|
179
|
-
|
|
180
|
-
${dotLinks.join("\n")}
|
|
181
|
-
|
|
182
|
-
${dotNodes.join("\n")}
|
|
183
|
-
}`).then(response => {
|
|
184
|
-
if (response.json) {
|
|
185
|
-
const pageBBox = parseBB(response.json.bb);
|
|
186
|
-
|
|
187
|
-
if (response.json.objects) {
|
|
188
|
-
response.json.objects.forEach(n => {
|
|
189
|
-
if (n.nodes) {
|
|
190
|
-
const bb = parseBB2(n.bb, pageBBox);
|
|
191
|
-
const c = clusterIdx[n.id];
|
|
192
|
-
c.x = bb.x - pageBBox.width / 2;
|
|
193
|
-
c.y = bb.y - pageBBox.height / 2;
|
|
194
|
-
c.width = bb.width;
|
|
195
|
-
c.height = bb.height;
|
|
196
|
-
} else {
|
|
197
|
-
const pos = parseNode(n.pos, n.width, n.height, pageBBox);
|
|
198
|
-
const v = nodeIdx[n.id];
|
|
199
|
-
if (v) {
|
|
200
|
-
v.x = pos.x - pageBBox.width / 2;
|
|
201
|
-
v.y = pos.y - pageBBox.height / 2;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
if (response.json.edges) {
|
|
207
|
-
response.json.edges.forEach(l => {
|
|
208
|
-
const e = linkIdx[l.id];
|
|
209
|
-
if (e) {
|
|
210
|
-
e.points = parseLink(l, pageBBox);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
return { clusters, nodes, links };
|
|
215
|
-
} else {
|
|
216
|
-
return response;
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
self.onmessage = event => {
|
|
222
|
-
graphvizLayout.apply(undefined, event.data).then(result => {
|
|
223
|
-
self.postMessage(result);
|
|
224
|
-
});
|
|
225
|
-
};
|
|
1
|
+
import { Graphviz } from "@hpcc-js/wasm-graphviz";
|
|
2
|
+
import { Cluster, Data, Engine, isCluster, Layout, LayoutJSON, LayoutSVG, Link, Node, Options } from "./graphvizOptions.js";
|
|
3
|
+
|
|
4
|
+
const clusterTpl = (cluster: Cluster): string => {
|
|
5
|
+
const childTpls: string[] = [];
|
|
6
|
+
cluster.children.forEach(child => {
|
|
7
|
+
if (isCluster(child)) {
|
|
8
|
+
childTpls.push(clusterTpl(child));
|
|
9
|
+
} else {
|
|
10
|
+
childTpls.push(nodeTpl(child));
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
return `subgraph cluster_${cluster.id} {
|
|
14
|
+
id="${cluster.id}";
|
|
15
|
+
label="${cluster.text}";
|
|
16
|
+
margin=16;
|
|
17
|
+
${childTpls.join("\n")}
|
|
18
|
+
}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const nodeTpl = (vc: Node): string => `${vc.id} [id="${vc.id}" label="${vc.text}" width=${pxToInch(vc.width)} height=${pxToInch(vc.height)}]`;
|
|
22
|
+
|
|
23
|
+
const linkTpl = (s, t, id, label) => `${s} -> ${t} [id="${id}", label="${label}"]`;
|
|
24
|
+
|
|
25
|
+
type GVPos = {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type GVBox = {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const pointToPx = (pt: number) => pt * 96 / 72;
|
|
38
|
+
const inchToPx = (inch: number) => inch * 96;
|
|
39
|
+
const pxToInch = (inch: number) => inch / 96;
|
|
40
|
+
|
|
41
|
+
function parseBB(bb?: string): GVBox {
|
|
42
|
+
const [llx, lly, urx, ury] = bb ? bb.split(",").map(p => pointToPx(+p)) : [0, 0, 0, 0];
|
|
43
|
+
const width = urx - llx;
|
|
44
|
+
const height = ury - lly;
|
|
45
|
+
return {
|
|
46
|
+
x: llx - width / 2,
|
|
47
|
+
y: lly - height / 2,
|
|
48
|
+
width,
|
|
49
|
+
height
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseBB2(_bb: string, page: GVBox): GVBox {
|
|
54
|
+
const bb = parseBB(_bb);
|
|
55
|
+
return {
|
|
56
|
+
x: -bb.x + page.width,
|
|
57
|
+
y: -bb.y + page.height,
|
|
58
|
+
width: bb.width,
|
|
59
|
+
height: bb.height
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function parsePos(pos: string, page: GVBox): GVPos {
|
|
64
|
+
const [x, y] = pos.split(",").map(p => pointToPx(+p));
|
|
65
|
+
return {
|
|
66
|
+
x: -x + page.width,
|
|
67
|
+
y: -y + page.height
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function parseNode(posStr: string, width: string, height: string, page: GVBox): GVBox {
|
|
72
|
+
const cpos = parsePos(posStr, page);
|
|
73
|
+
const w = inchToPx(+width);
|
|
74
|
+
const h = inchToPx(+height);
|
|
75
|
+
return {
|
|
76
|
+
x: cpos.x,
|
|
77
|
+
y: cpos.y,
|
|
78
|
+
width: w,
|
|
79
|
+
height: h
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function parseLink(l: any, page: GVBox) {
|
|
84
|
+
if (l.pos) {
|
|
85
|
+
const posStr = l.pos.substr(2);
|
|
86
|
+
const posParts = posStr.split(" ");
|
|
87
|
+
const points: Array<[number, number]> = posParts.map(p => parsePos(p, page)).map(pos => [pos.x - page.width / 2, pos.y - page.height / 2]);
|
|
88
|
+
const endpoint = points.shift();
|
|
89
|
+
return [...points, endpoint];
|
|
90
|
+
}
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function doLayoutSVG(mode: Engine, dot: string): Promise<LayoutSVG> {
|
|
95
|
+
const graphviz = await Graphviz.load();
|
|
96
|
+
try {
|
|
97
|
+
return {
|
|
98
|
+
svg: graphviz.layout(dot, "svg", mode)
|
|
99
|
+
};
|
|
100
|
+
} catch (e: any) {
|
|
101
|
+
if (e instanceof Error) {
|
|
102
|
+
return {
|
|
103
|
+
error: e.message,
|
|
104
|
+
errorDot: dot
|
|
105
|
+
};
|
|
106
|
+
} else {
|
|
107
|
+
throw e;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function doLayoutJSON(mode: Engine, dot: string): Promise<LayoutJSON> {
|
|
113
|
+
const graphviz = await Graphviz.load();
|
|
114
|
+
try {
|
|
115
|
+
return {
|
|
116
|
+
json: JSON.parse(graphviz.layout(dot, "json", mode))
|
|
117
|
+
};
|
|
118
|
+
} catch (e: any) {
|
|
119
|
+
if (e instanceof Error) {
|
|
120
|
+
return {
|
|
121
|
+
error: e.message,
|
|
122
|
+
errorDot: dot
|
|
123
|
+
};
|
|
124
|
+
} else {
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function graphvizLayout(data: Data, options: Options): Promise<Layout> {
|
|
131
|
+
if (data.raw) {
|
|
132
|
+
return doLayoutSVG(options.engine, data.raw);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const clusterIdx: { [id: string]: Cluster } = {};
|
|
136
|
+
const clusters: Cluster[] = [];
|
|
137
|
+
const dotClusters: string[] = [];
|
|
138
|
+
|
|
139
|
+
const nodeIdx: { [id: string]: Node } = {};
|
|
140
|
+
const nodes: Node[] = [];
|
|
141
|
+
const dotNodes: string[] = [];
|
|
142
|
+
|
|
143
|
+
const linkIdx: { [id: string]: Link } = {};
|
|
144
|
+
const links: Link[] = [];
|
|
145
|
+
const dotLinks: string[] = [];
|
|
146
|
+
|
|
147
|
+
function walk(item: Cluster | Node, top: boolean) {
|
|
148
|
+
if (isCluster(item)) {
|
|
149
|
+
clusterIdx[item.id] = item;
|
|
150
|
+
clusters.push(item);
|
|
151
|
+
item.children.forEach(child => walk(child, false));
|
|
152
|
+
if (top) {
|
|
153
|
+
dotClusters.push(clusterTpl(item));
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
nodeIdx[item.id] = item;
|
|
157
|
+
nodes.push(item);
|
|
158
|
+
if (top) {
|
|
159
|
+
dotNodes.push(nodeTpl(item));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
data.items.forEach(item => walk(item, true));
|
|
164
|
+
|
|
165
|
+
data.links.forEach(link => {
|
|
166
|
+
linkIdx[link.id] = link;
|
|
167
|
+
links.push(link);
|
|
168
|
+
dotLinks.push(linkTpl(link.source.id, link.target.id, link.id, link.text));
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
return doLayoutJSON(options.engine, `\
|
|
172
|
+
digraph G {
|
|
173
|
+
graph [fontname=Verdana,fontsize=11.0];
|
|
174
|
+
graph [rankdir=TB];
|
|
175
|
+
node [shape=rect,fontname=Verdana,fontsize=11.0,fixedsize=true];
|
|
176
|
+
edge [fontname=Verdana,fontsize=11.0];
|
|
177
|
+
|
|
178
|
+
${dotClusters.join("\n")}
|
|
179
|
+
|
|
180
|
+
${dotLinks.join("\n")}
|
|
181
|
+
|
|
182
|
+
${dotNodes.join("\n")}
|
|
183
|
+
}`).then(response => {
|
|
184
|
+
if (response.json) {
|
|
185
|
+
const pageBBox = parseBB(response.json.bb);
|
|
186
|
+
|
|
187
|
+
if (response.json.objects) {
|
|
188
|
+
response.json.objects.forEach(n => {
|
|
189
|
+
if (n.nodes) {
|
|
190
|
+
const bb = parseBB2(n.bb, pageBBox);
|
|
191
|
+
const c = clusterIdx[n.id];
|
|
192
|
+
c.x = bb.x - pageBBox.width / 2;
|
|
193
|
+
c.y = bb.y - pageBBox.height / 2;
|
|
194
|
+
c.width = bb.width;
|
|
195
|
+
c.height = bb.height;
|
|
196
|
+
} else {
|
|
197
|
+
const pos = parseNode(n.pos, n.width, n.height, pageBBox);
|
|
198
|
+
const v = nodeIdx[n.id];
|
|
199
|
+
if (v) {
|
|
200
|
+
v.x = pos.x - pageBBox.width / 2;
|
|
201
|
+
v.y = pos.y - pageBBox.height / 2;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (response.json.edges) {
|
|
207
|
+
response.json.edges.forEach(l => {
|
|
208
|
+
const e = linkIdx[l.id];
|
|
209
|
+
if (e) {
|
|
210
|
+
e.points = parseLink(l, pageBBox);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return { clusters, nodes, links };
|
|
215
|
+
} else {
|
|
216
|
+
return response;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
self.onmessage = event => {
|
|
222
|
+
graphvizLayout.apply(undefined, event.data).then(result => {
|
|
223
|
+
self.postMessage(result);
|
|
224
|
+
});
|
|
225
|
+
};
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
export type Engine = "circo" | "dot" | "fdp" | "neato" | "osage" | "patchwork" | "twopi";
|
|
2
|
-
|
|
3
|
-
export interface Cluster {
|
|
4
|
-
id: string;
|
|
5
|
-
text: string;
|
|
6
|
-
children: Array<Cluster | Node>;
|
|
7
|
-
|
|
8
|
-
// result ---
|
|
9
|
-
x?: number;
|
|
10
|
-
y?: number;
|
|
11
|
-
width?: number;
|
|
12
|
-
height?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface Node {
|
|
16
|
-
id: string;
|
|
17
|
-
text: string;
|
|
18
|
-
width: number;
|
|
19
|
-
height: number;
|
|
20
|
-
|
|
21
|
-
// result ---
|
|
22
|
-
x?: number;
|
|
23
|
-
y?: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function isCluster(item: Cluster | Node): item is Cluster {
|
|
27
|
-
return (item as Cluster).children !== undefined;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface Link {
|
|
31
|
-
id: string;
|
|
32
|
-
source: Node;
|
|
33
|
-
target: Node;
|
|
34
|
-
text: string;
|
|
35
|
-
|
|
36
|
-
// result ---
|
|
37
|
-
points?: Array<[number, number]>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface Data {
|
|
41
|
-
items: Array<Cluster | Node>;
|
|
42
|
-
links: Link[];
|
|
43
|
-
raw: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface Options {
|
|
47
|
-
engine: Engine;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface LayoutError {
|
|
51
|
-
error?: string;
|
|
52
|
-
errorDot?: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface LayoutSVG extends LayoutError {
|
|
56
|
-
svg?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface LayoutJSON extends LayoutError {
|
|
60
|
-
json?: any;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export type LayoutSuccess = { clusters: Cluster[], nodes: Node[], links: Link[] };
|
|
64
|
-
export type Layout = LayoutSuccess | LayoutJSON | LayoutSVG;
|
|
65
|
-
|
|
66
|
-
export function isLayoutSuccess(item: any): item is LayoutSuccess {
|
|
67
|
-
return (item as LayoutSuccess)?.clusters !== undefined &&
|
|
68
|
-
(item as LayoutSuccess)?.nodes !== undefined &&
|
|
69
|
-
(item as LayoutSuccess)?.links !== undefined;
|
|
70
|
-
}
|
|
1
|
+
export type Engine = "circo" | "dot" | "fdp" | "neato" | "osage" | "patchwork" | "twopi";
|
|
2
|
+
|
|
3
|
+
export interface Cluster {
|
|
4
|
+
id: string;
|
|
5
|
+
text: string;
|
|
6
|
+
children: Array<Cluster | Node>;
|
|
7
|
+
|
|
8
|
+
// result ---
|
|
9
|
+
x?: number;
|
|
10
|
+
y?: number;
|
|
11
|
+
width?: number;
|
|
12
|
+
height?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Node {
|
|
16
|
+
id: string;
|
|
17
|
+
text: string;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
|
|
21
|
+
// result ---
|
|
22
|
+
x?: number;
|
|
23
|
+
y?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isCluster(item: Cluster | Node): item is Cluster {
|
|
27
|
+
return (item as Cluster).children !== undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Link {
|
|
31
|
+
id: string;
|
|
32
|
+
source: Node;
|
|
33
|
+
target: Node;
|
|
34
|
+
text: string;
|
|
35
|
+
|
|
36
|
+
// result ---
|
|
37
|
+
points?: Array<[number, number]>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface Data {
|
|
41
|
+
items: Array<Cluster | Node>;
|
|
42
|
+
links: Link[];
|
|
43
|
+
raw: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Options {
|
|
47
|
+
engine: Engine;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface LayoutError {
|
|
51
|
+
error?: string;
|
|
52
|
+
errorDot?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface LayoutSVG extends LayoutError {
|
|
56
|
+
svg?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface LayoutJSON extends LayoutError {
|
|
60
|
+
json?: any;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type LayoutSuccess = { clusters: Cluster[], nodes: Node[], links: Link[] };
|
|
64
|
+
export type Layout = LayoutSuccess | LayoutJSON | LayoutSVG;
|
|
65
|
+
|
|
66
|
+
export function isLayoutSuccess(item: any): item is LayoutSuccess {
|
|
67
|
+
return (item as LayoutSuccess)?.clusters !== undefined &&
|
|
68
|
+
(item as LayoutSuccess)?.nodes !== undefined &&
|
|
69
|
+
(item as LayoutSuccess)?.links !== undefined;
|
|
70
|
+
}
|