@hpcc-js/graph 3.9.0 → 3.9.1
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/dist/assets/graphviz-BNpvf_gp.js.map +1 -0
- package/dist/assets/graphvizDot-CfwAsDJC.js.map +1 -0
- package/dist/index.js +138 -91
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +6 -6
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +9 -9
- package/src/common/layouts/graphvizDot.ts +33 -0
- package/src/common/layouts/index.ts +1 -0
- package/src/common/layouts/workers/graphvizDot.ts +25 -0
- package/src/common/layouts/workers/graphvizDotOptions.ts +14 -0
- package/src/graphviz/Widget.css +21 -4
- package/src/graphviz/Widget.ts +41 -19
- package/types/common/layouts/graphvizDot.d.ts +8 -0
- package/types/common/layouts/index.d.ts +1 -0
- package/types/common/layouts/workers/graphvizDotOptions.d.ts +11 -0
- package/types/graphviz/Widget.d.ts +3 -2
- package/dist/assets/graphviz-C6pqwU-h.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/graph",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.1",
|
|
4
4
|
"description": "hpcc-js - Viz Graph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.umd.cjs",
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
"update-major": "npx --yes npm-check-updates -u"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@hpcc-js/api": "^3.5.
|
|
44
|
-
"@hpcc-js/common": "^3.9.
|
|
45
|
-
"@hpcc-js/html": "^3.4.
|
|
46
|
-
"@hpcc-js/react": "^3.5.
|
|
47
|
-
"@hpcc-js/util": "^3.6.
|
|
43
|
+
"@hpcc-js/api": "^3.5.6",
|
|
44
|
+
"@hpcc-js/common": "^3.9.1",
|
|
45
|
+
"@hpcc-js/html": "^3.4.6",
|
|
46
|
+
"@hpcc-js/react": "^3.5.6",
|
|
47
|
+
"@hpcc-js/util": "^3.6.6"
|
|
48
48
|
},
|
|
49
49
|
"optionalPeerDependencies": {
|
|
50
50
|
"react": ">=17.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@hpcc-js/esbuild-plugins": "^1.9.
|
|
54
|
-
"@hpcc-js/wasm-graphviz": "1.
|
|
53
|
+
"@hpcc-js/esbuild-plugins": "^1.9.6",
|
|
54
|
+
"@hpcc-js/wasm-graphviz": "1.27.3",
|
|
55
55
|
"@types/d3-transition": "1.3.6",
|
|
56
56
|
"@types/dagre": "0.7.54",
|
|
57
57
|
"d3-force": "^1",
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"url": "https://github.com/hpcc-systems/Visualization/issues"
|
|
77
77
|
},
|
|
78
78
|
"homepage": "https://github.com/hpcc-systems/Visualization",
|
|
79
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "0128487e97c3ca56f55697c40c340de2c5c61ff2"
|
|
80
80
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Engine } from "@hpcc-js/wasm-graphviz";
|
|
2
|
+
import { isLayoutSuccess, type LayoutSVG } from "./workers/graphvizDotOptions.ts";
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import GraphvizDotWorker from "./workers/graphvizDot.ts?worker&inline";
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
isLayoutSuccess,
|
|
8
|
+
type LayoutSVG
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export interface GraphvizDotResponse {
|
|
12
|
+
response: Promise<string>;
|
|
13
|
+
terminate: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function graphvizDot(dot: string, layout: Engine = "dot"): GraphvizDotResponse {
|
|
17
|
+
const worker = new GraphvizDotWorker();
|
|
18
|
+
const response = new Promise<string>((resolve, reject) => {
|
|
19
|
+
worker.onmessage = event => {
|
|
20
|
+
if (isLayoutSuccess(event.data)) {
|
|
21
|
+
resolve(event.data.svg);
|
|
22
|
+
} else {
|
|
23
|
+
reject(new Error(event.data.error));
|
|
24
|
+
}
|
|
25
|
+
worker.terminate();
|
|
26
|
+
};
|
|
27
|
+
worker.postMessage({ dot, layout });
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
terminate: (): void => worker.terminate(),
|
|
31
|
+
response
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Graphviz, type Engine } from "@hpcc-js/wasm-graphviz";
|
|
2
|
+
import { LayoutSVG } from "./graphvizDotOptions.js";
|
|
3
|
+
|
|
4
|
+
async function graphvizDot(dot: string, layout: Engine): Promise<LayoutSVG> {
|
|
5
|
+
const graphviz = await Graphviz.load();
|
|
6
|
+
try {
|
|
7
|
+
return {
|
|
8
|
+
svg: graphviz.layout(dot, "svg", layout)
|
|
9
|
+
};
|
|
10
|
+
} catch (e: any) {
|
|
11
|
+
if (e instanceof Error) {
|
|
12
|
+
return {
|
|
13
|
+
error: e.message,
|
|
14
|
+
errorDot: dot
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
throw e;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
self.onmessage = event => {
|
|
22
|
+
graphvizDot(event.data.dot, event.data.layout).then(result => {
|
|
23
|
+
self.postMessage(result);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LayoutError {
|
|
2
|
+
error?: string;
|
|
3
|
+
errorDot?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface LayoutSVG extends LayoutError {
|
|
7
|
+
svg?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type LayoutSuccess = { svg: string };
|
|
11
|
+
|
|
12
|
+
export function isLayoutSuccess(item: any): item is LayoutSuccess {
|
|
13
|
+
return (item as LayoutSuccess)?.svg !== undefined;
|
|
14
|
+
}
|
package/src/graphviz/Widget.css
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
--gv-select-fill: light-dark(#deecf9, #1b3a5c);
|
|
7
7
|
|
|
8
8
|
--gv-unknown-stroke: light-dark(#616161, #9e9e9e);
|
|
9
|
-
--gv-unknown-fill: light-dark(#
|
|
9
|
+
--gv-unknown-fill: light-dark(#e0e0e020, #2a2a3e20);
|
|
10
10
|
--gv-complete-stroke: light-dark(#2e7d32, #66bb6a);
|
|
11
|
-
--gv-complete-fill: light-dark(#
|
|
11
|
+
--gv-complete-fill: light-dark(#e8f5e920, #1b3a1e20);
|
|
12
12
|
--gv-failed-stroke: light-dark(#c62828, #ef5350);
|
|
13
|
-
--gv-failed-fill: light-dark(#
|
|
13
|
+
--gv-failed-fill: light-dark(#ffebee20, #3a1b1b20);
|
|
14
14
|
--gv-running-stroke: light-dark(#e65100, #ffa726);
|
|
15
|
-
--gv-running-fill: light-dark(#
|
|
15
|
+
--gv-running-fill: light-dark(#fff3e020, #3a2a1b20);
|
|
16
16
|
|
|
17
17
|
background-color: var(--gv-shadow);
|
|
18
18
|
stroke: var(--gv-fg);
|
|
@@ -124,6 +124,23 @@
|
|
|
124
124
|
--_fill: var(--gv-running-fill);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/* When selected and stateful, keep state color on border but selected color on fill. */
|
|
128
|
+
.graph_GraphvizWidget :is(.unknown, .complete, .failed, .running).selected>:is(path, polygon, ellipse, polyline, rect) {
|
|
129
|
+
stroke: var(--_stroke);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.graph_GraphvizWidget :is(.unknown, .complete, .failed, .running).cluster.selected>:is(path, polygon, ellipse, polyline, rect) {
|
|
133
|
+
stroke: var(--_stroke);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.graph_GraphvizWidget :is(.unknown, .complete, .failed, .running):is(.node, .cluster).selected>:is(path, polygon, ellipse, polyline, rect):first-of-type {
|
|
137
|
+
fill: var(--gv-select-fill);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.graph_GraphvizWidget :is(.unknown, .complete, .failed, .running).edge.selected>:is(polygon, ellipse, polyline) {
|
|
141
|
+
fill: var(--gv-select-stroke);
|
|
142
|
+
}
|
|
143
|
+
|
|
127
144
|
/* Keep node and cluster outlines visible when zoomed out */
|
|
128
145
|
.graph_GraphvizWidget .node>path,
|
|
129
146
|
.graph_GraphvizWidget .node>polygon,
|
package/src/graphviz/Widget.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Graph } from "@hpcc-js/wasm-graphviz";
|
|
2
2
|
import { d3Event, SVGZoomWidget, type Widget as WidgetT } from "@hpcc-js/common";
|
|
3
|
+
import { graphvizDot, GraphvizDotResponse } from "../common/layouts/index.ts";
|
|
3
4
|
|
|
4
5
|
import "./Widget.css";
|
|
5
6
|
|
|
@@ -24,8 +25,6 @@ export class Widget extends SVGZoomWidget {
|
|
|
24
25
|
protected _selection: { [id: string]: boolean } = {};
|
|
25
26
|
protected _selectionPreferredNode: { [id: string]: SVGGElement } = {};
|
|
26
27
|
|
|
27
|
-
protected _customVertices: CustomVertex[] = [];
|
|
28
|
-
|
|
29
28
|
constructor() {
|
|
30
29
|
super();
|
|
31
30
|
this._drawStartPos = "origin";
|
|
@@ -341,8 +340,6 @@ export class Widget extends SVGZoomWidget {
|
|
|
341
340
|
}
|
|
342
341
|
}
|
|
343
342
|
|
|
344
|
-
protected _prevDot: string | undefined;
|
|
345
|
-
|
|
346
343
|
itemBBox(scopeID: string): ReturnType<Widget["getRenderElementBBox"]>;
|
|
347
344
|
itemBBox(node: SVGGraphicsElement): ReturnType<Widget["getRenderElementBBox"]>;
|
|
348
345
|
itemBBox(scopeIDOrNode: string | SVGGraphicsElement) {
|
|
@@ -386,18 +383,6 @@ export class Widget extends SVGZoomWidget {
|
|
|
386
383
|
|
|
387
384
|
update(domNode: HTMLElement | SVGElement, element: SVGGElement): this {
|
|
388
385
|
super.update(domNode, element);
|
|
389
|
-
|
|
390
|
-
this._customVertices = this.collectCustomVertices();
|
|
391
|
-
const dot = this._data.toDot();
|
|
392
|
-
if (this._prevDot !== dot) {
|
|
393
|
-
this._prevDot = dot;
|
|
394
|
-
const svg = this._data.layout("svg", "dot").replace(Widget._svgColorRe, m => Widget._svgColorMap[m]);
|
|
395
|
-
const svgDoc = new DOMParser().parseFromString(svg, "image/svg+xml");
|
|
396
|
-
const renderNode = this._renderElement.node();
|
|
397
|
-
renderNode.replaceChildren(...svgDoc.documentElement.childNodes);
|
|
398
|
-
this.postrenderCustomVertices(this._customVertices);
|
|
399
|
-
this._selectionChanged();
|
|
400
|
-
}
|
|
401
386
|
return this;
|
|
402
387
|
}
|
|
403
388
|
|
|
@@ -406,11 +391,48 @@ export class Widget extends SVGZoomWidget {
|
|
|
406
391
|
return this;
|
|
407
392
|
}
|
|
408
393
|
|
|
394
|
+
protected _prevDot: string | undefined;
|
|
395
|
+
protected _prevLayout: GraphvizDotResponse | undefined;
|
|
409
396
|
render(callback?: (w: WidgetT) => void): this {
|
|
410
397
|
super.render((w: WidgetT) => {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
398
|
+
const customVertices = this.collectCustomVertices();
|
|
399
|
+
const dot = this._data.toDot();
|
|
400
|
+
if (this._prevDot !== dot) {
|
|
401
|
+
this._prevDot = dot;
|
|
402
|
+
if (this._prevLayout) {
|
|
403
|
+
this._prevLayout.terminate();
|
|
404
|
+
}
|
|
405
|
+
const renderNode = this._renderElement.node();
|
|
406
|
+
renderNode.innerHTML = "";
|
|
407
|
+
|
|
408
|
+
this._prevLayout = graphvizDot(dot, "dot");
|
|
409
|
+
this._prevLayout.response
|
|
410
|
+
.then(svg => {
|
|
411
|
+
if (this._prevLayout) {
|
|
412
|
+
this._prevLayout = undefined;
|
|
413
|
+
}
|
|
414
|
+
svg = svg.replace(Widget._svgColorRe, m => Widget._svgColorMap[m]);
|
|
415
|
+
const svgDoc = new DOMParser().parseFromString(svg, "image/svg+xml");
|
|
416
|
+
renderNode.replaceChildren(...svgDoc.documentElement.childNodes);
|
|
417
|
+
this.postrenderCustomVertices(customVertices);
|
|
418
|
+
this._selectionChanged();
|
|
419
|
+
}).catch(e => {
|
|
420
|
+
if (this._prevLayout) {
|
|
421
|
+
this._prevLayout = undefined;
|
|
422
|
+
}
|
|
423
|
+
renderNode.innerHTML = "";
|
|
424
|
+
this.postrenderCustomVertices([]);
|
|
425
|
+
this._selectionChanged();
|
|
426
|
+
console.error(e);
|
|
427
|
+
}).finally(() => {
|
|
428
|
+
if (callback) {
|
|
429
|
+
callback(w);
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
} else {
|
|
433
|
+
if (callback) {
|
|
434
|
+
callback(w);
|
|
435
|
+
}
|
|
414
436
|
}
|
|
415
437
|
});
|
|
416
438
|
return this;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Engine } from "@hpcc-js/wasm-graphviz";
|
|
2
|
+
import { isLayoutSuccess, type LayoutSVG } from "./workers/graphvizDotOptions.ts";
|
|
3
|
+
export { isLayoutSuccess, type LayoutSVG };
|
|
4
|
+
export interface GraphvizDotResponse {
|
|
5
|
+
response: Promise<string>;
|
|
6
|
+
terminate: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function graphvizDot(dot: string, layout?: Engine): GraphvizDotResponse;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface LayoutError {
|
|
2
|
+
error?: string;
|
|
3
|
+
errorDot?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface LayoutSVG extends LayoutError {
|
|
6
|
+
svg?: string;
|
|
7
|
+
}
|
|
8
|
+
export type LayoutSuccess = {
|
|
9
|
+
svg: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function isLayoutSuccess(item: any): item is LayoutSuccess;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Graph } from "@hpcc-js/wasm-graphviz";
|
|
2
2
|
import { SVGZoomWidget, type Widget as WidgetT } from "@hpcc-js/common";
|
|
3
|
+
import { GraphvizDotResponse } from "../common/layouts/index.ts";
|
|
3
4
|
import "./Widget.css";
|
|
4
5
|
export declare const CUSTOM_HTML = "htmlContent";
|
|
5
6
|
export declare const CUSTOM_SVG = "svgContent";
|
|
@@ -18,7 +19,6 @@ export declare class Widget extends SVGZoomWidget {
|
|
|
18
19
|
protected _selectionPreferredNode: {
|
|
19
20
|
[id: string]: SVGGElement;
|
|
20
21
|
};
|
|
21
|
-
protected _customVertices: CustomVertex[];
|
|
22
22
|
constructor();
|
|
23
23
|
protected _data: Graph;
|
|
24
24
|
data(_: Graph): this;
|
|
@@ -36,13 +36,14 @@ export declare class Widget extends SVGZoomWidget {
|
|
|
36
36
|
enter(domNode: HTMLElement | SVGElement, element?: SVGGElement): this;
|
|
37
37
|
protected collectCustomVertices(): CustomVertex[];
|
|
38
38
|
protected postrenderCustomVertices(customVertices: CustomVertex[]): void;
|
|
39
|
-
protected _prevDot: string | undefined;
|
|
40
39
|
itemBBox(scopeID: string): ReturnType<Widget["getRenderElementBBox"]>;
|
|
41
40
|
itemBBox(node: SVGGraphicsElement): ReturnType<Widget["getRenderElementBBox"]>;
|
|
42
41
|
zoomToItem(scopeID: string): this;
|
|
43
42
|
zoomToItem(node: SVGGraphicsElement): this;
|
|
44
43
|
update(domNode: HTMLElement | SVGElement, element: SVGGElement): this;
|
|
45
44
|
exit(domNode: HTMLElement | SVGElement, element?: SVGGElement): this;
|
|
45
|
+
protected _prevDot: string | undefined;
|
|
46
|
+
protected _prevLayout: GraphvizDotResponse | undefined;
|
|
46
47
|
render(callback?: (w: WidgetT) => void): this;
|
|
47
48
|
selectionChanged(): void;
|
|
48
49
|
vertexButtonClicked(id: string, action: string): void;
|