@hpcc-js/graph 3.2.1 → 3.3.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/{dagre-D0bY8RPD.js.map → dagre-BVMQn91n.js.map} +1 -1
- package/dist/assets/graphviz-CMhlTALo.js.map +1 -1
- package/dist/index.js +2630 -1994
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +81 -7
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +7 -3
- package/src/__tests__/test5.ts +1 -1
- package/src/common/graphT.css +33 -0
- package/src/{graph2 → common}/graphT.ts +78 -47
- package/src/common/index.ts +3 -0
- package/src/{graph2 → common}/layouts/dagre.ts +16 -3
- package/src/{graph2 → common}/layouts/graphviz.ts +17 -4
- package/src/{graph2 → common}/layouts/layout.ts +48 -5
- package/src/common/layouts/pathIntersection.ts +67 -0
- package/src/{graph2 → common}/layouts/placeholders.ts +12 -0
- package/src/{graph2 → common}/layouts/tree.ts +2 -4
- package/src/{graph2 → common}/sankeyGraph.ts +2 -2
- package/src/html/annotation.ts +71 -0
- package/src/html/component.ts +14 -0
- package/src/html/graphHtml.ts +10 -0
- package/src/html/graphHtmlT.ts +49 -0
- package/src/html/icon.ts +64 -0
- package/src/html/image.ts +26 -0
- package/src/html/imageChar.ts +18 -0
- package/src/html/index.ts +8 -0
- package/src/html/shape.ts +136 -0
- package/src/html/text.ts +59 -0
- package/src/html/textBox.ts +41 -0
- package/src/html/vertex.ts +65 -0
- package/src/index.ts +3 -1
- package/src/{graph2 → react}/dataGraph.ts +11 -11
- package/src/{graph2/graph.ts → react/graphReact.ts} +65 -22
- package/src/{graph2 → react}/graphReactT.ts +1 -1
- package/src/react/index.ts +4 -0
- package/src/{graph2 → react}/subgraph.tsx +2 -1
- package/src/{graph2 → react}/vertex.tsx +2 -1
- package/types/{graph2 → common}/graphT.d.ts +9 -11
- package/types/common/index.d.ts +3 -0
- package/types/{graph2 → common}/layouts/layout.d.ts +18 -1
- package/types/common/layouts/pathIntersection.d.ts +24 -0
- package/types/{graph2 → common}/layouts/placeholders.d.ts +6 -0
- package/types/{graph2 → common}/sankeyGraph.d.ts +2 -2
- package/types/html/annotation.d.ts +13 -0
- package/types/html/component.d.ts +10 -0
- package/types/html/graphHtml.d.ts +5 -0
- package/types/html/graphHtmlT.d.ts +9 -0
- package/types/html/icon.d.ts +15 -0
- package/types/html/image.d.ts +8 -0
- package/types/html/imageChar.d.ts +2 -0
- package/types/html/index.d.ts +8 -0
- package/types/html/shape.d.ts +31 -0
- package/types/html/text.d.ts +10 -0
- package/types/html/textBox.d.ts +11 -0
- package/types/html/vertex.d.ts +17 -0
- package/types/index.d.ts +3 -1
- package/types/{graph2 → react}/dataGraph.d.ts +2 -2
- package/types/{graph2/graph.d.ts → react/graphReact.d.ts} +13 -3
- package/types/{graph2 → react}/graphReactT.d.ts +1 -1
- package/types/react/index.d.ts +4 -0
- package/types/{graph2 → react}/subgraph.d.ts +1 -1
- package/types/{graph2 → react}/vertex.d.ts +1 -1
- package/src/graph2/graph.css +0 -34
- package/src/graph2/index.ts +0 -7
- package/src/test.ts +0 -649
- package/types/graph2/index.d.ts +0 -7
- /package/src/{graph2 → common}/layouts/circle.ts +0 -0
- /package/src/{graph2 → common}/layouts/dagreWorker.ts +0 -0
- /package/src/{graph2 → common}/layouts/forceDirected.ts +0 -0
- /package/src/{graph2 → common}/layouts/forceDirectedWorker.ts +0 -0
- /package/src/{graph2 → common}/layouts/geoForceDirected.ts +0 -0
- /package/src/{graph2 → common}/layouts/graphvizWorker.ts +0 -0
- /package/src/{graph2 → common}/layouts/index.ts +0 -0
- /package/src/{graph2 → common}/layouts/null.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/dagre.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/dagreOptions.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/forceDirected.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/forceDirectedOptions.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/graphviz.ts +0 -0
- /package/src/{graph2 → common}/layouts/workers/graphvizOptions.ts +0 -0
- /package/src/{graph2 → common}/liteMap.ts +0 -0
- /package/src/{graph2 → common}/liteSVGZooom.ts +0 -0
- /package/src/{graph2 → common}/sankeyGraph.css +0 -0
- /package/types/{graph2 → common}/layouts/circle.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/dagre.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/dagreWorker.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/forceDirected.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/forceDirectedWorker.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/geoForceDirected.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/graphviz.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/graphvizWorker.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/index.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/null.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/tree.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/workers/dagreOptions.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/workers/forceDirectedOptions.d.ts +0 -0
- /package/types/{graph2 → common}/layouts/workers/graphvizOptions.d.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/graph",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "hpcc-js - Viz Graph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.umd.cjs",
|
|
@@ -44,6 +44,9 @@
|
|
|
44
44
|
"@hpcc-js/react": "^3.2.1",
|
|
45
45
|
"@hpcc-js/util": "^3.3.0"
|
|
46
46
|
},
|
|
47
|
+
"optionalPeerDependencies": {
|
|
48
|
+
"react": ">=18.0.0"
|
|
49
|
+
},
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@hpcc-js/esbuild-plugins": "^1.4.0",
|
|
49
52
|
"@hpcc-js/wasm-graphviz": "1.6.1",
|
|
@@ -56,7 +59,8 @@
|
|
|
56
59
|
"d3-shape": "^1",
|
|
57
60
|
"d3-tile": "^1",
|
|
58
61
|
"d3-transition": "^1",
|
|
59
|
-
"dagre": "0.8.5"
|
|
62
|
+
"dagre": "0.8.5",
|
|
63
|
+
"lit-html": "3.2.1"
|
|
60
64
|
},
|
|
61
65
|
"repository": {
|
|
62
66
|
"type": "git",
|
|
@@ -69,5 +73,5 @@
|
|
|
69
73
|
"url": "https://github.com/hpcc-systems/Visualization/issues"
|
|
70
74
|
},
|
|
71
75
|
"homepage": "https://github.com/hpcc-systems/Visualization",
|
|
72
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "85de89fcb489c807653c422459d98785ef647465"
|
|
73
77
|
}
|
package/src/__tests__/test5.ts
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.graph_GraphT .graphVertex {
|
|
2
|
+
cursor: pointer;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.graph_GraphT .allowDragging .graphVertex {
|
|
6
|
+
cursor: pointer;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.graph_GraphT .allowDragging .graphVertex.grabbed {
|
|
10
|
+
cursor: grabbing;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.graph_GraphT .graphEdge {
|
|
14
|
+
stroke: darkgray;
|
|
15
|
+
fill: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.graph_GraphT .graphEdge>text {
|
|
19
|
+
stroke: none;
|
|
20
|
+
fill: black;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.graph_GraphT .graphEdge.hide-text>text {
|
|
24
|
+
display: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.graph_GraphT g.selected rect {
|
|
28
|
+
stroke: navy !important;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.graph_GraphT g.selected circle {
|
|
32
|
+
stroke: navy !important;
|
|
33
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { d3Event, drag as d3Drag, Palette, select as d3Select, Selection, Spacer, SVGGlowFilter, SVGZoomWidget, ToggleButton, Utility, Widget
|
|
2
|
-
import { IconEx, Icons, render } from "@hpcc-js/react";
|
|
1
|
+
import { d3Event, drag as d3Drag, Palette, select as d3Select, Selection, Spacer, SVGGlowFilter, SVGZoomWidget, Button, ToggleButton, Utility, Widget } from "@hpcc-js/common";
|
|
3
2
|
import { Graph2 as GraphCollection, hashSum } from "@hpcc-js/util";
|
|
4
3
|
import { HTMLTooltip } from "@hpcc-js/html";
|
|
5
4
|
import { interpolateNumberArray as d3InterpolateNumberArray } from "d3-interpolate";
|
|
@@ -7,17 +6,18 @@ import "d3-transition";
|
|
|
7
6
|
import { interpolatePath as d3InterpolatePath } from "d3-interpolate-path";
|
|
8
7
|
import { Circle, Dagre, ForceDirected, ForceDirectedAnimated, Graphviz, ILayout, Null } from "./layouts/index.ts";
|
|
9
8
|
import { Options as FDOptions } from "./layouts/forceDirectedWorker.ts";
|
|
10
|
-
import type { VertexBaseProps, EdgeBaseProps, GraphDataProps, HierarchyBase, SubgraphBaseProps } from "./layouts/placeholders.ts";
|
|
9
|
+
import type { BaseProps, VertexBaseProps, EdgeBaseProps, GraphDataProps, HierarchyBase, SubgraphBaseProps } from "./layouts/placeholders.ts";
|
|
11
10
|
import { EdgePlaceholder, SubgraphPlaceholder, VertexPlaceholder, isEdgePlaceholder } from "./layouts/placeholders.ts";
|
|
12
11
|
import { Engine, graphviz as gvWorker } from "./layouts/graphvizWorker.ts";
|
|
13
12
|
import { Tree, RadialTree, Dendrogram, RadialDendrogram } from "./layouts/tree.ts";
|
|
14
13
|
|
|
15
|
-
import "
|
|
14
|
+
import "./graphT.css";
|
|
16
15
|
|
|
17
16
|
let scriptDir = (globalThis?.document?.currentScript as HTMLScriptElement)?.src ?? "./dummy.js";
|
|
18
17
|
scriptDir = scriptDir.substring(0, scriptDir.replace(/[?#].*/, "").lastIndexOf("/") + 1);
|
|
19
18
|
|
|
20
19
|
export {
|
|
20
|
+
BaseProps,
|
|
21
21
|
GraphDataProps,
|
|
22
22
|
SubgraphBaseProps,
|
|
23
23
|
VertexBaseProps,
|
|
@@ -43,7 +43,7 @@ function dragEnd<V extends VertexBaseProps>(n: VertexPlaceholder<V>) {
|
|
|
43
43
|
n.fy = n.sy = undefined;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export type RendererT<T> = (props: T, element: SVGGElement) =>
|
|
46
|
+
export type RendererT<T> = (props: T, element: SVGGElement) => unknown;
|
|
47
47
|
|
|
48
48
|
export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E extends EdgeBaseProps<V>> extends SVGZoomWidget {
|
|
49
49
|
|
|
@@ -121,6 +121,8 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
121
121
|
];
|
|
122
122
|
this._iconBar.buttons(buttons.concat(this._iconBar.buttons()));
|
|
123
123
|
|
|
124
|
+
this.selectionGlowColor("navy");
|
|
125
|
+
|
|
124
126
|
this._dragHandler
|
|
125
127
|
.on("start", function (d) {
|
|
126
128
|
if (context.allowDragging()) {
|
|
@@ -241,24 +243,6 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
241
243
|
return this._iconBar.buttons();
|
|
242
244
|
}
|
|
243
245
|
|
|
244
|
-
protected _categories: IconEx[] = [];
|
|
245
|
-
categories(): IconEx[];
|
|
246
|
-
categories(_: IconEx[]): this;
|
|
247
|
-
categories(_?: IconEx[]): IconEx[] | this {
|
|
248
|
-
if (_ === void 0) return this._categories;
|
|
249
|
-
this._categories = _;
|
|
250
|
-
return this;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
protected _annotations: IconEx[] = [];
|
|
254
|
-
annotations(): IconEx[];
|
|
255
|
-
annotations(_: IconEx[]): this;
|
|
256
|
-
annotations(_?: IconEx[]): IconEx[] | this {
|
|
257
|
-
if (_ === void 0) return this._annotations;
|
|
258
|
-
this._annotations = _;
|
|
259
|
-
return this;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
246
|
private _origData: GraphDataProps<SG, V, E> = {
|
|
263
247
|
subgraphs: [],
|
|
264
248
|
vertices: [],
|
|
@@ -485,7 +469,7 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
485
469
|
...context.vertexMapper(d.props, d.props.origData)
|
|
486
470
|
}
|
|
487
471
|
);
|
|
488
|
-
context._vertexRenderer(props, this);
|
|
472
|
+
d.renderResult = context._vertexRenderer(props, this);
|
|
489
473
|
}
|
|
490
474
|
})
|
|
491
475
|
.transition().duration(this.transitionDuration())
|
|
@@ -579,7 +563,10 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
579
563
|
|
|
580
564
|
moveEdgePlaceholder(ep: EdgePlaceholder<V, E>, transition: boolean): this {
|
|
581
565
|
const edgeLayout = {
|
|
582
|
-
...this._layoutAlgo.edgePath(ep as any, this.edgeArcDepth())
|
|
566
|
+
...this._layoutAlgo.edgePath(ep as any, this.edgeArcDepth()),
|
|
567
|
+
markerStart: `url(#${this.id()}_circleFoot)`,
|
|
568
|
+
markerEnd: `url(#${this.id()}_arrowHead)`,
|
|
569
|
+
|
|
583
570
|
};
|
|
584
571
|
const context = this;
|
|
585
572
|
if (this._edgeRenderer && ep.element) {
|
|
@@ -596,7 +583,7 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
596
583
|
strokeWidth: ep.props.strokeWidth ?? context.edgeStrokeWidth(),
|
|
597
584
|
color: ep.props.stroke ?? context.edgeColor()
|
|
598
585
|
};
|
|
599
|
-
context._edgeRenderer({ ...edgeLayout, ...ep.props, ...updated }, ep.element.node());
|
|
586
|
+
ep.renderResult = context._edgeRenderer({ graphInstance: context, ...edgeLayout, ...ep.props, ...updated }, ep.element.node());
|
|
600
587
|
};
|
|
601
588
|
});
|
|
602
589
|
}
|
|
@@ -639,7 +626,7 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
639
626
|
if (this._transformScale > this.maxScale() + (this._transformScale - this.maxScale()) / 2) {
|
|
640
627
|
scale = this.maxScale() + (this._transformScale - this.maxScale()) / 2;
|
|
641
628
|
} else if (this._transformScale < this.minScale() - (this._transformScale - this.minScale()) / 13) {
|
|
642
|
-
|
|
629
|
+
scale = this.minScale() - (this._transformScale - this.minScale()) / 13;
|
|
643
630
|
}
|
|
644
631
|
}
|
|
645
632
|
return Math.round(pos * scale * rf) / rf;
|
|
@@ -654,7 +641,14 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
654
641
|
projectPlacholder(vp: VertexPlaceholder<V>) {
|
|
655
642
|
return {
|
|
656
643
|
x: this.project(vp.fx !== undefined ? vp.fx : vp.x),
|
|
657
|
-
y: this.project(vp.fy !== undefined ? vp.fy : vp.y)
|
|
644
|
+
y: this.project(vp.fy !== undefined ? vp.fy : vp.y),
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
rprojectPlacholder(vp: VertexPlaceholder<V>) {
|
|
649
|
+
return {
|
|
650
|
+
x: this.rproject(vp.fx !== undefined ? vp.fx : vp.x),
|
|
651
|
+
y: this.rproject(vp.fy !== undefined ? vp.fy : vp.y),
|
|
658
652
|
};
|
|
659
653
|
}
|
|
660
654
|
|
|
@@ -663,26 +657,9 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
663
657
|
}
|
|
664
658
|
|
|
665
659
|
updateCategories() {
|
|
666
|
-
render(Icons, {
|
|
667
|
-
icons: this._categories.map((c): IconEx => ({
|
|
668
|
-
...c,
|
|
669
|
-
id: this.categoryID(c.id),
|
|
670
|
-
fill: c.fill || "transparent",
|
|
671
|
-
imageCharFill: c.imageCharFill || this._catPalette(c.id)
|
|
672
|
-
}))
|
|
673
|
-
}, this._svgDefsCat.node());
|
|
674
660
|
}
|
|
675
661
|
|
|
676
662
|
updateAnnotations() {
|
|
677
|
-
render(Icons, {
|
|
678
|
-
icons: this._annotations.map((c): IconEx => ({
|
|
679
|
-
...c,
|
|
680
|
-
id: this.categoryID(c.id, "ann"),
|
|
681
|
-
shape: c.shape || "square",
|
|
682
|
-
height: c.height || 12,
|
|
683
|
-
fill: c.fill || this._catPalette(c.id)
|
|
684
|
-
}))
|
|
685
|
-
}, this._svgDefsAnn.node());
|
|
686
663
|
}
|
|
687
664
|
|
|
688
665
|
private _edgeRenderer: RendererT<E>;
|
|
@@ -831,7 +808,7 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
831
808
|
...context.vertexMapper(d.props, d.props.origData)
|
|
832
809
|
}
|
|
833
810
|
);
|
|
834
|
-
context._vertexRenderer(props, this);
|
|
811
|
+
d.renderResult = context._vertexRenderer(props, this);
|
|
835
812
|
})
|
|
836
813
|
;
|
|
837
814
|
return this;
|
|
@@ -900,15 +877,66 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
900
877
|
return this;
|
|
901
878
|
}
|
|
902
879
|
|
|
880
|
+
addMarkers(clearFirst: boolean = false) {
|
|
881
|
+
if (clearFirst) {
|
|
882
|
+
this._svgDefs.select("#" + this._id + "_arrowHead").remove();
|
|
883
|
+
this._svgDefs.select("#" + this._id + "_circleFoot").remove();
|
|
884
|
+
this._svgDefs.select("#" + this._id + "_circleHead").remove();
|
|
885
|
+
}
|
|
886
|
+
this._svgDefs.append("marker")
|
|
887
|
+
.attr("class", "marker")
|
|
888
|
+
.attr("id", this._id + "_arrowHead")
|
|
889
|
+
.attr("viewBox", "0 0 10 10")
|
|
890
|
+
.attr("refX", 10)
|
|
891
|
+
.attr("refY", 5)
|
|
892
|
+
.attr("markerWidth", 8)
|
|
893
|
+
.attr("markerHeight", 8)
|
|
894
|
+
.attr("markerUnits", "strokeWidth")
|
|
895
|
+
.attr("orient", "auto")
|
|
896
|
+
.append("polyline")
|
|
897
|
+
.attr("points", "0,0 10,5 0,10 1,5")
|
|
898
|
+
;
|
|
899
|
+
this._svgDefs.append("marker")
|
|
900
|
+
.attr("class", "marker")
|
|
901
|
+
.attr("id", this._id + "_circleFoot")
|
|
902
|
+
.attr("viewBox", "0 0 10 10")
|
|
903
|
+
.attr("refX", 1)
|
|
904
|
+
.attr("refY", 5)
|
|
905
|
+
.attr("markerWidth", 7)
|
|
906
|
+
.attr("markerHeight", 7)
|
|
907
|
+
.attr("markerUnits", "strokeWidth")
|
|
908
|
+
.attr("orient", "auto")
|
|
909
|
+
.append("circle")
|
|
910
|
+
.attr("cx", 5)
|
|
911
|
+
.attr("cy", 5)
|
|
912
|
+
.attr("r", 4)
|
|
913
|
+
;
|
|
914
|
+
this._svgDefs.append("marker")
|
|
915
|
+
.attr("class", "marker")
|
|
916
|
+
.attr("id", this._id + "_circleHead")
|
|
917
|
+
.attr("viewBox", "0 0 10 10")
|
|
918
|
+
.attr("refX", 9)
|
|
919
|
+
.attr("refY", 5)
|
|
920
|
+
.attr("markerWidth", 7)
|
|
921
|
+
.attr("markerHeight", 7)
|
|
922
|
+
.attr("markerUnits", "strokeWidth")
|
|
923
|
+
.attr("orient", "auto")
|
|
924
|
+
.append("circle")
|
|
925
|
+
.attr("cx", 5)
|
|
926
|
+
.attr("cy", 5)
|
|
927
|
+
.attr("r", 4)
|
|
928
|
+
;
|
|
929
|
+
}
|
|
930
|
+
|
|
903
931
|
enter(domNode, element) {
|
|
904
932
|
super.enter(domNode, element);
|
|
905
933
|
|
|
906
934
|
const svg = this.locateSVGNode(domNode);
|
|
907
935
|
this._svgDefs = d3Select(svg).select<SVGDefsElement>("defs");
|
|
908
936
|
this._centroidFilter = new SVGGlowFilter(this._svgDefs, this._id + "_glow");
|
|
909
|
-
|
|
910
937
|
this._svgDefsCat = this._svgDefs.append("g");
|
|
911
938
|
this._svgDefsAnn = this._svgDefs.append("g");
|
|
939
|
+
this.addMarkers();
|
|
912
940
|
this._subgraphG = this._renderElement.append("g");
|
|
913
941
|
this._edgeG = this._renderElement.append("g");
|
|
914
942
|
this._vertexG = this._renderElement.append("g");
|
|
@@ -1036,6 +1064,9 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
1036
1064
|
super.update(domNode, element);
|
|
1037
1065
|
|
|
1038
1066
|
this._renderElement.classed("allowDragging", this.allowDragging());
|
|
1067
|
+
if (this._centroidFilter) {
|
|
1068
|
+
this._centroidFilter.update(this.selectionGlowColor());
|
|
1069
|
+
}
|
|
1039
1070
|
|
|
1040
1071
|
this.updateCategories();
|
|
1041
1072
|
this.updateAnnotations();
|
|
@@ -111,9 +111,22 @@ export class Dagre extends Layout {
|
|
|
111
111
|
let points = [];
|
|
112
112
|
let hasNaN = false;
|
|
113
113
|
if (ep.points) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
const line = this.edgeLine(ep);
|
|
115
|
+
points = ep.points.map((p, idx) => {
|
|
116
|
+
let x = NaN;
|
|
117
|
+
let y = NaN;
|
|
118
|
+
if (idx === 0) {
|
|
119
|
+
x = this._graph.rproject(line.source.x);
|
|
120
|
+
y = this._graph.rproject(line.source.y);
|
|
121
|
+
} else if (idx === ep.points.length - 1) {
|
|
122
|
+
x = this._graph.rproject(line.target.x);
|
|
123
|
+
y = this._graph.rproject(line.target.y);
|
|
124
|
+
} else {
|
|
125
|
+
x = p[0];
|
|
126
|
+
y = p[1];
|
|
127
|
+
}
|
|
128
|
+
x = this._graph.project(x, false);
|
|
129
|
+
y = this._graph.project(y, false);
|
|
117
130
|
if (isNaN(x) || isNaN(y)) {
|
|
118
131
|
hasNaN = true;
|
|
119
132
|
}
|
|
@@ -38,7 +38,7 @@ export class Graphviz extends Layout {
|
|
|
38
38
|
case "vertex":
|
|
39
39
|
delete item["fx"];
|
|
40
40
|
delete item["fy"];
|
|
41
|
-
const bbox =
|
|
41
|
+
const bbox = this.vertexSize(item);
|
|
42
42
|
const retVal = {
|
|
43
43
|
id: item.id,
|
|
44
44
|
text: item.props.text,
|
|
@@ -102,9 +102,22 @@ export class Graphviz extends Layout {
|
|
|
102
102
|
let points = [];
|
|
103
103
|
let hasNaN = false;
|
|
104
104
|
if (ep.points) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
const line = this.edgeLine(ep);
|
|
106
|
+
points = ep.points.map((p, idx) => {
|
|
107
|
+
let x = NaN;
|
|
108
|
+
let y = NaN;
|
|
109
|
+
if (idx === 0) {
|
|
110
|
+
x = this._graph.rproject(line.source.x);
|
|
111
|
+
y = this._graph.rproject(line.source.y);
|
|
112
|
+
} else if (idx === ep.points.length - 1) {
|
|
113
|
+
x = this._graph.rproject(line.target.x);
|
|
114
|
+
y = this._graph.rproject(line.target.y);
|
|
115
|
+
} else {
|
|
116
|
+
x = p[0];
|
|
117
|
+
y = p[1];
|
|
118
|
+
}
|
|
119
|
+
x = this._graph.project(x, false);
|
|
120
|
+
y = this._graph.project(y, false);
|
|
108
121
|
if (isNaN(x) || isNaN(y)) {
|
|
109
122
|
hasNaN = true;
|
|
110
123
|
}
|
|
@@ -2,9 +2,20 @@ import { Graph2 as GraphCollection } from "@hpcc-js/util";
|
|
|
2
2
|
import { curveBasis as d3CurveBasis, curveCardinal as d3CurveCardinal, line as d3Line } from "d3-shape";
|
|
3
3
|
import { EdgePlaceholder, SubgraphPlaceholder, VertexPlaceholder } from "./placeholders.ts";
|
|
4
4
|
import { EdgeLayout } from "./tree.ts";
|
|
5
|
+
import { intersection } from "./pathIntersection.ts";
|
|
5
6
|
|
|
6
7
|
export type Point = [number, number];
|
|
7
8
|
|
|
9
|
+
interface Position {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface Line {
|
|
15
|
+
source: Position;
|
|
16
|
+
target: Position;
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
const lineBasis = d3Line<Point>()
|
|
9
20
|
.x(d => d[0])
|
|
10
21
|
.y(d => d[1])
|
|
@@ -27,11 +38,15 @@ export interface ILayout {
|
|
|
27
38
|
|
|
28
39
|
export type Size = { width: number, height: number };
|
|
29
40
|
export interface IGraph {
|
|
41
|
+
id(): string;
|
|
30
42
|
size(): Size;
|
|
31
43
|
graphData(): GraphCollection<VertexPlaceholder, EdgePlaceholder, SubgraphPlaceholder>;
|
|
32
44
|
|
|
33
|
-
project(pos: number, clip
|
|
45
|
+
project(pos: number, clip?: boolean);
|
|
46
|
+
rproject(pos: number);
|
|
47
|
+
|
|
34
48
|
projectPlacholder(vp: VertexPlaceholder);
|
|
49
|
+
rprojectPlacholder(vp: VertexPlaceholder);
|
|
35
50
|
|
|
36
51
|
moveSubgraphs(transition: boolean): this;
|
|
37
52
|
|
|
@@ -78,10 +93,38 @@ export class Layout implements ILayout {
|
|
|
78
93
|
return [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2];
|
|
79
94
|
}
|
|
80
95
|
|
|
96
|
+
vertexSize(vp: VertexPlaceholder): { width: number, height: number } {
|
|
97
|
+
const size = vp.renderResult?.extent ? vp.renderResult.extent : vp.element.node().getBBox();
|
|
98
|
+
const retVal = {
|
|
99
|
+
width: this._graph.rproject(size.width),
|
|
100
|
+
height: this._graph.rproject(size.height)
|
|
101
|
+
};
|
|
102
|
+
return retVal;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
edgeLine(ep: EdgePlaceholder): Line {
|
|
106
|
+
const sPos = { ...this._graph.projectPlacholder(ep.source), w: ep.source?.renderResult?.extent?.width ?? 0, h: ep.source?.renderResult?.extent?.height ?? 0 };
|
|
107
|
+
const tPos = { ...this._graph.projectPlacholder(ep.target), w: ep.target?.renderResult?.extent?.width ?? 0, h: ep.target?.renderResult?.extent?.height ?? 0 };
|
|
108
|
+
const sIntersect = intersection(sPos, { start: sPos, end: tPos });
|
|
109
|
+
const tIntersect = intersection(tPos, { start: sPos, end: tPos });
|
|
110
|
+
return {
|
|
111
|
+
source: {
|
|
112
|
+
x: sIntersect ? sIntersect.x : sPos.x,
|
|
113
|
+
y: sIntersect ? sIntersect.y : sPos.y
|
|
114
|
+
},
|
|
115
|
+
target: {
|
|
116
|
+
x: tIntersect ? tIntersect.x : tPos.x,
|
|
117
|
+
y: tIntersect ? tIntersect.y : tPos.y
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
81
122
|
edgePath(ep: EdgePlaceholder, curveDepth: number): { path: string, labelPos: Point } {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
123
|
+
const line = this.edgeLine(ep);
|
|
124
|
+
const points: Point[] = [
|
|
125
|
+
[line.source.x, line.source.y],
|
|
126
|
+
[line.target.x, line.target.y]
|
|
127
|
+
];
|
|
85
128
|
|
|
86
129
|
if (curveDepth) {
|
|
87
130
|
const dx = points[0][0] - points[1][0];
|
|
@@ -92,7 +135,7 @@ export class Layout implements ILayout {
|
|
|
92
135
|
const midY = (points[0][1] + points[1][1]) / 2 + dx * curveDepth / 100;
|
|
93
136
|
return {
|
|
94
137
|
path: lineCardinal([points[0], [midX, midY], points[1]]),
|
|
95
|
-
labelPos: [midX, midY]
|
|
138
|
+
labelPos: [midX, midY],
|
|
96
139
|
};
|
|
97
140
|
}
|
|
98
141
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface Pos {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Segment {
|
|
7
|
+
start: Pos;
|
|
8
|
+
end: Pos;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Rectangle {
|
|
12
|
+
topLeft: Pos;
|
|
13
|
+
topRight: Pos;
|
|
14
|
+
bottomLeft: Pos;
|
|
15
|
+
bottomRight: Pos;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Rectangle2 {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
w: number;
|
|
22
|
+
h: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function rectEdges(rect: Rectangle) {
|
|
26
|
+
return [
|
|
27
|
+
{ start: rect.topLeft, end: rect.topRight },
|
|
28
|
+
{ start: rect.topRight, end: rect.bottomRight },
|
|
29
|
+
{ start: rect.bottomRight, end: rect.bottomLeft },
|
|
30
|
+
{ start: rect.bottomLeft, end: rect.topLeft }
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function lineIntersection(segment1: Segment, segment2: Segment) {
|
|
35
|
+
const { x: x1, y: y1 } = segment1.start;
|
|
36
|
+
const { x: x2, y: y2 } = segment1.end;
|
|
37
|
+
const { x: x3, y: y3 } = segment2.start;
|
|
38
|
+
const { x: x4, y: y4 } = segment2.end;
|
|
39
|
+
|
|
40
|
+
const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
|
41
|
+
if (denom === 0) return null; // Parallel lines
|
|
42
|
+
|
|
43
|
+
const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
|
|
44
|
+
const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
|
|
45
|
+
|
|
46
|
+
if (t > 0 && t < 1 && u > 0 && u < 1) {
|
|
47
|
+
return {
|
|
48
|
+
x: x1 + t * (x2 - x1),
|
|
49
|
+
y: y1 + t * (y2 - y1)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null; // No intersection
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function intersection(rect: Rectangle2, line: Segment) {
|
|
57
|
+
for (const edge of rectEdges({
|
|
58
|
+
topLeft: { x: rect.x - rect.w / 2, y: rect.y - rect.h / 2 },
|
|
59
|
+
topRight: { x: rect.x + rect.w / 2, y: rect.y - rect.h / 2 },
|
|
60
|
+
bottomRight: { x: rect.x + rect.w / 2, y: rect.y + rect.h / 2 },
|
|
61
|
+
bottomLeft: { x: rect.x - rect.w / 2, y: rect.y + rect.h / 2 }
|
|
62
|
+
})) {
|
|
63
|
+
const intersectionPoint = lineIntersection(edge, line);
|
|
64
|
+
if (intersectionPoint) return intersectionPoint;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
@@ -31,7 +31,10 @@ export interface EdgeBaseProps<V extends VertexBaseProps = VertexBaseProps> exte
|
|
|
31
31
|
strokeDasharray?: string;
|
|
32
32
|
strokeWidth?: number;
|
|
33
33
|
stroke?: string;
|
|
34
|
+
path?: string;
|
|
34
35
|
fontFamily?: string;
|
|
36
|
+
markerStart?: string;
|
|
37
|
+
markerEnd?: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
export interface HierarchyBase<SG extends SubgraphBaseProps, V extends VertexBaseProps> {
|
|
@@ -52,6 +55,9 @@ export interface SubgraphPlaceholder<SG extends SubgraphBaseProps = SubgraphBase
|
|
|
52
55
|
element?: Selection<SVGGElement, SubgraphPlaceholder<SG>, SVGGElement, any>;
|
|
53
56
|
props: SG;
|
|
54
57
|
|
|
58
|
+
// render result properties ---
|
|
59
|
+
renderResult?: unknown;
|
|
60
|
+
|
|
55
61
|
// Dagre / Graphviz Properties ---
|
|
56
62
|
x?: number; // The node’s current x-position
|
|
57
63
|
y?: number; // The node’s current y-position
|
|
@@ -62,6 +68,9 @@ export interface VertexPlaceholder<V extends VertexBaseProps = VertexBaseProps>
|
|
|
62
68
|
element?: Selection<SVGGElement, VertexPlaceholder<V>, SVGGElement, any>;
|
|
63
69
|
props: V;
|
|
64
70
|
|
|
71
|
+
// render result properties ---
|
|
72
|
+
renderResult?: any;
|
|
73
|
+
|
|
65
74
|
// D3 Assigned Properties ---
|
|
66
75
|
index?: number; // The node’s zero-based index into nodes
|
|
67
76
|
x?: number; // The node’s current x-position
|
|
@@ -91,6 +100,9 @@ export interface EdgePlaceholder<V extends VertexBaseProps = VertexBaseProps, E
|
|
|
91
100
|
source: VertexPlaceholder<V>; // The link’s source node
|
|
92
101
|
target: VertexPlaceholder<V>; // The link’s target node
|
|
93
102
|
|
|
103
|
+
// render result properties ---
|
|
104
|
+
renderResult?: any;
|
|
105
|
+
|
|
94
106
|
// D3 Assigned Properties ---
|
|
95
107
|
index?: number; // The zero-based index into links, assigned by this method
|
|
96
108
|
|
|
@@ -236,8 +236,7 @@ export class Tree extends TidyTreeBase {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
edgePath(ep: EdgePlaceholder, curveDepth: number): EdgeLayout {
|
|
239
|
-
const source = this.
|
|
240
|
-
const target = this._graph.projectPlacholder(ep.target);
|
|
239
|
+
const { source, target } = this.edgeLine(ep);
|
|
241
240
|
return {
|
|
242
241
|
path: linkHorizontal({ source, target }),
|
|
243
242
|
labelPos: this.center([[source.x, source.y], [target.x, target.y]])
|
|
@@ -294,8 +293,7 @@ export class Dendrogram extends TidyTreeBase {
|
|
|
294
293
|
}
|
|
295
294
|
|
|
296
295
|
edgePath(ep: EdgePlaceholder, curveDepth: number): EdgeLayout {
|
|
297
|
-
const source = this.
|
|
298
|
-
const target = this._graph.projectPlacholder(ep.target);
|
|
296
|
+
const { source, target } = this.edgeLine(ep);
|
|
299
297
|
return {
|
|
300
298
|
path: linkHorizontal({ source, target }),
|
|
301
299
|
labelPos: this.center([[source.x, source.y], [target.x, target.y]])
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Palette, SVGWidget, Utility, select as d3Select } from "@hpcc-js/common";
|
|
2
2
|
import { compare2 } from "@hpcc-js/util";
|
|
3
3
|
import { sankey as d3Sankey, sankeyLinkHorizontal as d3SankeyLinkHorizontal } from "d3-sankey";
|
|
4
|
-
import { AnnotationColumn, toJsonObj } from "
|
|
4
|
+
import { AnnotationColumn, toJsonObj } from "../react/dataGraph.ts";
|
|
5
5
|
|
|
6
|
-
import "
|
|
6
|
+
import "./sankeyGraph.css";
|
|
7
7
|
import { EdgeBaseProps, VertexBaseProps } from "./graphT.ts";
|
|
8
8
|
|
|
9
9
|
export class SankeyGraph extends SVGWidget {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { svg } from "lit-html";
|
|
2
|
+
import { Palette, Utility } from "@hpcc-js/common";
|
|
3
|
+
import { extend } from "./component.ts";
|
|
4
|
+
import { TextBox } from "./textBox.ts";
|
|
5
|
+
|
|
6
|
+
export interface AnnotationProps {
|
|
7
|
+
text: string;
|
|
8
|
+
fontFamily?: string;
|
|
9
|
+
fontSize?: number;
|
|
10
|
+
fill?: string;
|
|
11
|
+
stroke?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const annotation = ({
|
|
15
|
+
text,
|
|
16
|
+
fontFamily = "FontAwesome",
|
|
17
|
+
fontSize = 8,
|
|
18
|
+
fill = "gray",
|
|
19
|
+
stroke = "darkgray"
|
|
20
|
+
}: AnnotationProps) => {
|
|
21
|
+
const renderChar = fontFamily === "FontAwesome" ? Utility.faChar(text) : text;
|
|
22
|
+
const textBoxTpl = TextBox({
|
|
23
|
+
text: {
|
|
24
|
+
text: renderChar,
|
|
25
|
+
fill: Palette.textColor(fill),
|
|
26
|
+
fontFamily,
|
|
27
|
+
fontSize,
|
|
28
|
+
dominantBaseline: fontFamily === "FontAwesome" ? "ideographic" : undefined
|
|
29
|
+
},
|
|
30
|
+
padding: 3,
|
|
31
|
+
fill,
|
|
32
|
+
stroke,
|
|
33
|
+
cornerRadius: 0
|
|
34
|
+
});
|
|
35
|
+
return extend(svg`\
|
|
36
|
+
<g data-click="annotation" data-click-data=${JSON.stringify({ text, fill, fontFamily, fontSize, stroke })}>
|
|
37
|
+
${textBoxTpl}
|
|
38
|
+
</g>`, textBoxTpl.extent.width, textBoxTpl.extent.height);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface AnnotationsProps {
|
|
42
|
+
annotations: AnnotationProps[];
|
|
43
|
+
padding?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const annotations = ({
|
|
47
|
+
annotations,
|
|
48
|
+
padding = 3,
|
|
49
|
+
}: AnnotationsProps) => {
|
|
50
|
+
let xOffset = 0;
|
|
51
|
+
const items = annotations.map(annotationProp => {
|
|
52
|
+
const ann = annotation(annotationProp);
|
|
53
|
+
const itemSvg = extend(svg`\
|
|
54
|
+
<g transform="translate(${xOffset + ann.extent.width / 2} 0)">
|
|
55
|
+
${ann}
|
|
56
|
+
</g>`, ann.extent.width, ann.extent.height);
|
|
57
|
+
xOffset += ann.extent.width + padding;
|
|
58
|
+
return itemSvg;
|
|
59
|
+
});
|
|
60
|
+
const { width, height } = items.reduce((acc, item) => {
|
|
61
|
+
return {
|
|
62
|
+
width: acc.width + item.extent.width,
|
|
63
|
+
height: Math.max(acc.height, item.extent.height)
|
|
64
|
+
};
|
|
65
|
+
}, { width: (items.length - 1) * padding, height: 0 });
|
|
66
|
+
return extend(svg`\
|
|
67
|
+
<g transform="translate(${-width / 2} 0)">
|
|
68
|
+
${items}
|
|
69
|
+
</g>`, width, height);
|
|
70
|
+
};
|
|
71
|
+
|