Pro edition
Chart — Deep Reference
At a glance
Section titled “At a glance”This page is the contract-level reference for the NextPDF Pro Chart module. The surface is five public classes in NextPDF\Pro\Chart: the BarChart, LineChart, and PieChart renderers, the ChartBox placement rectangle, and the ChartColor value object. Each renderer is a drawing primitive. A static factory creates it, fluent with*() calls configure it, and render(ChartBox $box): string returns PDF content-stream operators for the supplied rectangle. Output is vector-only and deterministic: identical input and configuration produce identical bytes. Degenerate inputs return an empty string rather than throwing, so a chart never breaks the surrounding page. The task-oriented view lives on the capability page.
Availability & licensing
Section titled “Availability & licensing”This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.
Chart renderers are capability-licensed under the chart.* capability family. When the capability is not licensed, the chart renderers are not available.
Public API surface
Section titled “Public API surface”composer require nextpdf/pro:^3| Symbol | Parameters | Default behavior | Returns | Throws or fails with | Notes |
|---|---|---|---|---|---|
BarChart::fromData() | list<string> $labels, list<int|float> $values | Values are cast to float | self | Does not throw | Sole construction path; the constructor is private |
BarChart::withBarColor() | ChartColor $color | Bar fill; default is palette entry 0 | self | Does not throw | Fluent; mutates the receiver |
BarChart::withAxisColor() | ChartColor $color | Axis stroke; default #333333 | self | Does not throw | — |
BarChart::withBarGap() | float $gap | Gap as a fraction of slot width; default 0.2 | self | Does not throw | Clamped to 0.0–0.9; out-of-range input is clamped, not rejected |
BarChart::withFontSize() | float $size | Label font size in points; default 7.0 | self | Does not throw | — |
BarChart::render() | ChartBox $box | Axes, bars, category labels, five value ticks | string operators | Does not throw; empty data returns '' | A non-positive maximum scales against 1.0 |
LineChart::create() | list<string> $labels | Chart with no series | self | Does not throw | The constructor is private |
LineChart::fromData() | list<string> $labels, list<int|float> $values | Adds one unnamed series | self | Does not throw | Single-series convenience |
LineChart::addSeries() | string $name, list<int|float> $values, ?ChartColor $color = null | A null color auto-assigns from the palette by series index | self | Does not throw | The series name is reserved for legend use |
LineChart::withAxisColor() | ChartColor $color | Axis stroke; default #333333 | self | Does not throw | — |
LineChart::withLineWidth() | float $width | Series stroke width; default 1.5 | self | Does not throw | — |
LineChart::withFontSize() | float $size | Label font size; default 7.0 | self | Does not throw | — |
LineChart::withDots() | bool $show, float $radius = 2.5 | Data-point markers; on by default | self | Does not throw | Markers draw as Bezier-approximated circles |
LineChart::withGrid() | bool $show | Horizontal quartile grid; on by default | self | Does not throw | — |
LineChart::render() | ChartBox $box | Grid, axes, one path per series, labels | string operators | Does not throw; no series returns '' | A series shorter than two points draws no path |
PieChart::fromData() | list<string> $labels, list<int|float> $values | Proportions computed from the value sum | self | Does not throw | The constructor is private |
PieChart::withColors() | list<ChartColor> $colors | One color per slice, in order | self | Does not throw | Missing entries fall back to the palette |
PieChart::withStrokeColor() | ChartColor $color | Slice outline; default white | self | Does not throw | — |
PieChart::withFontSize() | float $size | Label font size; default 7.0 | self | Does not throw | — |
PieChart::withPercentages() | bool $show | Percentage labels; on by default | self | Does not throw | Labels render only on slices sweeping more than 15 degrees |
PieChart::withLegend() | bool $show | Right-hand legend; on by default | self | Does not throw | The legend reserves 80 points of box width |
PieChart::render() | ChartBox $box | Sectors, optional labels, optional legend | string operators | Does not throw; empty data or a total at or below zero returns '' | Arcs split into Bezier segments of at most 90 degrees |
ChartBox::__construct() | float $x, float $y, float $width, float $height | PDF bottom-left origin, in points | — | Does not throw | final readonly; dimensions are not validated |
ChartBox::fromUserSpace() | float $x, float $y, float $width, float $height, float $pageHeight | Flips a top-left-origin rectangle to PDF coordinates | self | Does not throw | — |
ChartBox::right() | none | x + width | float | Does not throw | Method, not a property |
ChartBox::top() | none | y + height | float | Does not throw | Method, not a property |
ChartBox::inset() | float $left, float $bottom, float $right, float $top | Sub-box shrunk by the given insets | self | Does not throw | Oversized insets yield negative dimensions; not validated |
ChartColor::__construct() | float $r, float $g, float $b, each 0.0–1.0 | — | — | Does not throw | final readonly; components are not clamped |
ChartColor::rgb() | int $r, int $g, int $b, each 0–255 | Scales components to 0.0–1.0 | self | Does not throw | — |
ChartColor::hex() | string $hex | Accepts #-prefixed or bare six-digit hex | self | Does not throw | Absent trailing digits decode as zero |
ChartColor::palette() | int $index | Built-in 12-color palette | self | TypeError on a negative index | Non-negative indexes wrap modulo 12 |
ChartColor::strokeOperator() | none | Stroke color operator (RG), three decimals | string | Does not throw | Method, not a property |
ChartColor::fillOperator() | none | Fill color operator (rg), three decimals | string | Does not throw | Method, not a property |
Entry-point signatures
Section titled “Entry-point signatures”public static function fromData(array $labels, array $values): selfpublic function withBarColor(ChartColor $color): selfpublic function withAxisColor(ChartColor $color): selfpublic function withBarGap(float $gap): selfpublic function withFontSize(float $size): selfpublic function render(ChartBox $box): stringpublic static function create(array $labels): selfpublic static function fromData(array $labels, array $values): selfpublic function addSeries(string $name, array $values, ?ChartColor $color = null): selfpublic function withAxisColor(ChartColor $color): selfpublic function withLineWidth(float $width): selfpublic function withFontSize(float $size): selfpublic function withDots(bool $show, float $radius = 2.5): selfpublic function withGrid(bool $show): selfpublic function render(ChartBox $box): stringpublic static function fromData(array $labels, array $values): selfpublic function withColors(array $colors): selfpublic function withStrokeColor(ChartColor $color): selfpublic function withFontSize(float $size): selfpublic function withPercentages(bool $show): selfpublic function withLegend(bool $show): selfpublic function render(ChartBox $box): stringpublic function __construct( public float $x, public float $y, public float $width, public float $height,)
public static function fromUserSpace( float $x, float $y, float $width, float $height, float $pageHeight,): self
public function right(): floatpublic function top(): floatpublic function inset(float $left, float $bottom, float $right, float $top): selfpublic static function rgb(int $r, int $g, int $b): selfpublic static function hex(string $hex): selfpublic static function palette(int $index): selfpublic function strokeOperator(): stringpublic function fillOperator(): stringBehavior contract
Section titled “Behavior contract”Common renderer shape
Section titled “Common renderer shape”All three renderers follow one lifecycle: a static factory, fluent configuration, one render() call. Configuration methods mutate the receiver and return it; renderers are not immutable value objects. render() reads configuration without mutating it, so one configured renderer can render into several boxes. Every render wraps its output in a save/restore graphics-state pair, so chart state never leaks into the page. Coordinates emit at two decimals and color components at three, which keeps output byte-stable. Text renders through the /ChartFont font resource name at the configured size; the caller registers a font under that name in the target page’s resource dictionary. Label strings escape backslash and parentheses before entering string operands. Renderers perform no reflow, no clipping, and no container negotiation: the caller owns placement.
Scaling and layout
Section titled “Scaling and layout”Bar and line charts reserve a fixed plot inset inside the box: 40 points left, 20 bottom, 10 right, 10 top. The remaining plot area scales values linearly against the series maximum. A maximum of zero or below scales against 1.0 instead, so all-zero data renders axes with flat content rather than dividing by zero. Both draw X and Y axes at 0.5-point width and five value ticks at quartile positions. Bar charts format tick values with K and M suffixes above one thousand and one million; line charts print plain numbers.
Bar chart
Section titled “Bar chart”Each value occupies an equal slot across the plot width. The bar fills the slot minus the configured gap fraction and is centered in the slot. Category labels draw 12 points below the plot area.
Line chart
Section titled “Line chart”The grid, when enabled, draws four horizontal quartile lines in light gray (0.85 0.85 0.85 RG) beneath the axes and series. Each series draws one polyline through its points, spanning the full plot width. Optional markers draw as four-segment Bezier circles at each data point. Series colors default to consecutive palette entries in insertion order.
Pie chart
Section titled “Pie chart”Slices lay out in data order, starting at the positive X axis and sweeping counterclockwise. Each sector path closes and paints with combined fill and stroke (h B); arcs split into Bezier segments of at most 90 degrees. Percentage labels round to whole percent and render only on slices sweeping more than 15 degrees. The legend, when enabled, reserves 80 points of box width on the right and renders an 8-point swatch per entry at a 12-point line height. The radius is half the smaller of the remaining width and the box height, minus a 10-point margin.
Placement and color value objects
Section titled “Placement and color value objects”ChartBox is an immutable rectangle in PDF user units (points) with a bottom-left origin. ChartBox::fromUserSpace() converts a top-left-origin rectangle by flipping against the supplied page height. inset() returns a new, smaller box; right() and top() are accessor methods. ChartColor is self-contained and does not depend on the Core color classes. Its 12-entry palette assigns series and slice colors when the caller supplies none.
Support matrix (evidence-backed)
Section titled “Support matrix (evidence-backed)”A chart type or feature earns Verified only when a pro/tests/** fixture exercises it. No external standard governs charts, so the evidence is unit-level behavioral coverage.
| Chart type / feature | Status | Evidence (test path) | Confidence | Notes |
|---|---|---|---|---|
| Bar chart — render, axes, bar rectangles, gap clamping, empty/all-zero data, K/M value formatting | Verified | pro/tests/Unit/Chart/BarChartTest.php; BarChartArithmeticCoverageTest.php; BarChartBoundaryCoverageTest.php | high | Graphics-state wrap, axis lines, bar-height proportions, tick count, and formatting boundaries asserted. |
| Line chart — single and multi-series, line path, axes, dots, grid, single-point | Verified | pro/tests/Unit/Chart/LineChartTest.php; LineChartCoverageTest.php; LineChartArithmeticCoverageTest.php; LineChartTypeCastCoverageTest.php | high | Multi-series, single-point no-line, empty-series, grid and dot paths covered. |
| Pie chart — sectors, Bezier segmentation, percentages, legend, zero/negative total | Verified | pro/tests/Unit/Chart/PieChartTest.php; PieChartArithmeticCoverageTest.php; PieChartBoundaryCoverageTest.php | high | Sector paths, segment counts per sweep, the 15-degree label threshold, legend geometry, and empty-string behavior covered. |
ChartBox — coordinate conversion (user space to PDF), page top/bottom, zero dims, inset | Verified | pro/tests/Unit/Chart/ChartBoxTest.php | high | Top-left-origin to bottom-left-origin conversion at page top, bottom, and zero-dimension edges. |
ChartColor — RGB scaling, hex parsing, palette, stroke/fill operators | Verified | pro/tests/Unit/Chart/ChartColorTest.php | high | 0–255 to 0–1 scaling, #-prefixed and bare hex, mixed case, palette wrap-around after 12 entries. |
| Cross-renderer regression hardening | Verified | pro/tests/Unit/Chart/ChartCoverageTest.php | high | Shared regression suite across the three renderers plus value-formatting arithmetic. |
All six rows are Verified, each anchored to a pro/tests/** suite.
Edge cases & failure modes
Section titled “Edge cases & failure modes”- No renderer throws on data. Degenerate input degrades to an empty string: empty bar or line data, an empty series list, and a pie total at or below zero all return
''. - A line series with fewer than two points draws no path and no markers; axes and labels still render.
- Negative bar values are not rejected; the bar rectangle extends below the X axis.
- Label and value counts are not cross-validated. The caller supplies lists of matching length.
- A
ChartBoxwith zero or negative dimensions is accepted and produces degenerate output; callers must size the box. - Renderers do not clip. An oversized chart, its below-plot category labels, or a long legend can overflow the intended page region.
- A page missing a font under the chart font resource name leaves text operators referencing an undefined resource; viewer behavior is then undefined.
ChartColor::hex()performs no validation; input shorter than six digits decodes absent components as zero.ChartColor::palette()fails withTypeErroron a negative index, because PHP’s negative modulo resolves no palette key.- The module performs no cryptography; FIPS mode has no chart-specific behavior.
Conformance
Section titled “Conformance”The Chart module emits PDF content-stream operators. No external chart, symbology, or cryptographic standard governs its output, so the only conformance surface is the emitted operator stream.
| Claim | Standard | Clause |
|---|---|---|
| Emitted graphics follow the content-stream operator model; output nests inside a saved and restored graphics state. | ISO 32000-2 | §8.1 |
Bars, lines, sectors, and markers are path objects: construction begins with m or re and concludes with a path-painting operator. | ISO 32000-2 | §8.5.2 |
Labels render as text objects: the position is established after BT, and glyphs paint with the Tj text-showing operator. | ISO 32000-2 | §9.2.2, §9.4.3 |
All clauses are paraphrased; this page reproduces no normative text. These are capability statements. Correct rendering of the stream also depends on the enclosing document being well formed, which is the document writer’s responsibility.
Development notes
Section titled “Development notes”- All five classes carry
@since 1.9.0and are current innextpdf/pro3.1.0. - The module is self-contained: renderers depend only on
ChartBoxandChartColor, with no Core coupling. - Deterministic output keeps charted documents reproducible, diff-stable, and safe to sign or archive.
- Register a font under the chart font resource name once per page that hosts charts.
- Reuse a configured renderer across boxes freely;
render()performs no state mutation. - Test evidence lives under
pro/tests/Unit/Chart/; the support matrix anchors each Verified row to its suite.
Publication boundary
Section titled “Publication boundary”This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.
See also
Section titled “See also”- Chart (capability) — task-oriented overview, install, and code samples.
- Barcode — Deep Reference — the sibling Pro drawing surface with its own evidence-backed support matrix.