Tracks, Bands And Legends
Three helpers for the recurring furniture of a chart or a board: parallel lanes, an edge strip, and a key. Each takes a rectangle and returns placed frames. None of them draws anything.
Track Groups
TrackGroup divides a canvas into parallel lanes along one axis, with an optional header and footer reserved at the ends.
horizontal()vertical()use Atelier\Layout\Track\TrackGroup;
use Atelier\Layout\Value\InsetSpec;
$placed = TrackGroup::horizontal('swimlanes')
->padding(InsetSpec::px(12))
->gap(8)
->headerSize(28)
->equalTracks()
->addTrack('backlog')
->addTrack('doing')
->addTrack('done')
->place($canvas);
Three sizing policies decide how the lanes share the main axis:
| Policy | Behaviour |
|---|---|
equalTracks() |
every lane gets the same size |
contentSizedTracks() |
each lane takes its preferred size |
stretchedTracks(float $flex) |
lanes share the leftover space |
addTrack() accepts a Dimension or a preferred main size to override the group policy for one lane. Kanban columns, swimlanes, and Gantt rows are the usual consumers. When the lanes need two axes rather than one, reach for Grid instead.
Edge Bands
EdgeBand reserves a strip along the top or bottom of a rectangle and returns both the strip and what remains.
use Atelier\Layout\Band\EdgeBand;
$placed = EdgeBand::top('axis')
->bandSize(24)
->gap(8)
->place($available);
It answers the question every chart asks first: where does the axis go, and what is left for the plot. Splitting it out means the plot area is computed once, by one rule, instead of being open-coded next to each renderer.
Legends
LegendBlock lays out entries made of a swatch and a label, in a column or a row.
vertical()horizontal()use Atelier\Layout\Alignment;
use Atelier\Layout\Legend\LegendBlock;
$placed = LegendBlock::vertical('series')
->swatchSize(10, 10)
->labelGap(6)
->gap(4)
->align(Alignment::Start, Alignment::Start)
->add('revenue', labelWidth: 54, labelHeight: 12)
->add('cost', labelWidth: 38, labelHeight: 12)
->place($available);
Label widths are supplied by the caller, measured with whatever measurer the consumer trusts. The legend places; it does not measure text on your behalf. See Text And Inline Runs if you need that measurement first.
gap() separates entries, labelGap() separates a swatch from its own label. Two different rhythms, two different knobs.