feat(graph): centered column headers + member avatar letters

- Column headers centered horizontally over pill area (not column edge)
- Member/lead nodes show first letter of name inside hexagon as avatar
  (bold, sized proportionally to node radius, colored in member color)
- Lead gets slightly smaller font (0.6r vs 0.7r) to fit context ring
This commit is contained in:
iliya 2026-03-28 12:39:50 +02:00
parent 899922da9b
commit 9fdbdd72d9
2 changed files with 25 additions and 3 deletions

View file

@ -44,6 +44,9 @@ export function drawAgents(
// Hexagonal body with interior fill
drawHexBody(ctx, x, y, r, color, node.state, time, isSelected, isHovered);
// Avatar: first letter of name centered inside hexagon
drawAvatar(ctx, x, y, r, node.label, color, node.kind === 'lead');
// Breathing animation + spawn/waiting effects
drawBreathing(ctx, x, y, r, node.state, time, node.spawnStatus);
@ -207,6 +210,25 @@ function drawBreathing(
}
}
function drawAvatar(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
r: number,
name: string,
color: string,
isLead: boolean,
): void {
const letter = name.charAt(0).toUpperCase();
const fontSize = isLead ? Math.round(r * 0.6) : Math.round(r * 0.7);
ctx.font = `bold ${fontSize}px sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = hexWithAlpha(color, 0.9);
ctx.fillText(letter, x, y + 1);
}
function drawLabel(
ctx: CanvasRenderingContext2D,
x: number,

View file

@ -8,7 +8,7 @@
*/
import type { GraphNode } from '../ports/types';
import { KANBAN_ZONE } from '../constants/canvas-constants';
import { KANBAN_ZONE, TASK_PILL } from '../constants/canvas-constants';
/** Column header info for rendering */
export interface KanbanColumnHeader {
@ -125,10 +125,10 @@ export class KanbanLayoutEngine {
const colX = baseX + colIdx * columnWidth;
const config = COLUMN_LABELS[col.name] ?? { label: col.name, color: '#888' };
// Column header
// Column header — centered over pill area
headers.push({
label: config.label,
x: colX + columnWidth / 2, // centered in column
x: colX + TASK_PILL.width / 2, // horizontally centered over pills
y: baseY,
color: config.color,
});