Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sparkline Laravel Package

davaxi/sparkline

davaxi/sparkline is a lightweight PHP library for generating compact sparkline charts from numeric data. It offers customizable dimensions, colors, and image output, making it easy to add small inline trend visualizations to Laravel or any PHP app.

Deep Wiki
Context7

Getting Started

davaxi/sparkline is a single-class, GD-based PNG renderer for tiny line charts. There is no service provider, config file, facade, or Blade component — you instantiate Davaxi\Sparkline yourself and feed it an array of numbers.

Install and verify the only hard dependency:

composer require davaxi/sparkline
php -m | grep -i gd   # must be present; install php-gd if not

Where to look first:

  1. vendor/davaxi/sparkline/README.md — the entire public API is documented there.
  2. vendor/davaxi/sparkline/src/Sparkline.php — one class; read setData(), generate()/show(), save(), and the color/alpha setters to confirm method names for your pinned version.
  3. Any tests shipped in the package — they show the expected data shapes and edge cases.

First use case — a trend column on a dashboard. Generate a 200×40 PNG from the last 30 days of an Eloquent aggregate and return it from a route:

use Davaxi\Sparkline;

Route::get('/metrics/orders/sparkline', function () {
    $values = Order::query()
        ->where('created_at', '>=', now()->subDays(30))
        ->selectRaw('DATE(created_at) as day, COUNT(*) as total')
        ->groupBy('day')
        ->orderBy('day')
        ->pluck('total')
        ->map(fn ($v) => (float) $v)
        ->all();

    $sparkline = new Sparkline();
    $sparkline->setWidth(200);
    $sparkline->setHeight(40);
    $sparkline->setPadding(2);
    $sparkline->setLineThickness(2);
    $sparkline->setLineColor('#2563eb');
    $sparkline->setFillColor('#2563eb', 0.2);
    $sparkline->setBackgroundColor('#ffffff');
    $sparkline->setData($values);

    $png = $sparkline->generate();

    return response($png, 200, [
        'Content-Type' => 'image/png',
        'Content-Length' => strlen($png),
        'Cache-Control' => 'public, max-age=300',
    ]);
});

If your installed version does not expose a binary-returning method, use save() to a temp path and read it back, or show() behind output buffering — but prefer generate()/save() inside Laravel so the framework owns the response headers.

Implementation Patterns

Wrap it in one application service. Do not scatter new Sparkline() calls across controllers and Blade files. Put defaults (dimensions, palette, padding, thickness) in config/sparkline.php and expose a single renderer:

namespace App\Support;

use Davaxi\Sparkline;

class SparklineRenderer
{
    public function png(array $values, array $overrides = []): string
    {
        $o = array_merge(config('sparkline.defaults'), $overrides);

        $sparkline = new Sparkline();
        $sparkline->setWidth($o['width']);
        $sparkline->setHeight($o['height']);
        $sparkline->setPadding($o['padding']);
        $sparkline->setLineThickness($o['thickness']);
        $sparkline->setLineColor($o['line_color']);
        $sparkline->setFillColor($o['fill_color'], $o['fill_alpha']);
        $sparkline->setBackgroundColor($o['background']);
        $sparkline->setData($this->normalize($values));

        return $sparkline->generate();
    }

    private function normalize(array $values): array
    {
        $values = array_values(array_filter($values, 'is_numeric'));
        return array_map('floatval', $values);
    }
}

This gives you one place to change brand colors, add caching, or swap the renderer later.

Inline base64 for dashboard pages. A dashboard with 20 sparklines should not fire 20 additional HTTP requests. Render server-side and embed data URIs:

function sparkline_data_uri(array $values, array $opts = []): string
{
    $png = app(SparklineRenderer::class)->png($values, $opts);
    return 'data:image/png;base64,' . base64_encode($png);
}
<img src="{{ sparkline_data_uri($values, ['line_color' => '#16a34a']) }}"
     width="200" height="40" alt="30-day trend">

Cache the rendered PNG, not just the query. GD rendering and base64 encoding are cheap per image but add up across a dashboard. Key on the data hash and styling so style changes invalidate correctly:

$key = 'sparkline:' . md5(serialize([$values, $options]));

