PHPackages                             hbvsoft/charthandler - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. hbvsoft/charthandler

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

hbvsoft/charthandler
====================

Extensible PHP charting library with pluggable rendering backends and multiple output formats (PNG/JPEG/SVG, base64/data-URI).

v1.4.0(1mo ago)06MITPHPPHP &gt;=8.1CI passing

Since May 20Pushed 1mo agoCompare

[ Source](https://github.com/hbagheri/ChartHandler)[ Packagist](https://packagist.org/packages/hbvsoft/charthandler)[ RSS](/packages/hbvsoft-charthandler/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (3)Versions (6)Used By (0)

ChartHandler
============

[](#charthandler)

[![CI](https://github.com/hbagheri/ChartHandler/actions/workflows/ci.yml/badge.svg)](https://github.com/hbagheri/ChartHandler/actions/workflows/ci.yml)

A clean, dependency-light PHP charting library with **two rendering backends** (pure-PHP SVG and GD raster) and multiple output formats — designed so charts drop straight into **HTML emails as inline base64 images**, even offline.

```
use HBVSoft\ChartHandler\Chart;

// A PNG  tag you can paste into an HTML email — no external requests.
echo Chart::pie(['Chrome' => 63, 'Firefox' => 19, 'Safari' => 18])
    ->title('Browser share')
    ->toEmailImg();
```

Features
--------

[](#features)

- **Chart types:** pie, donut, bar, stacked bar, line, area, scatter, and **combo** (mixed bars + line/area with a secondary axis).
- **Two backends, zero external chart libraries:**
    - `SvgRenderer` — pure PHP, crisp and scalable (great for the web).
    - `GdRenderer` — PNG / JPEG / GIF / WebP via PHP's standard `gd` extension.
- **Output anywhere:** raw bytes, file, base64, `data:` URI, or a ready-to-embed `` tag.
- **Email-first:** `toEmailImg()` produces a self-contained PNG `` that renders in every client (including Outlook desktop, which does **not** render inline SVG).
- Fluent API; strict types; PHPStan level 6; tested.

Requirements
------------

[](#requirements)

- PHP **8.1+**
- `ext-gd` — only for raster output (PNG/JPEG/GIF/WebP). SVG output needs no extensions.

Installation
------------

[](#installation)

```
composer require hbvsoft/charthandler
```

Quickstart
----------

[](#quickstart)

```
use HBVSoft\ChartHandler\Chart;
use HBVSoft\ChartHandler\Spec\Series;

// Pie from an associative array (keys become slice labels)
Chart::pie(['Chrome' => 63, 'Firefox' => 19, 'Safari' => 18])
    ->title('Browser share')
    ->save('browser-share.png');          // format inferred from the extension

// Bar with explicit categories
Chart::bar([12, 19, 7, 22, 15])
    ->title('Monthly revenue')
    ->categories(['Jan', 'Feb', 'Mar', 'Apr', 'May'])
    ->save('revenue.svg');

// Multi-series line
Chart::line([Series::fromValues('2024', [10, 14, 9, 18])])
    ->addSeries(Series::fromValues('2025', [13, 11, 17, 21]))
    ->categories(['Q1', 'Q2', 'Q3', 'Q4'])
    ->toPng();                            // raw PNG bytes

// Donut as an SVG string
$svg = Chart::donut(['Linux' => 45, 'Windows' => 35, 'macOS' => 20])->toSvg();

// Stacked bar: series stacked per category
Chart::stackedBar([
    Series::fromValues('Direct', [12, 19, 15]),
    Series::fromValues('Organic', [20, 24, 28]),
])->categories(['Jan', 'Feb', 'Mar'])->toPng();

// Scatter from numeric (x, y) pairs
Chart::scatter([[1, 5], [2, 9], [4, 3], [6, 7]])
    ->addPoints('Series B', [[1, 2], [3, 6], [5, 4]])
    ->toSvg();
```

Combo charts (dual axis)
------------------------

[](#combo-charts-dual-axis)

Mix bars with a line/area in one chart, each bound to its own axis. The secondary (right) axis is scaled independently, so you never pre-scale the line's values:

```
use HBVSoft\ChartHandler\Chart;
use HBVSoft\ChartHandler\Spec\Axis;

Chart::combo()
    ->addBar('Revenue', [120, 190, 70, 220])
    ->addLine('Conversion %', [3.2, 4.1, 2.8, 5.0], Axis::Right)  // right axis, own scale
    ->title('Revenue vs conversion')
    ->categories(['Q1', 'Q2', 'Q3', 'Q4'])
    ->toEmailImg();
```

`addBar()`, `addLine()`, and `addArea()` each take `(string $name, array|Series $data, Axis $axis = Axis::Left)`.

Output methods
--------------

[](#output-methods)

MethodReturnsNotes`toSvg()``string`SVG markup`toPng()` / `toJpeg()``string`raw image bytes (needs `ext-gd`)`toDataUri(Format = Png)``string``data:;base64,…``toHtmlImg(Format = Png, $attrs = [])``string````toEmailImg($attrs = [])``string`PNG `` — **use this for email**`save($path)``bool`format inferred from the file extension`render(Format)``RenderedChart`the value object below, for full control`Format` (`HBVSoft\ChartHandler\Output\Format`): `Png`, `Jpeg`, `Gif`, `Webp`, `Svg`.

Charts in HTML email (the main use case)
----------------------------------------

[](#charts-in-html-email-the-main-use-case)

Email clients can't fetch external images when offline, and **many (Outlook desktop, some Gmail setups) won't render inline SVG at all**. The reliable approach is a base64 **PNG** embedded directly in the markup:

```
$img = Chart::bar(['Mon' => 8, 'Tue' => 12, 'Wed' => 5, 'Thu' => 14, 'Fri' => 9])
    ->title('This week')
    ->toEmailImg(['alt' => 'Weekly activity', 'width' => 480]);

$html = "Your weekly report{$img}";
// →
```

No ``, so nothing to load — it just shows up.

Styling
-------

[](#styling)

```
use HBVSoft\ChartHandler\Spec\LegendPosition;

Chart::pie($data)
    ->size(500, 500)
    ->legend(LegendPosition::Bottom)        // None | Top | Right | Bottom | Left
    ->palette(['#4e79a7', '#f28e2b', '#e15759'])
    ->background('#ffffff')                 // or null for transparent (PNG/SVG)
    ->toPng();
```

Per-slice / per-series colors and labels are available via the lower-level `Series` / `DataPoint` value objects in `HBVSoft\ChartHandler\Spec`.

A complete example
------------------

[](#a-complete-example)

```
