Spur label: clamp text right edge to trapezoid boundary
Measure actual text width and position so the right side of the text aligns with the angled edge of the spur, preventing overflow onto adjacent conveyors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
31aea34361
commit
07ace0d3f4
@ -556,21 +556,19 @@ function drawConveyanceLabel(ctx: CanvasRenderingContext2D, sym: PlacedSymbol) {
|
|||||||
let cx: number, cy: number, availW: number, availH: number;
|
let cx: number, cy: number, availW: number, availH: number;
|
||||||
if (isSpurType(sym.symbolId)) {
|
if (isSpurType(sym.symbolId)) {
|
||||||
const w2 = sym.w2 ?? sym.w;
|
const w2 = sym.w2 ?? sym.w;
|
||||||
// Find optimal position: push text down where trapezoid is widest,
|
// Compute text dimensions at 14px to find optimal placement
|
||||||
// then center horizontally in the available width at that height.
|
ctx.font = 'bold 14px Arial';
|
||||||
// Trapezoid right edge at height y: w2 + (y/h) * (w - w2)
|
const maxTextW = Math.max(...lines.map(l => ctx.measureText(l).width));
|
||||||
const fontSize = 14;
|
const th = 14 * lines.length;
|
||||||
const lineCount = lines.length;
|
// Push text down where trapezoid is wider, but leave room
|
||||||
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);
|
const optCy = Math.min(sym.h - th / 2 - 1, sym.h * 0.55);
|
||||||
// Right edge at the TOP of the text block (most constraining)
|
// Right edge at top of text — text must not exceed this
|
||||||
const textTop = optCy - th / 2;
|
const textTop = optCy - th / 2;
|
||||||
const rightEdgeAtTop = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
const rightEdge = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
||||||
// Center text in the available width (0 to rightEdgeAtTop)
|
// Place text so right side of text = rightEdge (hard clamp)
|
||||||
cx = sym.x + rightEdgeAtTop / 2;
|
cx = sym.x + Math.min(rightEdge / 2, rightEdge - maxTextW / 2);
|
||||||
cy = sym.y + optCy;
|
cy = sym.y + optCy;
|
||||||
availW = Infinity; // never shrink — position handles fit
|
availW = Infinity;
|
||||||
availH = sym.h;
|
availH = sym.h;
|
||||||
} else {
|
} else {
|
||||||
cx = sym.x + sym.w / 2;
|
cx = sym.x + sym.w / 2;
|
||||||
|
|||||||
@ -48,8 +48,10 @@ function emitConveyanceLabelInner(lines: string[], sym: PlacedSymbol) {
|
|||||||
const th = fontSize * textLines.length;
|
const th = fontSize * textLines.length;
|
||||||
const optCy = Math.min(sym.h - th / 2 - 1, sym.h * 0.55);
|
const optCy = Math.min(sym.h - th / 2 - 1, sym.h * 0.55);
|
||||||
const textTop = optCy - th / 2;
|
const textTop = optCy - th / 2;
|
||||||
const rightEdgeAtTop = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
const rightEdge = w2 + (Math.max(0, textTop) / sym.h) * (sym.w - w2);
|
||||||
labelCx = sym.x + rightEdgeAtTop / 2;
|
// Estimate text width (~8px per char at 14px bold)
|
||||||
|
const estTextW = Math.max(...textLines.map(l => l.length * 8));
|
||||||
|
labelCx = sym.x + Math.min(rightEdge / 2, rightEdge - estTextW / 2);
|
||||||
labelCy = sym.y + optCy;
|
labelCy = sym.y + optCy;
|
||||||
availH = sym.h;
|
availH = sym.h;
|
||||||
} else if (isInductionType(sym.symbolId)) {
|
} else if (isInductionType(sym.symbolId)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user