Skip to content

Commit 0f9143a

Browse files
authored
Merge branch 'staging' into add-create-repo
2 parents d1e2591 + 42fe6c3 commit 0f9143a

File tree

2 files changed

+85
-23
lines changed

2 files changed

+85
-23
lines changed

app/components/graphView.tsx

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import ForceGraph2D, { ForceGraphMethods, NodeObject } from 'react-force-graph-2d';
32
import { Graph, GraphData, Link, Node } from './model';
43
import { Dispatch, RefObject, SetStateAction, useEffect, useRef, useState } from 'react';
@@ -254,38 +253,77 @@ export default function GraphView({
254253

255254
if (!start.x || !start.y || !end.x || !end.y) return
256255

256+
let textX, textY, angle;
257+
257258
if (start.id === end.id) {
258259
const radius = NODE_SIZE * link.curve * 6.2;
259260
const angleOffset = -Math.PI / 4; // 45 degrees offset for text alignment
260-
const textX = start.x + radius * Math.cos(angleOffset);
261-
const textY = start.y + radius * Math.sin(angleOffset);
262-
263-
ctx.save();
264-
ctx.translate(textX, textY);
265-
ctx.rotate(-angleOffset);
261+
textX = start.x + radius * Math.cos(angleOffset);
262+
textY = start.y + radius * Math.sin(angleOffset);
263+
angle = -angleOffset;
266264
} else {
267-
const midX = (start.x + end.x) / 2 + (end.y - start.y) * (link.curve / 2);
268-
const midY = (start.y + end.y) / 2 + (start.x - end.x) * (link.curve / 2);
265+
const midX = (start.x + end.x) / 2;
266+
const midY = (start.y + end.y) / 2;
267+
const offset = link.curve / 2;
269268

270-
let textAngle = Math.atan2(end.y - start.y, end.x - start.x)
269+
angle = Math.atan2(end.y - start.y, end.x - start.x);
271270

272271
// maintain label vertical orientation for legibility
273-
if (textAngle > Math.PI / 2) textAngle = -(Math.PI - textAngle);
274-
if (textAngle < -Math.PI / 2) textAngle = -(-Math.PI - textAngle);
272+
if (angle > Math.PI / 2) angle = -(Math.PI - angle);
273+
if (angle < -Math.PI / 2) angle = -(-Math.PI - angle);
274+
275+
// Calculate perpendicular offset
276+
const perpX = -Math.sin(angle) * offset;
277+
const perpY = Math.cos(angle) * offset;
278+
279+
// Adjust position to compensate for rotation around origin
280+
const cos = Math.cos(angle);
281+
const sin = Math.sin(angle);
282+
textX = midX + perpX;
283+
textY = midY + perpY;
284+
const rotatedX = textX * cos + textY * sin;
285+
const rotatedY = -textX * sin + textY * cos;
286+
textX = rotatedX;
287+
textY = rotatedY;
288+
}
275289

276-
ctx.save();
277-
ctx.translate(midX, midY);
278-
ctx.rotate(textAngle);
290+
// Setup text properties to measure background size
291+
ctx.font = '2px Arial';
292+
const padding = 0.5;
293+
// Get text width and height
294+
const label = graph.LabelsMap.get(link.label)!
295+
let { textWidth, textHeight } = label
296+
297+
if (!textWidth || !textHeight) {
298+
const { width, actualBoundingBoxAscent, actualBoundingBoxDescent } = ctx.measureText(link.label)
299+
textWidth = width
300+
textHeight = actualBoundingBoxAscent + actualBoundingBoxDescent
301+
graph.LabelsMap.set(link.label, { ...label, textWidth, textHeight })
279302
}
280303

281-
// add label
304+
// Save the current context state
305+
ctx.save();
306+
307+
// add label with background and rotation
308+
ctx.rotate(angle);
309+
310+
// Draw background
311+
ctx.fillStyle = 'white';
312+
ctx.fillRect(
313+
textX - textWidth / 2 - padding,
314+
textY - textHeight / 2 - padding,
315+
textWidth + padding * 2,
316+
textHeight + padding * 2
317+
);
318+
319+
// Draw text
282320
ctx.globalAlpha = 1;
283321
ctx.fillStyle = 'black';
284322
ctx.textAlign = 'center';
285323
ctx.textBaseline = 'middle';
286-
ctx.font = '2px Arial';
287-
ctx.fillText(link.label, 0, 0);
288-
ctx.restore()
324+
ctx.fillText(link.label, textX, textY);
325+
326+
ctx.restore(); // reset rotation
289327
}}
290328
onNodeClick={handleNodeClick}
291329
onNodeDragEnd={(n, translate) => setPosition(prev => {

app/components/model.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ export interface Category {
1111
show: boolean,
1212
}
1313

14+
export interface Label {
15+
name: string,
16+
textWidth: number,
17+
textHeight: number,
18+
}
19+
1420
export type Node = NodeObject<{
1521
id: number,
1622
name: string,
@@ -62,18 +68,21 @@ export class Graph {
6268

6369
private id: string;
6470
private categories: Category[];
71+
private labels: Label[];
6572
private elements: GraphData;
66-
6773
private categoriesMap: Map<string, Category>;
74+
private labelsMap: Map<string, Label>;
6875
private nodesMap: Map<number, Node>;
6976
private linksMap: Map<number, Link>;
7077

71-
private constructor(id: string, categories: Category[], elements: GraphData,
72-
categoriesMap: Map<string, Category>, nodesMap: Map<number, Node>, edgesMap: Map<number, Link>) {
78+
private constructor(id: string, categories: Category[], labels: Label[], elements: GraphData,
79+
categoriesMap: Map<string, Category>, labelsMap: Map<string, Label>, nodesMap: Map<number, Node>, edgesMap: Map<number, Link>) {
7380
this.id = id;
7481
this.categories = categories;
82+
this.labels = labels;
7583
this.elements = elements;
7684
this.categoriesMap = categoriesMap;
85+
this.labelsMap = labelsMap;
7786
this.nodesMap = nodesMap;
7887
this.linksMap = edgesMap;
7988
}
@@ -90,6 +99,14 @@ export class Graph {
9099
return this.categoriesMap;
91100
}
92101

102+
get Labels(): Label[] {
103+
return this.labels;
104+
}
105+
106+
get LabelsMap(): Map<string, Label> {
107+
return this.labelsMap;
108+
}
109+
93110
get Elements(): GraphData {
94111
return this.elements;
95112
}
@@ -111,7 +128,7 @@ export class Graph {
111128
}
112129

113130
public static empty(): Graph {
114-
return new Graph("", [], { nodes: [], links: [] }, new Map<string, Category>(), new Map<number, Node>(), new Map<number, Link>())
131+
return new Graph("", [], [], { nodes: [], links: [] }, new Map<string, Category>(), new Map<string, Label>(), new Map<number, Node>(), new Map<number, Link>())
115132
}
116133

117134
public static create(results: any, graphName: string): Graph {
@@ -207,6 +224,13 @@ export class Graph {
207224
this.nodesMap.set(edgeData.dest_node, target)
208225
}
209226

227+
let label = this.labelsMap.get(edgeData.relation)
228+
if (!label) {
229+
label = { name: edgeData.relation, textWidth: 0, textHeight: 0 }
230+
this.labelsMap.set(edgeData.relation, label)
231+
this.labels.push(label)
232+
}
233+
210234
link = {
211235
id: edgeData.id,
212236
source,

0 commit comments

Comments
 (0)