PHPackages                             noeka/svgraph - 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. [Image &amp; Media](/categories/media)
4. /
5. noeka/svgraph

ActiveLibrary[Image &amp; Media](/categories/media)

noeka/svgraph
=============

JavaScript-free SVG chart rendering for PHP. Sparkline, line/area, bar, pie/donut, and progress charts as static markup.

0.3.0(3w ago)014↓50%[3 issues](https://github.com/noeka/svgraph/issues)[1 PRs](https://github.com/noeka/svgraph/pulls)MITPHPPHP ^8.3CI passing

Since Apr 30Pushed 3w agoCompare

[ Source](https://github.com/noeka/svgraph)[ Packagist](https://packagist.org/packages/noeka/svgraph)[ RSS](/packages/noeka-svgraph/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (4)Dependencies (7)Versions (9)Used By (0)

svgraph
=======

[](#svgraph)

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

JavaScript-free SVG chart rendering for PHP. Sparkline, line/area, bar, pie/donut, and progress charts as static markup — no canvas, no JS, no build step.

[![Hero example](docs/images/line-hero.svg)](docs/images/line-hero.svg)

- Server-side: charts render to plain SVG strings, ready to echo into a template.
- Zero JavaScript: hover tooltips, keyboard focus, and animations are pure CSS.
- Themeable: built-in light/dark themes plus a full set of CSS custom properties.
- Accessible: `role="img"` with labelled ``/``, screen-reader data table fallback, focusable points, link safety, reduced-motion aware.
- Tiny: PSR-4, no runtime dependencies.

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

[](#requirements)

- PHP 8.3+

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

[](#installation)

```
composer require noeka/svgraph
```

Quick start
-----------

[](#quick-start)

```
use Noeka\Svgraph\Chart;

echo Chart::line([
    ['Mon', 12], ['Tue', 27], ['Wed', 18], ['Thu', 41],
])->axes()->grid()->smooth()->stroke('#3b82f6');
```

Every chart is `Stringable` — cast with `(string)` or drop directly into a template with ``.

Chart gallery
-------------

[](#chart-gallery)

**[Sparkline](docs/charts/sparkline.md)**
[![sparkline](docs/images/sparkline-hero.svg)](docs/images/sparkline-hero.svg)**[Line / area](docs/charts/line.md)**
[![line](docs/images/line-hero.svg)](docs/images/line-hero.svg)**[Bar](docs/charts/bar.md)**
[![bar](docs/images/bar-hero.svg)](docs/images/bar-hero.svg)**[Pie](docs/charts/pie.md)**
[![pie](docs/images/pie-hero.svg)](docs/images/pie-hero.svg)**[Donut](docs/charts/donut.md)**
[![donut](docs/images/donut-hero.svg)](docs/images/donut-hero.svg)**[Progress](docs/charts/progress.md)**
[![progress](docs/images/progress-hero.svg)](docs/images/progress-hero.svg)Click any chart for its full options reference and worked examples.

Theming
-------

[](#theming)

```
use Noeka\Svgraph\Theme;

// Built-in dark theme
Chart::line($data)->theme(Theme::dark());

// Custom palette on top of the default theme
Chart::pie($data)->theme(
    Theme::default()->withPalette('#6366f1', '#f43f5e', '#0ea5e9', '#84cc16'),
);
```

Full reference: [docs/theming.md](docs/theming.md).

Multi-series
------------

[](#multi-series)

```
use Noeka\Svgraph\Data\Series;

Chart::line(['Jan' => 12, 'Feb' => 27, 'Mar' => 18])
    ->addSeries(Series::of('Costs', ['Jan' => 6, 'Feb' => 14, 'Mar' => 9], '#ef4444'))
    ->axes()->grid();
```

For bar charts, `->grouped()` and `->stacked()` pick how series share each x-tick. See [bar chart docs](docs/charts/bar.md#multi-series).

Legend (toggle series visibility)
---------------------------------

[](#legend-toggle-series-visibility)

```
Chart::line(['Jan' => 12, 'Feb' => 27, 'Mar' => 18])
    ->addSeries(Series::of('Costs', ['Jan' => 6, 'Feb' => 14, 'Mar' => 9]))
    ->legend();
```

Available on line and bar charts. Each legend entry is a `` bound to a hidden checkbox; clicking it hides that series and dims the entry. Pure CSS — no JavaScript.

Caveats:

- **State is page-local.** Refreshing the page resets every toggle; without JS there is nowhere to persist it.
- **Axes do not rescale.** Hiding a tall series leaves the value axis at the original combined min/max, so the remaining series stay at their original positions on the canvas.
- **Multiple charts on the same page** get unique IDs automatically, so toggling one chart never affects another.
- **Keyboard-accessible.** The `` + checkbox combo is natively focusable; pressing Space toggles the series.

Animations
----------

[](#animations)

```
Chart::pie($data)->legend()->animate();
```

All entrance animations sit inside `@media (prefers-reduced-motion: no-preference)`, so users who request reduced motion always see a static chart. Details: [docs/animations.md](docs/animations.md).

Documentation
-------------

[](#documentation)

- [Getting started](docs/getting-started.md)
- [Data formats](docs/data-formats.md) — every input shape (lists, tuples, maps, `Point`/`Series`/`Slice`/`Link`)
- [Theming](docs/theming.md) — themes, palettes, full token reference
- [Annotations](docs/annotations.md) — reference lines, threshold bands, target zones, callouts
- [Animations](docs/animations.md)
- [Accessibility](docs/accessibility.md)
- [CSS customization](docs/css-customization.md) — `.series-{N}` hooks, `--svgraph-*` properties
- [Recipes](docs/recipes.md) — Blade, Twig, email, caching
- [docs/index.md](docs/index.md) — full table of contents
- [Contributing](CONTRIBUTING.md) — developer setup, tooling, workflow

Regenerating example images
---------------------------

[](#regenerating-example-images)

The SVGs in [`docs/images/`](docs/images/) are generated from the runnable PHP scripts in [`examples/`](examples/). Rebuild them after a code change:

```
composer docs:images
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance94

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

4

Last Release

26d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2317dc2ee5bd19ddba9c1ee87f40cfb5b13a364fe31a35e1b1bd7359b81ea71d?d=identicon)[noeka](/maintainers/noeka)

---

Top Contributors

[![noeka](https://avatars.githubusercontent.com/u/22107875?v=4)](https://github.com/noeka "noeka (28 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/noeka-svgraph/health.svg)

```
[![Health](https://phpackages.com/badges/noeka-svgraph/health.svg)](https://phpackages.com/packages/noeka-svgraph)
```

###  Alternatives

[goat1000/svggraph

Generates SVG graphs

132890.0k3](/packages/goat1000-svggraph)[imagekit/imagekit

PHP library for Imagekit

46877.3k10](/packages/imagekit-imagekit)[jdenticon/jdenticon

Render PNG and SVG identicons.

62413.4k6](/packages/jdenticon-jdenticon)[gravatarphp/gravatar

Gravatar URL builder which is most commonly called as a Gravatar library

16644.1k2](/packages/gravatarphp-gravatar)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
