# Measured automatic label placement Opt into alternative positions around visible nodes and connections: ```ts const renderer = new CanvasGraphRenderer({ labels: { mode: 'placement', placementGap: 4, collisionPadding: 3, maxPlacementChecks: 10000, maxPlacementMs: 12 } }) ``` Canvas measures glyph extents with the actual resolved font and middle baseline, including the text outline. It tries eight positions around node bounds and positions on either side of edge paths. Straight, curved, looped and accepted layout routes share the renderer's geometry. Candidate rectangles avoid node bodies/strokes, edge strokes/arrows and already accepted labels. Conservative curve flattening includes its approximation error; bounding rectangles can reject visually empty corners of nonrectangular nodes. Dragging, selection, focus, hover and highlights get first choice, in that order. Node labels precede edge labels on a tie. An emphasized label bypasses the normal zoom threshold but still has to fit without collisions. Existing explicit `layoutCenter` values are fixed candidates in this mode. Hidden owners/styles, labels below their zoom threshold, offscreen candidates and unresolved conflicts are suppressed. Node/edge picking and source graph membership remain unchanged. The default `all` mode and existing `automatic` suppression mode remain available. `placement` is a separate opt-in policy for diagrams that need alternatives. ## Inspect and reuse results After a successful placement-mode render: ```ts const report = renderer.getLabelPlacements() // report.placements: id, owner, priority, status, screen/world centers, bounds // report.checks and report.exhausted: null, 'checks', or 'time' ``` Each label reports `placed`, `hidden`, `zoom`, `conflict` or `budget`. Placed bounds include measured text, halo and collision padding. Reports and nested coordinates are immutable. Resize/unmount/destroy clear the report; subsequent renders remeasure and replace it, including after camera, graph, route, style or interaction changes. No label positions are written back into graph data. The public `placeRenderLabels(snapshot, measureLabel, options)` utility exposes the same policy for custom renderers and exports. Its metrics provider returns a symmetric `{ width, height }` in CSS pixels around the middle-baseline center; include any text halo in those dimensions. `resolveVisibleLabelIds` remains a lightweight inspection helper and uses a conservative text estimator when no Canvas is involved; its results are not a font-metric guarantee. ## Budgets and fonts Defaults cap search at 10,000 rectangle/segment checks and 12 milliseconds, with linear geometry preparation and label ordering overhead. A long explicit route also consumes checks while generating candidates. Exhaustion suppresses the remaining labels in stable priority/input order. Check-limited results are repeatable for fixed inputs; elapsed-time limits can change the accepted prefix across machines. This is bounded best-effort placement, not a hard frame-time or all-labels-visible guarantee. Increase budgets deliberately for your diagram. Wait for the fonts your application uses before rendering (`document.fonts.ready` for already requested document fonts), and rerender after later font loads or font changes. Canvas measures the font currently available; it does not download fonts or monitor application styles. The [routing and label example](../../vanilla/obstacle-routing/index.html) demonstrates placement, exact edge picking, rerouting after movement and refresh after zoom.