Skip to content

Commit 41b72f1

Browse files
committed
Improve link label rendering in graph view
1 parent d925841 commit 41b72f1

1 file changed

Lines changed: 49 additions & 22 deletions

File tree

app/components/graphView.tsx

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

233232
if (!start.x || !start.y || !end.x || !end.y) return
234233

234+
let textX, textY, angle;
235+
235236
if (start.id === end.id) {
236237
const radius = NODE_SIZE * link.curve * 6.2;
237238
const angleOffset = -Math.PI / 4; // 45 degrees offset for text alignment
238-
const textX = start.x + radius * Math.cos(angleOffset);
239-
const textY = start.y + radius * Math.sin(angleOffset);
240-
241-
ctx.save();
242-
ctx.translate(textX, textY);
243-
ctx.rotate(-angleOffset);
239+
textX = start.x + radius * Math.cos(angleOffset);
240+
textY = start.y + radius * Math.sin(angleOffset);
241+
angle = -angleOffset;
244242
} else {
245-
const midX = (start.x + end.x) / 2 + (end.y - start.y) * (link.curve / 2);
246-
const midY = (start.y + end.y) / 2 + (start.x - end.x) * (link.curve / 2);
247-
248-
let textAngle = Math.atan2(end.y - start.y, end.x - start.x)
249-
243+
const midX = (start.x + end.x) / 2;
244+
const midY = (start.y + end.y) / 2;
245+
const offset = link.curve / 2;
246+
247+
angle = Math.atan2(end.y - start.y, end.x - start.x);
248+
250249
// maintain label vertical orientation for legibility
251-
if (textAngle > Math.PI / 2) textAngle = -(Math.PI - textAngle);
252-
if (textAngle < -Math.PI / 2) textAngle = -(-Math.PI - textAngle);
253-
254-
ctx.save();
255-
ctx.translate(midX, midY);
256-
ctx.rotate(textAngle);
250+
if (angle > Math.PI / 2) angle = -(Math.PI - angle);
251+
if (angle < -Math.PI / 2) angle = -(-Math.PI - angle);
252+
253+
// Calculate perpendicular offset
254+
const perpX = -Math.sin(angle) * offset;
255+
const perpY = Math.cos(angle) * offset;
256+
257+
// Adjust position to compensate for rotation around origin
258+
const cos = Math.cos(angle);
259+
const sin = Math.sin(angle);
260+
textX = midX + perpX;
261+
textY = midY + perpY;
262+
const rotatedX = textX * cos + textY * sin;
263+
const rotatedY = -textX * sin + textY * cos;
264+
textX = rotatedX;
265+
textY = rotatedY;
257266
}
258267

259-
// add label
268+
// Setup text properties to measure background size
269+
ctx.font = '2px Arial';
270+
const padding = 0.5;
271+
const textWidth = ctx.measureText(link.label).width;
272+
const textHeight = 2; // Approximate height for 2px font
273+
274+
// add label with background and rotation
275+
ctx.rotate(angle);
276+
277+
// Draw background
278+
ctx.fillStyle = 'white';
279+
ctx.fillRect(
280+
textX - textWidth/2 - padding,
281+
textY - textHeight/2 - padding,
282+
textWidth + padding * 2,
283+
textHeight + padding * 2
284+
);
285+
286+
// Draw text
260287
ctx.globalAlpha = 1;
261288
ctx.fillStyle = 'black';
262289
ctx.textAlign = 'center';
263290
ctx.textBaseline = 'middle';
264-
ctx.font = '2px Arial';
265-
ctx.fillText(link.label, 0, 0);
266-
ctx.restore()
291+
ctx.fillText(link.label, textX, textY);
292+
293+
ctx.rotate(-angle); // reset rotation
267294
}}
268295
onNodeClick={handleNodeClick}
269296
onNodeDragEnd={(n, translate) => setPosition(prev => {

0 commit comments

Comments
 (0)