$png = Cache::remember($key, now()->addMinutes(10), fn () =>
    app(SparklineRenderer::class)->png($values, $options)
);

For routes, add a cache-busting query string (?v={{ $lastUpdated->timestamp }}) and keep long Cache-Control headers.

Prepare data as a normalized, ordered numeric series. The class plots values left-to-right and auto-scales between the series min and max. There is no date axis, so gaps in your aggregate must be filled in PHP (zero-fill missing days) or the x-axis will be misleading. Cast database pluck() results to float — MySQL often returns aggregates as strings.

One sparkline per series. The package draws a single line; there is no multi-series API. For comparisons, render two images side by side or stack them with a shared legend in HTML.

Saving to disk for exports or queued jobs. Use save() with an absolute path under storage_path():

$sparkline->save(storage_path('app/reports/orders-sparkline.png'));

Create the directory first and ensure the web/queue user can write to it.

Testing. Do not assert exact bytes — GD output can differ across GD versions. Assert the PNG signature and decode dimensions:

$png = app(SparklineRenderer::class)->png([1, 4, 2, 8]);

$this->assertStringStartsWith("\x89PNG\r\n\x1a\n", $png);
$this->assertSame([200, 40], array_slice(getimagesizefromstring($png), 0, 2));

Also test your normalizer: empty input, one value, flat series, numeric strings, and nulls.

Compose with Laravel HTTP responses rather than show(). show() sends Content-Type: image/png and echoes to the output buffer, which conflicts with Laravel middleware, response caching, and test assertions. Return the binary through response().

Gotchas and Tips

  • GD is mandatory and not always installed. ext-gd with PNG support must be compiled in. CI containers and minimal PHP images frequently omit it; add an explicit platform requirement in composer.json.
  • show() sends headers directly. Calling it after any output (including a stray newline or debug dump()) produces "headers already sent" warnings and corrupt images. In Laravel, use generate() or save() and return a response.
  • API names vary by version. Depending on the release, the binary-output method may be generate(), show(), or only save(). Pin the version in composer.json and confirm against src/Sparkline.php; this package is small and low-activity, so don't assume the README matches the installed tag.
  • Empty or single-point data can break rendering. A one-value series gives no line, and a completely flat series can cause a division-by-zero when scaling. Guard in your wrapper: duplicate a single value, or return null and render a placeholder.
  • Padding is in pixels on all sides. If 2 * padding >= height (or width), the drawable area collapses. Keep padding small relative to the requested size.
  • Alpha conventions are easy to get wrong. The color setters take a hex color plus a separate alpha argument. Confirm whether that argument is a 0–1 float or GD's 0–127 integer for your version, and never pass rgba() CSS strings. Pass plain hex (#2563eb), not named colors.
  • Raster only — no SVG, no labels, no tooltips. Generate at 2× dimensions and downscale with CSS width/height for crisp HiDPI output. Don't try to use this as a general charting library; it has no axes, legends, or hover behavior.
  • Auto-scaling does not start at zero. A series hovering around 90–100 will look as dramatic as one swinging 0–100. If visual honesty matters, include a zero baseline in the data or choose a different chart.
  • Downsample before rendering. More points than pixels adds cost without visible detail, and very wide images consume more GD memory. Aggregate to roughly the pixel width.
  • GD images are uncompressed in memory. Rendering dozens of large sparklines in one request can hit memory_limit. Keep images small and cache aggressively; never render a sparkline inside a loop over thousands of records.
  • No Laravel integration ships with it. There is no facade, config publish, or Blade directive. The wrapper service above is your extension point — it is also where you would swap in a different library if maintenance becomes a concern.
  • save() requires a real, writable path. Relative paths resolve against the process working directory, which differs between FPM, queue workers, and tests. Always use storage_path().
  • Cache keys must include styling. If the key only hashes the data, a palette change will keep serving old colors until the TTL expires.
  • Keep the data contract narrow. Accept array<int, int|float> in your renderer, reject or filter everything else. Letting strings with thousands separators ("1,204") reach setData() produces silently wrong charts.
  • Low maintenance signal. With ~70 stars and a single-purpose codebase, treat it as a vendored utility: pin the version, wrap it, and keep the rendering surface small so replacement is a one-file change.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin