Skip to content
getnextpdf.com

Pro edition

Chart — Deep Reference

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.

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.

Terminal window
composer require nextpdf/pro:^3
SymbolParametersDefault behaviorReturnsThrows or fails withNotes
BarChart::fromData()list<string> $labels, list<int|float> $valuesValues are cast to floatselfDoes not throwSole construction path; the constructor is private
BarChart::withBarColor()ChartColor $colorBar fill; default is palette entry 0selfDoes not throwFluent; mutates the receiver
BarChart::withAxisColor()ChartColor $colorAxis stroke; default #333333selfDoes not throw
BarChart::withBarGap()float $gapGap as a fraction of slot width; default 0.2selfDoes not throwClamped to 0.00.9; out-of-range input is clamped, not rejected
BarChart::withFontSize()float $sizeLabel font size in points; default 7.0selfDoes not throw
BarChart::render()ChartBox $boxAxes, bars, category labels, five value ticksstring operatorsDoes not throw; empty data returns ''A non-positive maximum scales against 1.0
LineChart::create()list<string> $labelsChart with no seriesselfDoes not throwThe constructor is private
LineChart::fromData()list<string> $labels, list<int|float> $valuesAdds one unnamed seriesselfDoes not throwSingle-series convenience
LineChart::addSeries()string $name, list<int|float> $values, ?ChartColor $color = nullA null color auto-assigns from the palette by series indexselfDoes not throwThe series name is reserved for legend use
LineChart::withAxisColor()ChartColor $colorAxis stroke; default #333333selfDoes not throw
LineChart::withLineWidth()float $widthSeries stroke width; default 1.5selfDoes not throw
LineChart::withFontSize()float $sizeLabel font size; default 7.0selfDoes not throw
LineChart::withDots()bool $show, float $radius = 2.5Data-point markers; on by defaultselfDoes not throwMarkers draw as Bezier-approximated circles
LineChart::withGrid()bool $showHorizontal quartile grid; on by defaultselfDoes not throw
LineChart::render()ChartBox $boxGrid, axes, one path per series, labelsstring operatorsDoes not throw; no series returns ''A series shorter than two points draws no path
PieChart::fromData()list<string> $labels, list<int|float> $valuesProportions computed from the value sumselfDoes not throwThe constructor is private
PieChart::withColors()list<ChartColor> $colorsOne color per slice, in orderselfDoes not throwMissing entries fall back to the palette
PieChart::withStrokeColor()ChartColor $colorSlice outline; default whiteselfDoes not throw
PieChart::withFontSize()float $sizeLabel font size; default 7.0selfDoes not throw
PieChart::withPercentages()bool $showPercentage labels; on by defaultselfDoes not throwLabels render only on slices sweeping more than 15 degrees
PieChart::withLegend()bool $showRight-hand legend; on by defaultselfDoes not throwThe legend reserves 80 points of box width
PieChart::render()ChartBox $boxSectors, optional labels, optional legendstring operatorsDoes 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 $heightPDF bottom-left origin, in pointsDoes not throwfinal readonly; dimensions are not validated
ChartBox::fromUserSpace()float $x, float $y, float $width, float $height, float $pageHeightFlips a top-left-origin rectangle to PDF coordinatesselfDoes not throw
ChartBox::right()nonex + widthfloatDoes not throwMethod, not a property
ChartBox::top()noney + heightfloatDoes not throwMethod, not a property
ChartBox::inset()float $left, float $bottom, float $right, float $topSub-box shrunk by the given insetsselfDoes not throwOversized insets yield negative dimensions; not validated
ChartColor::__construct()float $r, float $g, float $b, each 0.01.0Does not throwfinal readonly; components are not clamped
ChartColor::rgb()int $r, int $g, int $b, each 0255Scales components to 0.01.0selfDoes not throw
ChartColor::hex()string $hexAccepts #-prefixed or bare six-digit hexselfDoes not throwAbsent trailing digits decode as zero
ChartColor::palette()int $indexBuilt-in 12-color paletteselfTypeError on a negative indexNon-negative indexes wrap modulo 12
ChartColor::strokeOperator()noneStroke color operator (RG), three decimalsstringDoes not throwMethod, not a property
ChartColor::fillOperator()noneFill color operator (rg), three decimalsstringDoes not throwMethod, not a property
public static function fromData(array $labels, array $values): self
public function withBarColor(ChartColor $color): self
public function withAxisColor(ChartColor $color): self
public function withBarGap(float $gap): self
public function withFontSize(float $size): self
public function render(ChartBox $box): string
public static function create(array $labels): self
public static function fromData(array $labels, array $values): self
public function addSeries(string $name, array $values, ?ChartColor $color = null): self
public function withAxisColor(ChartColor $color): self
public function withLineWidth(float $width): self
public function withFontSize(float $size): self
public function withDots(bool $show, float $radius = 2.5): self
public function withGrid(bool $show): self
public function render(ChartBox $box): string
public static function fromData(array $labels, array $values): self
public function withColors(array $colors): self
public function withStrokeColor(ChartColor $color): self
public function withFontSize(float $size): self
public function withPercentages(bool $show): self
public function withLegend(bool $show): self
public function render(ChartBox $box): string
public 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(): float
public function top(): float
public function inset(float $left, float $bottom, float $right, float $top): self
public static function rgb(int $r, int $g, int $b): self
public static function hex(string $hex): self
public static function palette(int $index): self
public function strokeOperator(): string
public function fillOperator(): string

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.

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.

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.

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.

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.

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.

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 / featureStatusEvidence (test path)ConfidenceNotes
Bar chart — render, axes, bar rectangles, gap clamping, empty/all-zero data, K/M value formattingVerifiedpro/tests/Unit/Chart/BarChartTest.php; BarChartArithmeticCoverageTest.php; BarChartBoundaryCoverageTest.phphighGraphics-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-pointVerifiedpro/tests/Unit/Chart/LineChartTest.php; LineChartCoverageTest.php; LineChartArithmeticCoverageTest.php; LineChartTypeCastCoverageTest.phphighMulti-series, single-point no-line, empty-series, grid and dot paths covered.
Pie chart — sectors, Bezier segmentation, percentages, legend, zero/negative totalVerifiedpro/tests/Unit/Chart/PieChartTest.php; PieChartArithmeticCoverageTest.php; PieChartBoundaryCoverageTest.phphighSector 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, insetVerifiedpro/tests/Unit/Chart/ChartBoxTest.phphighTop-left-origin to bottom-left-origin conversion at page top, bottom, and zero-dimension edges.
ChartColor — RGB scaling, hex parsing, palette, stroke/fill operatorsVerifiedpro/tests/Unit/Chart/ChartColorTest.phphigh0–255 to 0–1 scaling, #-prefixed and bare hex, mixed case, palette wrap-around after 12 entries.
Cross-renderer regression hardeningVerifiedpro/tests/Unit/Chart/ChartCoverageTest.phphighShared regression suite across the three renderers plus value-formatting arithmetic.

All six rows are Verified, each anchored to a pro/tests/** suite.

  • 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 ChartBox with 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 with TypeError on a negative index, because PHP’s negative modulo resolves no palette key.
  • The module performs no cryptography; FIPS mode has no chart-specific behavior.

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.

ClaimStandardClause
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.

  • All five classes carry @since 1.9.0 and are current in nextpdf/pro 3.1.0.
  • The module is self-contained: renderers depend only on ChartBox and ChartColor, 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.

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.