Skip to content

Commit 6f3f585

Browse files
committed
yeeeeaaaa.... nah
1 parent 20ca1ea commit 6f3f585

1 file changed

Lines changed: 100 additions & 8 deletions

File tree

src/graph-view.tsx

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ type Node = {
2121
vx: number;
2222
vy: number;
2323
className: string | null;
24+
longestLinkLength: number;
2425
};
2526

2627
type Link = {
2728
source: string;
2829
target: string;
2930
data: N3.Quad;
31+
name: string;
3032
};
3133

3234
type GraphRef = ForceGraphMethods<
@@ -60,7 +62,8 @@ function mkNode(data: N3.Quad_Object, prefixes: Record<string, string>): Node {
6062
data,
6163
vx: Math.random() * 2.0 - 1.0,
6264
vy: Math.random() * 2.0 - 1.0,
63-
className: null
65+
className: null,
66+
longestLinkLength: 0
6467
};
6568
}
6669

@@ -113,6 +116,84 @@ function pointerAreaPaint(
113116
ctx.fillRect(n.x! - width * 0.5, n.y! - height * 0.5, width, height);
114117
}
115118

119+
export function boxCollision(
120+
w: number,
121+
h: number,
122+
dx: number,
123+
dy: number
124+
): number {
125+
const ax = Math.abs(dx);
126+
const ay = Math.abs(dy);
127+
128+
return Math.min((w * 0.5) / ax, (h * 0.5) / ay);
129+
}
130+
131+
function renderLink(
132+
l: LinkObject<Node, Link>,
133+
ctx: CanvasRenderingContext2D
134+
): void {
135+
const s = l.source as Node;
136+
const t = l.target as Node;
137+
138+
if (typeof s !== "object" || typeof t !== "object") {
139+
return;
140+
}
141+
142+
ctx.strokeStyle = "rgba(255, 255, 255, 0.25)";
143+
ctx.lineWidth = 2;
144+
ctx.lineJoin = "bevel";
145+
146+
const [sw, sh] = getNodeSize(s);
147+
const [tw, th] = getNodeSize(t);
148+
let dx = t.x! - s.x!;
149+
let dy = t.y! - s.y!;
150+
151+
const len = Math.sqrt(dx * dx + dy * dy);
152+
dx /= len;
153+
dy /= len;
154+
155+
const o1 = boxCollision(sw, sh, dx, dy);
156+
const o2 = boxCollision(tw, th, -dx, -dy);
157+
158+
const tx = t.x! - dx * o2;
159+
const ty = t.y! - dy * o2;
160+
const arrowBack = 5;
161+
const arrowSide = 5;
162+
163+
ctx.beginPath();
164+
ctx.moveTo(s.x! + dx * o1, s.y! + dy * o1);
165+
ctx.lineTo(tx, ty);
166+
ctx.lineTo(
167+
tx - dx * arrowBack + dy * arrowSide,
168+
ty - dy * arrowBack - dx * arrowSide
169+
);
170+
ctx.lineTo(tx, ty);
171+
ctx.lineTo(
172+
tx - dx * arrowBack - dy * arrowSide,
173+
ty - dy * arrowBack + dx * arrowSide
174+
);
175+
ctx.stroke();
176+
177+
const origTransform = ctx.getTransform();
178+
const angle = Math.atan2(dy, dx);
179+
180+
ctx.translate(s.x!, s.y!);
181+
ctx.rotate(Math.atan2(dy, dx));
182+
ctx.translate(len * 0.5, 0);
183+
184+
if (angle < -Math.PI * 0.5 || angle > Math.PI * 0.5) {
185+
ctx.rotate(Math.PI);
186+
}
187+
188+
ctx.font = "8px monospace";
189+
ctx.textAlign = "center";
190+
ctx.textBaseline = "middle";
191+
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
192+
ctx.fillText(l.name, 0, 8);
193+
194+
ctx.setTransform(origTransform);
195+
}
196+
116197
const GraphView = React.memo(function GraphView({
117198
data
118199
}: GraphViewProps): React.JSX.Element {
@@ -148,11 +229,24 @@ const GraphView = React.memo(function GraphView({
148229
nodeMap.set(object.id, object);
149230
}
150231

232+
const linkName = stripPrefix(q.predicate.value, prefixes);
233+
151234
links.push({
152235
source: subject.id,
153236
target: object.id,
154-
data: q
237+
data: q,
238+
name: linkName
155239
});
240+
241+
subject.longestLinkLength = Math.max(
242+
subject.longestLinkLength,
243+
linkName.length
244+
);
245+
246+
object.longestLinkLength = Math.max(
247+
object.longestLinkLength,
248+
linkName.length
249+
);
156250
}
157251

158252
for (const q of types) {
@@ -180,7 +274,9 @@ const GraphView = React.memo(function GraphView({
180274
"collide",
181275
forceCollide(n => {
182276
const [w, h] = getNodeSize(n as Node);
183-
return Math.max(w, h) * 0.5 + 5;
277+
const linkSz = (n as Node).longestLinkLength * 6;
278+
279+
return Math.max(w, h, linkSz) * 0.5 + 5;
184280
})
185281
);
186282

@@ -193,11 +289,7 @@ const GraphView = React.memo(function GraphView({
193289
graphData={graphData}
194290
nodeCanvasObject={renderNode}
195291
nodePointerAreaPaint={pointerAreaPaint}
196-
linkColor={() => "rgba(255, 255, 255, 0.25)"}
197-
linkWidth={2}
198-
linkDirectionalArrowLength={10}
199-
linkDirectionalArrowRelPos={1.0}
200-
linkCurvature={0.1}
292+
linkCanvasObject={renderLink}
201293
ref={graphRef as RefObject<GraphRef>}
202294
cooldownTime={Number.POSITIVE_INFINITY}
203295
/>

0 commit comments

Comments
 (0)