Spur label: compute optimal position from trapezoid geometry
Position text at 55% height (toward wider area), then center horizontally based on the actual right edge at the text's top, minimizing overflow past the angled edge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f203556082
commit
31aea34361
@ -556,12 +556,21 @@ function drawConveyanceLabel(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
||||
let cx: number, cy: number, availW: number, availH: number;
|
||||
if (isSpurType(sym.symbolId)) {
|
||||
const w2 = sym.w2 ?? sym.w;
|
||||
// The 90° corners are at x=0 (left edge). The rectangular region
|
||||
// from x=0 to x=min(w2,w) always fits inside the trapezoid.
|
||||
const safeW = Math.min(w2, sym.w);
|
||||
cx = sym.x + safeW / 2;
|
||||
cy = sym.y + sym.h / 2;
|
||||
availW = Infinity; // never shrink font for spurs — enough visual room
|
||||
// Find optimal position: push text down where trapezoid is widest,
|
||||
// then center horizontally in the available width at that height.
|
||||
// Trapezoid right edge at height y: w2 + (y/h) * (w - w2)
|
||||
const fontSize = 14;
|
||||
const lineCount = lines.length;
|
||||
const th = fontSize * lineCount;
|
||||
// Optimal cy: as low as possible (widest area), clamped to fit
|
||||
const optCy = Math.min(sym.h - th / 2 - 1, sym.h * 0.55);
|
||||
// Right edge at the TOP of the text block (most constraining)
|
||||
const textTop = optCy - th / 2;
|
||||
const rightEdgeAtTop = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
||||
// Center text in the available width (0 to rightEdgeAtTop)
|
||||
cx = sym.x + rightEdgeAtTop / 2;
|
||||
cy = sym.y + optCy;
|
||||
availW = Infinity; // never shrink — position handles fit
|
||||
availH = sym.h;
|
||||
} else {
|
||||
cx = sym.x + sym.w / 2;
|
||||
|
||||
@ -44,9 +44,13 @@ function emitConveyanceLabelInner(lines: string[], sym: PlacedSymbol) {
|
||||
textRotDeg = (textRotRad * 180) / Math.PI;
|
||||
} else if (isSpurType(sym.symbolId)) {
|
||||
const w2 = sym.w2 ?? sym.w;
|
||||
const safeW = Math.min(w2, sym.w);
|
||||
labelCx = sym.x + safeW / 2;
|
||||
labelCy = sym.y + sym.h / 2;
|
||||
const fontSize = 14;
|
||||
const th = fontSize * textLines.length;
|
||||
const optCy = Math.min(sym.h - th / 2 - 1, sym.h * 0.55);
|
||||
const textTop = optCy - th / 2;
|
||||
const rightEdgeAtTop = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
||||
labelCx = sym.x + rightEdgeAtTop / 2;
|
||||
labelCy = sym.y + optCy;
|
||||
availH = sym.h;
|
||||
} else if (isInductionType(sym.symbolId)) {
|
||||
const stripTopY = sym.y + sym.h * INDUCTION_CONFIG.stripTopFrac;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user