@hpcc-js/graph 3.6.5 → 3.6.6
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-DQ0E8zfY.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 +6 -6
- package/src/AdjacencyGraph.ts +224 -224
- package/src/Edge.css +23 -23
- 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 +46 -46
- package/src/Sankey.ts +304 -304
- package/src/Subgraph.css +10 -10
- package/src/Subgraph.ts +165 -165
- package/src/Vertex.css +3 -3
- 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 +45 -45
- 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
package/src/html/imageChar.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Utility } from "@hpcc-js/common";
|
|
2
|
-
import { TextLine, TextProps } from "./text.ts";
|
|
3
|
-
|
|
4
|
-
export const ImageChar = ({
|
|
5
|
-
text = "",
|
|
6
|
-
fill,
|
|
7
|
-
fontFamily = "FontAwesome",
|
|
8
|
-
fontSize = 12
|
|
9
|
-
}: TextProps) => {
|
|
10
|
-
const renderChar = fontFamily === "FontAwesome" ? Utility.faChar(text) : text;
|
|
11
|
-
return TextLine({
|
|
12
|
-
text: renderChar,
|
|
13
|
-
fill,
|
|
14
|
-
fontFamily,
|
|
15
|
-
fontSize,
|
|
16
|
-
dominantBaseline: fontFamily === "FontAwesome" ? "ideographic" : undefined
|
|
17
|
-
});
|
|
18
|
-
};
|
|
1
|
+
import { Utility } from "@hpcc-js/common";
|
|
2
|
+
import { TextLine, TextProps } from "./text.ts";
|
|
3
|
+
|
|
4
|
+
export const ImageChar = ({
|
|
5
|
+
text = "",
|
|
6
|
+
fill,
|
|
7
|
+
fontFamily = "FontAwesome",
|
|
8
|
+
fontSize = 12
|
|
9
|
+
}: TextProps) => {
|
|
10
|
+
const renderChar = fontFamily === "FontAwesome" ? Utility.faChar(text) : text;
|
|
11
|
+
return TextLine({
|
|
12
|
+
text: renderChar,
|
|
13
|
+
fill,
|
|
14
|
+
fontFamily,
|
|
15
|
+
fontSize,
|
|
16
|
+
dominantBaseline: fontFamily === "FontAwesome" ? "ideographic" : undefined
|
|
17
|
+
});
|
|
18
|
+
};
|
package/src/html/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from "./annotation.ts";
|
|
2
|
-
export * from "./graphHtml.ts";
|
|
3
|
-
export * from "./icon.ts";
|
|
4
|
-
export * from "./image.ts";
|
|
5
|
-
export * from "./imageChar.ts";
|
|
6
|
-
export * from "./shape.ts";
|
|
7
|
-
export * from "./text.ts";
|
|
8
|
-
export * from "./vertex.ts";
|
|
1
|
+
export * from "./annotation.ts";
|
|
2
|
+
export * from "./graphHtml.ts";
|
|
3
|
+
export * from "./icon.ts";
|
|
4
|
+
export * from "./image.ts";
|
|
5
|
+
export * from "./imageChar.ts";
|
|
6
|
+
export * from "./shape.ts";
|
|
7
|
+
export * from "./text.ts";
|
|
8
|
+
export * from "./vertex.ts";
|
package/src/html/intersection.ts
CHANGED
|
@@ -1,110 +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
|
-
}
|
|
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,141 +1,141 @@
|
|
|
1
|
-
import { svg } from "lit-html";
|
|
2
|
-
import { extend } from "./component.ts";
|
|
3
|
-
import { circleSegment, rectangleSegment } from "./intersection.ts";
|
|
4
|
-
|
|
5
|
-
export const DEFAULT_SHAPE_SIZE = 32;
|
|
6
|
-
|
|
7
|
-
interface BaseProps {
|
|
8
|
-
fill?: string;
|
|
9
|
-
stroke?: string;
|
|
10
|
-
strokeWidth?: number;
|
|
11
|
-
shapeRendering?: "auto" | "optimizeSpeed" | "crispEdges" | "geometricPrecision";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface CircleProps extends BaseProps {
|
|
15
|
-
diameter?: number;
|
|
16
|
-
}
|
|
17
|
-
export const circle = ({
|
|
18
|
-
diameter = DEFAULT_SHAPE_SIZE,
|
|
19
|
-
fill = "whiteSmoke",
|
|
20
|
-
stroke = fill,
|
|
21
|
-
strokeWidth = 1,
|
|
22
|
-
shapeRendering = "auto"
|
|
23
|
-
}: CircleProps) => {
|
|
24
|
-
return extend(svg`\
|
|
25
|
-
<circle
|
|
26
|
-
r=${diameter / 2}
|
|
27
|
-
fill=${fill}
|
|
28
|
-
stroke=${stroke}
|
|
29
|
-
stroke-width=${strokeWidth}
|
|
30
|
-
shape-rendering=${shapeRendering}
|
|
31
|
-
/>`, diameter, diameter, (pos, line) => {
|
|
32
|
-
return circleSegment(pos, diameter / 2, line);
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export interface RectangleProps extends BaseProps {
|
|
37
|
-
width: number;
|
|
38
|
-
height: number;
|
|
39
|
-
cornerRadius?: number;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const rectangle = ({
|
|
43
|
-
width = DEFAULT_SHAPE_SIZE,
|
|
44
|
-
height = DEFAULT_SHAPE_SIZE,
|
|
45
|
-
cornerRadius = 4,
|
|
46
|
-
fill = "whiteSmoke",
|
|
47
|
-
stroke = fill,
|
|
48
|
-
strokeWidth = 1,
|
|
49
|
-
shapeRendering = "crispEdges"
|
|
50
|
-
}: RectangleProps) => {
|
|
51
|
-
return extend(svg`\
|
|
52
|
-
<rect
|
|
53
|
-
x=${-width / 2}
|
|
54
|
-
y=${-height / 2}
|
|
55
|
-
rx=${cornerRadius}
|
|
56
|
-
ry=${cornerRadius}
|
|
57
|
-
width=${width}
|
|
58
|
-
height=${height}
|
|
59
|
-
fill=${fill}
|
|
60
|
-
stroke=${stroke}
|
|
61
|
-
stroke-width=${strokeWidth}
|
|
62
|
-
shape-rendering=${shapeRendering}
|
|
63
|
-
/>`, width, height, (pos, line) => {
|
|
64
|
-
return rectangleSegment({ x: pos.x, y: pos.y, width, height }, line);
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export interface SquareProps extends BaseProps {
|
|
69
|
-
width?: number;
|
|
70
|
-
cornerRadius?: number;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export const square = ({
|
|
74
|
-
width = DEFAULT_SHAPE_SIZE,
|
|
75
|
-
cornerRadius,
|
|
76
|
-
fill,
|
|
77
|
-
stroke,
|
|
78
|
-
strokeWidth,
|
|
79
|
-
shapeRendering
|
|
80
|
-
}: SquareProps) => {
|
|
81
|
-
return rectangle({
|
|
82
|
-
width,
|
|
83
|
-
height: width,
|
|
84
|
-
cornerRadius,
|
|
85
|
-
fill,
|
|
86
|
-
stroke,
|
|
87
|
-
strokeWidth,
|
|
88
|
-
shapeRendering
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export interface ShapeProps extends BaseProps {
|
|
93
|
-
shape?: "circle" | "square" | "rectangle";
|
|
94
|
-
diameter?: number;
|
|
95
|
-
width?: number;
|
|
96
|
-
height?: number;
|
|
97
|
-
cornerRadius?: number;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const shape = ({
|
|
101
|
-
shape = "circle",
|
|
102
|
-
diameter,
|
|
103
|
-
width,
|
|
104
|
-
height,
|
|
105
|
-
fill,
|
|
106
|
-
stroke,
|
|
107
|
-
strokeWidth = 1,
|
|
108
|
-
shapeRendering = "auto",
|
|
109
|
-
cornerRadius
|
|
110
|
-
}: ShapeProps) => {
|
|
111
|
-
switch (shape) {
|
|
112
|
-
case "square":
|
|
113
|
-
return square({
|
|
114
|
-
width: width ?? height ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
115
|
-
fill,
|
|
116
|
-
stroke,
|
|
117
|
-
strokeWidth,
|
|
118
|
-
shapeRendering,
|
|
119
|
-
cornerRadius
|
|
120
|
-
});
|
|
121
|
-
case "rectangle":
|
|
122
|
-
return rectangle({
|
|
123
|
-
width: width ?? height ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
124
|
-
height: height ?? width ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
125
|
-
fill,
|
|
126
|
-
stroke,
|
|
127
|
-
strokeWidth,
|
|
128
|
-
shapeRendering,
|
|
129
|
-
cornerRadius
|
|
130
|
-
});
|
|
131
|
-
case "circle":
|
|
132
|
-
default:
|
|
133
|
-
return circle({
|
|
134
|
-
diameter: diameter ?? width ?? height ?? DEFAULT_SHAPE_SIZE,
|
|
135
|
-
fill,
|
|
136
|
-
stroke,
|
|
137
|
-
strokeWidth,
|
|
138
|
-
shapeRendering
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
};
|
|
1
|
+
import { svg } from "lit-html";
|
|
2
|
+
import { extend } from "./component.ts";
|
|
3
|
+
import { circleSegment, rectangleSegment } from "./intersection.ts";
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_SHAPE_SIZE = 32;
|
|
6
|
+
|
|
7
|
+
interface BaseProps {
|
|
8
|
+
fill?: string;
|
|
9
|
+
stroke?: string;
|
|
10
|
+
strokeWidth?: number;
|
|
11
|
+
shapeRendering?: "auto" | "optimizeSpeed" | "crispEdges" | "geometricPrecision";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CircleProps extends BaseProps {
|
|
15
|
+
diameter?: number;
|
|
16
|
+
}
|
|
17
|
+
export const circle = ({
|
|
18
|
+
diameter = DEFAULT_SHAPE_SIZE,
|
|
19
|
+
fill = "whiteSmoke",
|
|
20
|
+
stroke = fill,
|
|
21
|
+
strokeWidth = 1,
|
|
22
|
+
shapeRendering = "auto"
|
|
23
|
+
}: CircleProps) => {
|
|
24
|
+
return extend(svg`\
|
|
25
|
+
<circle
|
|
26
|
+
r=${diameter / 2}
|
|
27
|
+
fill=${fill}
|
|
28
|
+
stroke=${stroke}
|
|
29
|
+
stroke-width=${strokeWidth}
|
|
30
|
+
shape-rendering=${shapeRendering}
|
|
31
|
+
/>`, diameter, diameter, (pos, line) => {
|
|
32
|
+
return circleSegment(pos, diameter / 2, line);
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export interface RectangleProps extends BaseProps {
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
cornerRadius?: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const rectangle = ({
|
|
43
|
+
width = DEFAULT_SHAPE_SIZE,
|
|
44
|
+
height = DEFAULT_SHAPE_SIZE,
|
|
45
|
+
cornerRadius = 4,
|
|
46
|
+
fill = "whiteSmoke",
|
|
47
|
+
stroke = fill,
|
|
48
|
+
strokeWidth = 1,
|
|
49
|
+
shapeRendering = "crispEdges"
|
|
50
|
+
}: RectangleProps) => {
|
|
51
|
+
return extend(svg`\
|
|
52
|
+
<rect
|
|
53
|
+
x=${-width / 2}
|
|
54
|
+
y=${-height / 2}
|
|
55
|
+
rx=${cornerRadius}
|
|
56
|
+
ry=${cornerRadius}
|
|
57
|
+
width=${width}
|
|
58
|
+
height=${height}
|
|
59
|
+
fill=${fill}
|
|
60
|
+
stroke=${stroke}
|
|
61
|
+
stroke-width=${strokeWidth}
|
|
62
|
+
shape-rendering=${shapeRendering}
|
|
63
|
+
/>`, width, height, (pos, line) => {
|
|
64
|
+
return rectangleSegment({ x: pos.x, y: pos.y, width, height }, line);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export interface SquareProps extends BaseProps {
|
|
69
|
+
width?: number;
|
|
70
|
+
cornerRadius?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const square = ({
|
|
74
|
+
width = DEFAULT_SHAPE_SIZE,
|
|
75
|
+
cornerRadius,
|
|
76
|
+
fill,
|
|
77
|
+
stroke,
|
|
78
|
+
strokeWidth,
|
|
79
|
+
shapeRendering
|
|
80
|
+
}: SquareProps) => {
|
|
81
|
+
return rectangle({
|
|
82
|
+
width,
|
|
83
|
+
height: width,
|
|
84
|
+
cornerRadius,
|
|
85
|
+
fill,
|
|
86
|
+
stroke,
|
|
87
|
+
strokeWidth,
|
|
88
|
+
shapeRendering
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export interface ShapeProps extends BaseProps {
|
|
93
|
+
shape?: "circle" | "square" | "rectangle";
|
|
94
|
+
diameter?: number;
|
|
95
|
+
width?: number;
|
|
96
|
+
height?: number;
|
|
97
|
+
cornerRadius?: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const shape = ({
|
|
101
|
+
shape = "circle",
|
|
102
|
+
diameter,
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
fill,
|
|
106
|
+
stroke,
|
|
107
|
+
strokeWidth = 1,
|
|
108
|
+
shapeRendering = "auto",
|
|
109
|
+
cornerRadius
|
|
110
|
+
}: ShapeProps) => {
|
|
111
|
+
switch (shape) {
|
|
112
|
+
case "square":
|
|
113
|
+
return square({
|
|
114
|
+
width: width ?? height ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
115
|
+
fill,
|
|
116
|
+
stroke,
|
|
117
|
+
strokeWidth,
|
|
118
|
+
shapeRendering,
|
|
119
|
+
cornerRadius
|
|
120
|
+
});
|
|
121
|
+
case "rectangle":
|
|
122
|
+
return rectangle({
|
|
123
|
+
width: width ?? height ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
124
|
+
height: height ?? width ?? diameter ?? DEFAULT_SHAPE_SIZE,
|
|
125
|
+
fill,
|
|
126
|
+
stroke,
|
|
127
|
+
strokeWidth,
|
|
128
|
+
shapeRendering,
|
|
129
|
+
cornerRadius
|
|
130
|
+
});
|
|
131
|
+
case "circle":
|
|
132
|
+
default:
|
|
133
|
+
return circle({
|
|
134
|
+
diameter: diameter ?? width ?? height ?? DEFAULT_SHAPE_SIZE,
|
|
135
|
+
fill,
|
|
136
|
+
stroke,
|
|
137
|
+
strokeWidth,
|
|
138
|
+
shapeRendering
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
package/src/html/text.ts
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import { svg } from "lit-html";
|
|
2
|
-
import { Utility } from "@hpcc-js/common";
|
|
3
|
-
import { extend } from "./component.ts";
|
|
4
|
-
|
|
5
|
-
export interface TextProps {
|
|
6
|
-
text: string;
|
|
7
|
-
anchor?: "left" | "middle" | "end";
|
|
8
|
-
fill?: string;
|
|
9
|
-
fontFamily?: string;
|
|
10
|
-
fontSize?: number;
|
|
11
|
-
dominantBaseline?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const TextLine = ({
|
|
15
|
-
text,
|
|
16
|
-
anchor = "middle",
|
|
17
|
-
fill = "black",
|
|
18
|
-
fontFamily = "Verdana",
|
|
19
|
-
fontSize = 12,
|
|
20
|
-
dominantBaseline = "middle",
|
|
21
|
-
}: TextProps) => {
|
|
22
|
-
const { width, height } = Utility.textSize(text, fontFamily, fontSize);
|
|
23
|
-
return extend(svg`\
|
|
24
|
-
<text y=${height / 2} font-family=${fontFamily} font-size=${`${fontSize}px`} text-anchor=${anchor} fill=${fill} dominant-baseline=${dominantBaseline}>
|
|
25
|
-
${text}
|
|
26
|
-
</text>`, width, height);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const Text = ({
|
|
30
|
-
text,
|
|
31
|
-
anchor = "middle",
|
|
32
|
-
fill = "black",
|
|
33
|
-
fontFamily = "Verdana",
|
|
34
|
-
fontSize = 12,
|
|
35
|
-
}: TextProps) => {
|
|
36
|
-
const parts = text.split("\n").map(line => TextLine({ text: line, anchor, fill, fontFamily, fontSize }));
|
|
37
|
-
const { width, height } = parts.reduce((acc, part) => {
|
|
38
|
-
return {
|
|
39
|
-
width: Math.max(acc.width, part.extent.width),
|
|
40
|
-
height: acc.height + part.extent.height
|
|
41
|
-
};
|
|
42
|
-
}, { width: 0, height: 0 });
|
|
43
|
-
|
|
44
|
-
let xOffset = 0;
|
|
45
|
-
if (anchor === "left") {
|
|
46
|
-
xOffset = -width / 2;
|
|
47
|
-
} else if (anchor === "end") {
|
|
48
|
-
xOffset = width / 2;
|
|
49
|
-
}
|
|
50
|
-
const lineHeight = height / parts.length;
|
|
51
|
-
const TextLines = parts.map((p, i) => {
|
|
52
|
-
return svg`\
|
|
53
|
-
<g key=${`key-${i}`} transform="translate(${xOffset} ${-height / 2 + i * lineHeight})">
|
|
54
|
-
${p}
|
|
55
|
-
</g>`;
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return extend(svg`${TextLines}`, width, height);
|
|
59
|
-
};
|
|
1
|
+
import { svg } from "lit-html";
|
|
2
|
+
import { Utility } from "@hpcc-js/common";
|
|
3
|
+
import { extend } from "./component.ts";
|
|
4
|
+
|
|
5
|
+
export interface TextProps {
|
|
6
|
+
text: string;
|
|
7
|
+
anchor?: "left" | "middle" | "end";
|
|
8
|
+
fill?: string;
|
|
9
|
+
fontFamily?: string;
|
|
10
|
+
fontSize?: number;
|
|
11
|
+
dominantBaseline?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const TextLine = ({
|
|
15
|
+
text,
|
|
16
|
+
anchor = "middle",
|
|
17
|
+
fill = "black",
|
|
18
|
+
fontFamily = "Verdana",
|
|
19
|
+
fontSize = 12,
|
|
20
|
+
dominantBaseline = "middle",
|
|
21
|
+
}: TextProps) => {
|
|
22
|
+
const { width, height } = Utility.textSize(text, fontFamily, fontSize);
|
|
23
|
+
return extend(svg`\
|
|
24
|
+
<text y=${height / 2} font-family=${fontFamily} font-size=${`${fontSize}px`} text-anchor=${anchor} fill=${fill} dominant-baseline=${dominantBaseline}>
|
|
25
|
+
${text}
|
|
26
|
+
</text>`, width, height);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Text = ({
|
|
30
|
+
text,
|
|
31
|
+
anchor = "middle",
|
|
32
|
+
fill = "black",
|
|
33
|
+
fontFamily = "Verdana",
|
|
34
|
+
fontSize = 12,
|
|
35
|
+
}: TextProps) => {
|
|
36
|
+
const parts = text.split("\n").map(line => TextLine({ text: line, anchor, fill, fontFamily, fontSize }));
|
|
37
|
+
const { width, height } = parts.reduce((acc, part) => {
|
|
38
|
+
return {
|
|
39
|
+
width: Math.max(acc.width, part.extent.width),
|
|
40
|
+
height: acc.height + part.extent.height
|
|
41
|
+
};
|
|
42
|
+
}, { width: 0, height: 0 });
|
|
43
|
+
|
|
44
|
+
let xOffset = 0;
|
|
45
|
+
if (anchor === "left") {
|
|
46
|
+
xOffset = -width / 2;
|
|
47
|
+
} else if (anchor === "end") {
|
|
48
|
+
xOffset = width / 2;
|
|
49
|
+
}
|
|
50
|
+
const lineHeight = height / parts.length;
|
|
51
|
+
const TextLines = parts.map((p, i) => {
|
|
52
|
+
return svg`\
|
|
53
|
+
<g key=${`key-${i}`} transform="translate(${xOffset} ${-height / 2 + i * lineHeight})">
|
|
54
|
+
${p}
|
|
55
|
+
</g>`;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return extend(svg`${TextLines}`, width, height);
|
|
59
|
+
};
|