@hpcc-js/graph 3.3.1 → 3.3.3
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/index.js +159 -130
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +10 -10
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +8 -8
- package/src/common/graphT.ts +0 -55
- package/src/common/layouts/layout.ts +2 -3
- package/src/common/layouts/placeholders.ts +0 -2
- package/src/html/component.ts +7 -3
- package/src/html/edge.ts +15 -0
- package/src/html/graphHtml.ts +4 -2
- package/src/html/graphHtmlT.ts +72 -4
- package/src/html/icon.ts +1 -1
- package/src/html/intersection.ts +110 -0
- package/src/html/shape.ts +7 -2
- package/src/html/textBox.ts +5 -1
- package/src/html/vertex.ts +4 -2
- package/types/common/graphT.d.ts +0 -1
- package/types/common/layouts/placeholders.d.ts +0 -2
- package/types/html/component.d.ts +5 -5
- package/types/html/edge.d.ts +6 -0
- package/types/html/graphHtml.d.ts +3 -2
- package/types/html/graphHtmlT.d.ts +8 -0
- package/types/html/intersection.d.ts +20 -0
- package/src/common/layouts/pathIntersection.ts +0 -67
- package/types/common/layouts/pathIntersection.d.ts +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/graph",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.3",
|
|
4
4
|
"description": "hpcc-js - Viz Graph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.umd.cjs",
|
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
"update-major": "npx --yes npm-check-updates -u"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@hpcc-js/api": "^3.3.
|
|
42
|
-
"@hpcc-js/common": "^3.3.
|
|
43
|
-
"@hpcc-js/html": "^3.2.
|
|
44
|
-
"@hpcc-js/react": "^3.2.
|
|
45
|
-
"@hpcc-js/util": "^3.3.
|
|
41
|
+
"@hpcc-js/api": "^3.3.1",
|
|
42
|
+
"@hpcc-js/common": "^3.3.1",
|
|
43
|
+
"@hpcc-js/html": "^3.2.2",
|
|
44
|
+
"@hpcc-js/react": "^3.2.2",
|
|
45
|
+
"@hpcc-js/util": "^3.3.1"
|
|
46
46
|
},
|
|
47
47
|
"optionalPeerDependencies": {
|
|
48
48
|
"react": ">=18.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@hpcc-js/esbuild-plugins": "^1.4.
|
|
51
|
+
"@hpcc-js/esbuild-plugins": "^1.4.1",
|
|
52
52
|
"@hpcc-js/wasm-graphviz": "1.6.1",
|
|
53
53
|
"@types/d3-transition": "1.3.6",
|
|
54
54
|
"@types/dagre": "0.7.52",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"url": "https://github.com/hpcc-systems/Visualization/issues"
|
|
74
74
|
},
|
|
75
75
|
"homepage": "https://github.com/hpcc-systems/Visualization",
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "521692e7cfd01c274d5cfff0c54e79d1686d3dd6"
|
|
77
77
|
}
|
package/src/common/graphT.ts
CHANGED
|
@@ -564,9 +564,6 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
564
564
|
moveEdgePlaceholder(ep: EdgePlaceholder<V, E>, transition: boolean): this {
|
|
565
565
|
const edgeLayout = {
|
|
566
566
|
...this._layoutAlgo.edgePath(ep as any, this.edgeArcDepth()),
|
|
567
|
-
markerStart: `url(#${this.id()}_circleFoot)`,
|
|
568
|
-
markerEnd: `url(#${this.id()}_arrowHead)`,
|
|
569
|
-
|
|
570
567
|
};
|
|
571
568
|
const context = this;
|
|
572
569
|
if (this._edgeRenderer && ep.element) {
|
|
@@ -877,57 +874,6 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
877
874
|
return this;
|
|
878
875
|
}
|
|
879
876
|
|
|
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
|
-
|
|
931
877
|
enter(domNode, element) {
|
|
932
878
|
super.enter(domNode, element);
|
|
933
879
|
|
|
@@ -936,7 +882,6 @@ export class GraphT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E e
|
|
|
936
882
|
this._centroidFilter = new SVGGlowFilter(this._svgDefs, this._id + "_glow");
|
|
937
883
|
this._svgDefsCat = this._svgDefs.append("g");
|
|
938
884
|
this._svgDefsAnn = this._svgDefs.append("g");
|
|
939
|
-
this.addMarkers();
|
|
940
885
|
this._subgraphG = this._renderElement.append("g");
|
|
941
886
|
this._edgeG = this._renderElement.append("g");
|
|
942
887
|
this._vertexG = this._renderElement.append("g");
|
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
|
|
7
6
|
export type Point = [number, number];
|
|
8
7
|
|
|
@@ -105,8 +104,8 @@ export class Layout implements ILayout {
|
|
|
105
104
|
edgeLine(ep: EdgePlaceholder): Line {
|
|
106
105
|
const sPos = { ...this._graph.projectPlacholder(ep.source), w: ep.source?.renderResult?.extent?.width ?? 0, h: ep.source?.renderResult?.extent?.height ?? 0 };
|
|
107
106
|
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 });
|
|
107
|
+
const sIntersect = ep.source.renderResult?.intersection ? ep.source.renderResult.intersection(sPos, { start: sPos, end: tPos }) : null;
|
|
108
|
+
const tIntersect = ep.target.renderResult?.intersection ? ep.target.renderResult.intersection(tPos, { start: sPos, end: tPos }) : null;
|
|
110
109
|
return {
|
|
111
110
|
source: {
|
|
112
111
|
x: sIntersect ? sIntersect.x : sPos.x,
|
|
@@ -33,8 +33,6 @@ export interface EdgeBaseProps<V extends VertexBaseProps = VertexBaseProps> exte
|
|
|
33
33
|
stroke?: string;
|
|
34
34
|
path?: string;
|
|
35
35
|
fontFamily?: string;
|
|
36
|
-
markerStart?: string;
|
|
37
|
-
markerEnd?: string;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
export interface HierarchyBase<SG extends SubgraphBaseProps, V extends VertexBaseProps> {
|
package/src/html/component.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { HTMLTemplateResult, SVGTemplateResult } from "lit-html";
|
|
2
|
+
import type { Pos, Segment, Extent } from "./intersection.ts";
|
|
2
3
|
|
|
3
4
|
export type TemplateResult = HTMLTemplateResult | SVGTemplateResult;
|
|
5
|
+
export type IntersectionFunc = (pos: Pos, line: Segment) => Pos | null;
|
|
4
6
|
export type TemplateResultEx = TemplateResult & {
|
|
5
|
-
extent?:
|
|
7
|
+
extent?: Extent;
|
|
8
|
+
intersection: IntersectionFunc;
|
|
6
9
|
};
|
|
7
|
-
export function extend(result: TemplateResult, width: number, height: number): TemplateResultEx {
|
|
10
|
+
export function extend(result: TemplateResult, width: number, height: number, intersection: IntersectionFunc = (pos: Pos, line: Segment) => null): TemplateResultEx {
|
|
8
11
|
return {
|
|
9
12
|
...result,
|
|
10
|
-
extent: { width, height }
|
|
13
|
+
extent: { width, height },
|
|
14
|
+
intersection
|
|
11
15
|
};
|
|
12
16
|
}
|
|
13
17
|
export type Component<T> = (props: T) => TemplateResult;
|
package/src/html/edge.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { svg } from "lit-html";
|
|
2
|
+
import type { SubgraphBaseProps, EdgeBaseProps, VertexBaseProps } from "../common/layouts/placeholders.ts";
|
|
3
|
+
import { GraphHtmlT } from "./graphHtmlT.ts";
|
|
4
|
+
|
|
5
|
+
export interface EdgeProps<V extends VertexBaseProps> extends EdgeBaseProps<V> {
|
|
6
|
+
graphInstance: GraphHtmlT<SubgraphBaseProps, V, EdgeProps<V>>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const edge = ({
|
|
10
|
+
graphInstance,
|
|
11
|
+
strokeWidth,
|
|
12
|
+
path
|
|
13
|
+
}: EdgeProps<VertexBaseProps>) => {
|
|
14
|
+
return svg`<path d="${path}" marker-start="url(#${graphInstance.id()}_source${graphInstance.sourceMarker()})" marker-end="url(#${graphInstance.id()}_target${graphInstance.targetMarker()})" style="stroke-width:${strokeWidth}px"></path>`;
|
|
15
|
+
};
|
package/src/html/graphHtml.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { GraphHtmlT, SubgraphBaseProps, EdgeBaseProps } from "./graphHtmlT.ts";
|
|
2
2
|
import { vertex, VertexProps } from "./vertex.ts";
|
|
3
|
+
import { edge, EdgeProps } from "./edge.ts";
|
|
4
|
+
import { Vertex } from "@hpcc-js/util";
|
|
3
5
|
|
|
4
|
-
export class GraphHtml extends GraphHtmlT<SubgraphBaseProps, VertexProps,
|
|
6
|
+
export class GraphHtml extends GraphHtmlT<SubgraphBaseProps, VertexProps, EdgeProps<VertexProps>> {
|
|
5
7
|
constructor() {
|
|
6
|
-
super(undefined, vertex);
|
|
8
|
+
super(undefined, vertex, edge);
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
}
|
package/src/html/graphHtmlT.ts
CHANGED
|
@@ -33,11 +33,9 @@ const defaultVertexRenderer = ({
|
|
|
33
33
|
|
|
34
34
|
const defaultEdgeRenderer = ({
|
|
35
35
|
strokeWidth,
|
|
36
|
-
path
|
|
37
|
-
markerStart,
|
|
38
|
-
markerEnd,
|
|
36
|
+
path
|
|
39
37
|
}: EdgeBaseProps<VertexBaseProps>) => {
|
|
40
|
-
return svg`<path d="${path}"
|
|
38
|
+
return svg`<path d="${path}" style="stroke-width:${strokeWidth}px"></path>`;
|
|
41
39
|
};
|
|
42
40
|
|
|
43
41
|
export class GraphHtmlT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E extends EdgeBaseProps<V>> extends GraphT<SG, V, E> {
|
|
@@ -45,5 +43,75 @@ export class GraphHtmlT<SG extends SubgraphBaseProps, V extends VertexBaseProps,
|
|
|
45
43
|
constructor(subgraphRenderer: Component<SG> = defaultSubgraphRenderer, vertexRenderer: Component<V> = defaultVertexRenderer, edgeRenderer: Component<E> = defaultEdgeRenderer) {
|
|
46
44
|
super(adapter(subgraphRenderer), adapter<V>(vertexRenderer), adapter(edgeRenderer));
|
|
47
45
|
}
|
|
46
|
+
|
|
47
|
+
enterMarkers(clearFirst: boolean = false) {
|
|
48
|
+
if (clearFirst) {
|
|
49
|
+
this._svgDefs.select("#" + this._id + "_sourceDot").remove();
|
|
50
|
+
this._svgDefs.select("#" + this._id + "_targetDot").remove();
|
|
51
|
+
this._svgDefs.select("#" + this._id + "_targetArrow").remove();
|
|
52
|
+
}
|
|
53
|
+
this._svgDefs.append("marker")
|
|
54
|
+
.attr("class", "marker")
|
|
55
|
+
.attr("id", this._id + "_sourceDot")
|
|
56
|
+
.attr("refX", 1)
|
|
57
|
+
.attr("refY", 3)
|
|
58
|
+
.attr("markerWidth", 6)
|
|
59
|
+
.attr("markerHeight", 6)
|
|
60
|
+
.attr("markerUnits", "strokeWidth")
|
|
61
|
+
.attr("orient", "auto")
|
|
62
|
+
.append("circle")
|
|
63
|
+
.attr("cx", 3)
|
|
64
|
+
.attr("cy", 3)
|
|
65
|
+
.attr("r", 1.5)
|
|
66
|
+
.attr("fill", "context-stroke")
|
|
67
|
+
.attr("stroke", "context-stroke")
|
|
68
|
+
;
|
|
69
|
+
this._svgDefs.append("marker")
|
|
70
|
+
.attr("class", "marker")
|
|
71
|
+
.attr("id", this._id + "_targetDot")
|
|
72
|
+
.attr("refX", 5)
|
|
73
|
+
.attr("refY", 3)
|
|
74
|
+
.attr("markerWidth", 6)
|
|
75
|
+
.attr("markerHeight", 6)
|
|
76
|
+
.attr("markerUnits", "strokeWidth")
|
|
77
|
+
.attr("orient", "auto")
|
|
78
|
+
.append("circle")
|
|
79
|
+
.attr("cx", 3)
|
|
80
|
+
.attr("cy", 3)
|
|
81
|
+
.attr("r", 1.5)
|
|
82
|
+
.attr("fill", "context-stroke")
|
|
83
|
+
.attr("stroke", "context-stroke")
|
|
84
|
+
;
|
|
85
|
+
this._svgDefs.append("marker")
|
|
86
|
+
.attr("class", "marker")
|
|
87
|
+
.attr("id", this._id + "_targetArrow")
|
|
88
|
+
.attr("viewBox", "0 0 10 10")
|
|
89
|
+
.attr("refX", 10)
|
|
90
|
+
.attr("refY", 5)
|
|
91
|
+
.attr("markerWidth", 5)
|
|
92
|
+
.attr("markerHeight", 5)
|
|
93
|
+
.attr("markerUnits", "strokeWidth")
|
|
94
|
+
.attr("orient", "auto")
|
|
95
|
+
.append("polyline")
|
|
96
|
+
.attr("points", "0,0 10,5 0,10 0,5")
|
|
97
|
+
.attr("fill", "context-stroke")
|
|
98
|
+
.attr("stroke", "context-stroke")
|
|
99
|
+
;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
enter(domNode, element) {
|
|
103
|
+
super.enter(domNode, element);
|
|
104
|
+
this.enterMarkers();
|
|
105
|
+
}
|
|
48
106
|
}
|
|
49
107
|
GraphHtmlT.prototype._class += " graph_GraphHtmlT";
|
|
108
|
+
|
|
109
|
+
export interface GraphHtmlT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E extends EdgeBaseProps<V>> extends GraphT<SG, V, E> {
|
|
110
|
+
sourceMarker(): "Dot" | "None";
|
|
111
|
+
sourceMarker(_: "Dot" | "None"): this;
|
|
112
|
+
targetMarker(): "Arrow" | "Dot" | "None";
|
|
113
|
+
targetMarker(_: "Arrow" | "Dot" | "None"): this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
GraphHtmlT.prototype.publish("sourceMarker", "Dot", "set", "Target Marker", ["Dot", "None"]);
|
|
117
|
+
GraphHtmlT.prototype.publish("targetMarker", "Arrow", "set", "Target Marker", ["Arrow", "Dot", "None"]);
|
package/src/html/icon.ts
CHANGED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export interface Pos {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface Extent {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Segment {
|
|
12
|
+
start: Pos;
|
|
13
|
+
end: Pos;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Rectangle {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function segmentSegment(s1: Segment, s2: Segment): Pos | undefined {
|
|
24
|
+
const { x: x1, y: y1 } = s1.start;
|
|
25
|
+
const { x: x2, y: y2 } = s1.end;
|
|
26
|
+
const { x: x3, y: y3 } = s2.start;
|
|
27
|
+
const { x: x4, y: y4 } = s2.end;
|
|
28
|
+
|
|
29
|
+
const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
|
30
|
+
if (denom === 0) {
|
|
31
|
+
// Parallel lines ---
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
|
|
36
|
+
const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
|
|
37
|
+
|
|
38
|
+
if (t > 0 && t < 1 && u > 0 && u < 1) {
|
|
39
|
+
return {
|
|
40
|
+
x: x1 + t * (x2 - x1),
|
|
41
|
+
y: y1 + t * (y2 - y1)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function rectEdges(rect: Rectangle): Segment[] {
|
|
49
|
+
const r = {
|
|
50
|
+
topLeft: { x: rect.x - rect.width / 2, y: rect.y - rect.height / 2 },
|
|
51
|
+
topRight: { x: rect.x + rect.width / 2, y: rect.y - rect.height / 2 },
|
|
52
|
+
bottomRight: { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 },
|
|
53
|
+
bottomLeft: { x: rect.x - rect.width / 2, y: rect.y + rect.height / 2 }
|
|
54
|
+
};
|
|
55
|
+
return [
|
|
56
|
+
{ start: r.bottomLeft, end: r.topLeft },
|
|
57
|
+
{ start: r.topLeft, end: r.topRight },
|
|
58
|
+
{ start: r.topRight, end: r.bottomRight },
|
|
59
|
+
{ start: r.bottomRight, end: r.bottomLeft },
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function rectangleSegment(rect: Rectangle, line: Segment): Pos | undefined {
|
|
64
|
+
for (const edge of rectEdges(rect)) {
|
|
65
|
+
const intersectionPoint = segmentSegment(edge, line);
|
|
66
|
+
if (intersectionPoint) {
|
|
67
|
+
return intersectionPoint;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function sortSegment(pos: Pos, line: Segment): Segment {
|
|
74
|
+
const distStart = Math.hypot(line.start.x - pos.x, line.start.y - pos.y);
|
|
75
|
+
const distEnd = Math.hypot(line.end.x - pos.x, line.end.y - pos.y);
|
|
76
|
+
|
|
77
|
+
if (distStart <= distEnd) {
|
|
78
|
+
return line;
|
|
79
|
+
} else {
|
|
80
|
+
return { start: line.end, end: line.start };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function circleSegment(pos: Pos, r: number, line: Segment): Pos | undefined {
|
|
85
|
+
line = sortSegment(pos, line);
|
|
86
|
+
const { x: x1, y: y1 } = line.start;
|
|
87
|
+
const { x: x2, y: y2 } = line.end;
|
|
88
|
+
|
|
89
|
+
const dx = x2 - x1;
|
|
90
|
+
const dy = y2 - y1;
|
|
91
|
+
|
|
92
|
+
const a = dx * dx + dy * dy;
|
|
93
|
+
const b = 2 * (dx * (x1 - pos.x) + dy * (y1 - pos.y));
|
|
94
|
+
const c = (x1 - pos.x) * (x1 - pos.x) + (y1 - pos.y) * (y1 - pos.y) - r * r;
|
|
95
|
+
|
|
96
|
+
const discriminant = b * b - 4 * a * c;
|
|
97
|
+
|
|
98
|
+
if (discriminant < 0) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const t1 = (-b + Math.sqrt(discriminant)) / (2 * a);
|
|
103
|
+
|
|
104
|
+
if (t1 >= 0 && t1 <= 1) {
|
|
105
|
+
return {
|
|
106
|
+
x: x1 + t1 * dx,
|
|
107
|
+
y: y1 + t1 * dy
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
package/src/html/shape.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { svg } from "lit-html";
|
|
2
2
|
import { extend } from "./component.ts";
|
|
3
|
+
import { circleSegment, rectangleSegment } from "./intersection.ts";
|
|
3
4
|
|
|
4
5
|
export const DEFAULT_SHAPE_SIZE = 32;
|
|
5
6
|
|
|
@@ -27,7 +28,9 @@ export const circle = ({
|
|
|
27
28
|
stroke=${stroke}
|
|
28
29
|
stroke-width=${strokeWidth}
|
|
29
30
|
shape-rendering=${shapeRendering}
|
|
30
|
-
/>`, diameter, diameter)
|
|
31
|
+
/>`, diameter, diameter, (pos, line) => {
|
|
32
|
+
return circleSegment(pos, diameter / 2, line);
|
|
33
|
+
});
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
export interface RectangleProps extends BaseProps {
|
|
@@ -57,7 +60,9 @@ export const rectangle = ({
|
|
|
57
60
|
stroke=${stroke}
|
|
58
61
|
stroke-width=${strokeWidth}
|
|
59
62
|
shape-rendering=${shapeRendering}
|
|
60
|
-
/>`, width, height)
|
|
63
|
+
/>`, width, height, (pos, line) => {
|
|
64
|
+
return rectangleSegment({ x: pos.x, y: pos.y, width, height }, line);
|
|
65
|
+
});
|
|
61
66
|
};
|
|
62
67
|
|
|
63
68
|
export interface SquareProps extends BaseProps {
|
package/src/html/textBox.ts
CHANGED
package/src/html/vertex.ts
CHANGED
|
@@ -18,7 +18,6 @@ export interface VertexProps extends VertexBaseProps {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export const vertex: Component<VertexProps> = ({
|
|
21
|
-
id,
|
|
22
21
|
text,
|
|
23
22
|
textBox,
|
|
24
23
|
textBoxAnnotationsE = [],
|
|
@@ -61,5 +60,8 @@ ${textBoxTpl}
|
|
|
61
60
|
<g transform="translate(${iconAnnotationsTpl.extent.width / 2 + xIconAnnotationOffset} ${yIconOffset - yIconAnnotationOffset})">
|
|
62
61
|
${iconAnnotationsTpl}
|
|
63
62
|
</g>
|
|
64
|
-
`, textBoxTpl.extent.width, textBoxTpl.extent.height)
|
|
63
|
+
`, textBoxTpl.extent.width, textBoxTpl.extent.height, (pos, line) => {
|
|
64
|
+
return iconTpl.intersection({ x: pos.x, y: yIconOffset + pos.y }, line) ??
|
|
65
|
+
textBoxTpl.intersection({ x: pos.x, y: pos.y }, line);
|
|
66
|
+
});
|
|
65
67
|
};
|
package/types/common/graphT.d.ts
CHANGED
|
@@ -112,7 +112,6 @@ export declare class GraphT<SG extends SubgraphBaseProps, V extends VertexBasePr
|
|
|
112
112
|
subgraphRenderer(): RendererT<SG>;
|
|
113
113
|
subgraphRenderer(_: RendererT<SG>): this;
|
|
114
114
|
updateSubgraphs(): this;
|
|
115
|
-
addMarkers(clearFirst?: boolean): void;
|
|
116
115
|
enter(domNode: any, element: any): void;
|
|
117
116
|
protected forceDirectedOptions(): FDOptions;
|
|
118
117
|
private layoutOptions;
|
|
@@ -28,8 +28,6 @@ export interface EdgeBaseProps<V extends VertexBaseProps = VertexBaseProps> exte
|
|
|
28
28
|
stroke?: string;
|
|
29
29
|
path?: string;
|
|
30
30
|
fontFamily?: string;
|
|
31
|
-
markerStart?: string;
|
|
32
|
-
markerEnd?: string;
|
|
33
31
|
}
|
|
34
32
|
export interface HierarchyBase<SG extends SubgraphBaseProps, V extends VertexBaseProps> {
|
|
35
33
|
id: string | number;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { HTMLTemplateResult, SVGTemplateResult } from "lit-html";
|
|
2
|
+
import type { Pos, Segment, Extent } from "./intersection.ts";
|
|
2
3
|
export type TemplateResult = HTMLTemplateResult | SVGTemplateResult;
|
|
4
|
+
export type IntersectionFunc = (pos: Pos, line: Segment) => Pos | null;
|
|
3
5
|
export type TemplateResultEx = TemplateResult & {
|
|
4
|
-
extent?:
|
|
5
|
-
|
|
6
|
-
height: number;
|
|
7
|
-
};
|
|
6
|
+
extent?: Extent;
|
|
7
|
+
intersection: IntersectionFunc;
|
|
8
8
|
};
|
|
9
|
-
export declare function extend(result: TemplateResult, width: number, height: number): TemplateResultEx;
|
|
9
|
+
export declare function extend(result: TemplateResult, width: number, height: number, intersection?: IntersectionFunc): TemplateResultEx;
|
|
10
10
|
export type Component<T> = (props: T) => TemplateResult;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SubgraphBaseProps, EdgeBaseProps, VertexBaseProps } from "../common/layouts/placeholders.ts";
|
|
2
|
+
import { GraphHtmlT } from "./graphHtmlT.ts";
|
|
3
|
+
export interface EdgeProps<V extends VertexBaseProps> extends EdgeBaseProps<V> {
|
|
4
|
+
graphInstance: GraphHtmlT<SubgraphBaseProps, V, EdgeProps<V>>;
|
|
5
|
+
}
|
|
6
|
+
export declare const edge: ({ graphInstance, strokeWidth, path }: EdgeProps<VertexBaseProps>) => import("lit-html").TemplateResult<2>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { GraphHtmlT, SubgraphBaseProps
|
|
1
|
+
import { GraphHtmlT, SubgraphBaseProps } from "./graphHtmlT.ts";
|
|
2
2
|
import { VertexProps } from "./vertex.ts";
|
|
3
|
-
|
|
3
|
+
import { EdgeProps } from "./edge.ts";
|
|
4
|
+
export declare class GraphHtml extends GraphHtmlT<SubgraphBaseProps, VertexProps, EdgeProps<VertexProps>> {
|
|
4
5
|
constructor();
|
|
5
6
|
}
|
|
@@ -6,4 +6,12 @@ export { html, svg, EdgeBaseProps, SubgraphBaseProps, VertexBaseProps };
|
|
|
6
6
|
export declare function adapter<T extends BaseProps>(component: Component<T>): RendererT<T>;
|
|
7
7
|
export declare class GraphHtmlT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E extends EdgeBaseProps<V>> extends GraphT<SG, V, E> {
|
|
8
8
|
constructor(subgraphRenderer?: Component<SG>, vertexRenderer?: Component<V>, edgeRenderer?: Component<E>);
|
|
9
|
+
enterMarkers(clearFirst?: boolean): void;
|
|
10
|
+
enter(domNode: any, element: any): void;
|
|
11
|
+
}
|
|
12
|
+
export interface GraphHtmlT<SG extends SubgraphBaseProps, V extends VertexBaseProps, E extends EdgeBaseProps<V>> extends GraphT<SG, V, E> {
|
|
13
|
+
sourceMarker(): "Dot" | "None";
|
|
14
|
+
sourceMarker(_: "Dot" | "None"): this;
|
|
15
|
+
targetMarker(): "Arrow" | "Dot" | "None";
|
|
16
|
+
targetMarker(_: "Arrow" | "Dot" | "None"): this;
|
|
9
17
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface Pos {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
export interface Extent {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
export interface Segment {
|
|
10
|
+
start: Pos;
|
|
11
|
+
end: Pos;
|
|
12
|
+
}
|
|
13
|
+
export interface Rectangle {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function rectangleSegment(rect: Rectangle, line: Segment): Pos | undefined;
|
|
20
|
+
export declare function circleSegment(pos: Pos, r: number, line: Segment): Pos | undefined;
|
|
@@ -1,67 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface Pos {
|
|
2
|
-
x: number;
|
|
3
|
-
y: number;
|
|
4
|
-
}
|
|
5
|
-
export interface Segment {
|
|
6
|
-
start: Pos;
|
|
7
|
-
end: Pos;
|
|
8
|
-
}
|
|
9
|
-
export interface Rectangle {
|
|
10
|
-
topLeft: Pos;
|
|
11
|
-
topRight: Pos;
|
|
12
|
-
bottomLeft: Pos;
|
|
13
|
-
bottomRight: Pos;
|
|
14
|
-
}
|
|
15
|
-
export interface Rectangle2 {
|
|
16
|
-
x: number;
|
|
17
|
-
y: number;
|
|
18
|
-
w: number;
|
|
19
|
-
h: number;
|
|
20
|
-
}
|
|
21
|
-
export declare function intersection(rect: Rectangle2, line: Segment): {
|
|
22
|
-
x: number;
|
|
23
|
-
y: number;
|
|
24
|
-
};
|