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

Flot Bundle Laravel Package

jasonroman/flot-bundle

A Symfony bundle for building Flot JavaScript charts: construct datasets and options in PHP, then render them in Twig templates with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before anything else: jasonroman/flot-bundle is a Symfony2 bundle. There is no service provider, no facade, no config/*.php to publish, no illuminate/* constraint. Do not composer require it into a Laravel app — its composer.json pins the Symfony ~2.x stack, which will either fail resolution or drag Laravel's symfony/* components down with it. Use it as a reference implementation, not a dependency.

What the bundle actually gives you (the parts worth reading):

  1. A DI extension + config tree (DependencyInjection/) — a config alias with default chart options you can override per-env.
  2. A Twig extension — the whole reason the bundle existed. It takes a PHP array of series + options and returns markup: a placeholder <div id="…"> plus an inline $.plot(...) initialiser.
  3. Asset wiring — registers Flot JS/CSS (and its jQuery dependency) through the Symfony asset pipeline.
  4. A default Twig template in Resources/views/ — the ~20 lines that generate the HTML and script block.

Where to look first (as a Symfony2 maintainer):

  • Resources/views/ — the template that emits the chart div + $.plot call. This is the actual product surface.
  • The Twig extension class — see how it normalises incoming series and options arrays before rendering; that normalisation is the logic you'll re-implement.
  • DependencyInjection/Configuration.php — the config alias and default options worth mirroring.
  • composer.json — confirms the Symfony constraint and which Flot version the vendored assets correspond to.

First use case — day-to-day in the legacy Symfony2 app:

A reporting page that renders a daily-signups line chart. Route/controller returns a small array of [x => timestamp, y => count] data points. Template calls the bundle's Twig function with that data plus axis options; the helper emits a <div> and the inline script that calls $.plot(). That's the entire developer loop: controller returns data → Twig helper renders chart → asset pipeline ships jQuery + Flot. If your team lives in that loop, the bundle saves you the boilerplate — that's the only scenario where it earns its keep.

First use case — porting the pattern to Laravel:

  1. Create a Blade component resources/views/components/flot-chart.blade.php that renders <div id="{{ $id }}" data-points='@json($points)' data-options='@json($options)'></div>.
  2. Ship Flot via npm (flot is still on npm) or a CDN, not via the bundle.
  3. Load a tiny ES module that finds [data-points] elements and calls $.plot() on each — this replaces the Twig extension.
  4. Pass chart data as a JSON endpoint (/reports/signups) so you can refresh without a full page reload.

That is the honest day-to-day value of this package for a Laravel dev: a canonical example of how not to couple chart rendering to a PHP templating layer, and a working reference you can extract the JS shape from.

Implementation Patterns

Pattern 1 — Twig helper with a data array (the classic Symfony2 flow). The bundle's Twig function takes a series array ([[x, y], …]), an options array (axes, legend, grid, tooltip), and returns a <div> + $.plot('#chart', data, options) block. The pattern to internalise is "data in, markup out" — the PHP layer never touches the browser, it just serialises. Copy that shape, don't copy the implementation.

Pattern 2 — Config-driven defaults, overrides per chart. The bundle merges bundle-level config defaults (grid, colours, axis styling) with per-call options. In Laravel this becomes config/charts.php with a defaults array deep-merged (array_replace_recursive) against per-view options, so individual charts overrides only what they care about.

Pattern 3 — AJAX/refresh without re-rendering the page. Flot is designed for $.plot() to be called again on the same container to update it. Expose the series data behind a JSON endpoint:

Route::get('/reports/signups', fn () => Signup::daily()->get(['day', 'count']));

Blade mounts the div once; the JS module polls or re-fetches and re-calls $.plot(). Note that the original bundle cannot do this — it only renders on server response. This is where the bundle's design shows its age and where you get real day-to-day value by skipping it.

Pattern 4 — Blade component + JSON payload (Laravel-native equivalent of the Twig helper).

{{-- resources/views/components/flot-chart.blade.php --}}
<div wire:ignore id="{{ $id }}" class="flot-chart"
     data-series='@json($series)' data-options='@json($options)'></div>
// app/View/Components/FlotChart.php
class FlotChart extends Component {
    public function __construct(
        public string $id,
        public array $series,
        public array $options = []
    ) { $this->options = array_replace_recursive(config('charts.defaults'), $options); }
    public function render() { return view('components.flot-chart'); }
}

Mount with <x-flot-chart id="signups" :series="$series" :options="['yaxis'=>['min'=>0]]" />. This is the direct translation of the bundle's Twig extension, minus the Symfony coupling.

Pattern 5 — Asset inclusion without the bundle. Install Flot via npm (npm i flot jquery) and import in resources/js/app.js:

import $ from 'jquery';
import 'flot';
import 'flot/source/jquery.flot.time';
// …
$('[data-series]').each(function () {
    const el = this;
    $.plot($(el), JSON.parse(el.dataset.series), JSON.parse(el.dataset.options));
});

This is the day-to-day workflow you actually want — Vite handles bundling, tree-shaking, hashing, and CSP nonces; the bundle's Assetic-era asset pipeline handles none of this.

Pattern 6 — Migration bridge for a legacy Symfony2 tenant. If an existing Symfony2 app already uses the bundle, the safe pattern is:

  1. Keep the Twig helper rendering as-is (no behaviour change).
  2. Add a parallel JSON controller for chart data.
  3. Add a small JS entry that can re-render a chart from the JSON endpoint, keyed by the same element id the helper emits.
  4. Switch views over one at a time from server-rendered to JSON-driven.
  5. Retire the Twig helper once all views are switched.

You get zero-downtime migration and can freeze the Flot version at its current point while you plan the eventual replacement.

Gotchas and Tips

Don't try to install it in Laravel. Even with --ignore-platform-reqs you'll get an AppKernel-shaped bundle that expects a Symfony kernel to bootstrap. There is no shim worth writing. If someone on the team asks "can we just use this?", the correct answer is "we can copy the 20 lines of JS out of it, but not the package."

The Flot version bundled is old. Flot's last real release was ~2014. Later minor patches exist but there is no active maintenance. Pin the exact version you vendor in package.json and document why. Do not npm update Flot casually — some plugins (jquery.flot.time, jquery.flot.pie) have version-coupling bugs.

jQuery is a hard dependency, and a global one. Flot attaches to $. If your Laravel app is jQuery-free, adding Flot adds ~30kB gzipped. If your app already uses jQuery via another package, verify versions — Flot expects a fairly modern jQuery but has been known to break against jQuery 4.x betas. Check $.fn.plot is defined in the browser console before hunting for logic bugs.

CSP. The bundle emits inline <script> tags. If you adopt any pattern derived from it, keep the $.plot() call in an external module and pass data via data-* attributes (as shown in Pattern 4). Inline scripts will trip a strict script-src policy and you'll waste half a day on nonce plumbing otherwise.

Data format is easy to get wrong. Flot series are { label: 'x', data: [[ts, value], …] }. If you pass a flat array you'll get a silent empty chart. If you pass strings instead of numbers for timestamps you'll get a chart with no axes rendered and no error. Log the parsed series in the console on first mount of any new chart type.

Time axes need the extra plugin. xaxis: { mode: 'time' } silently does nothing unless jquery.flot.time is imported before $.plot() runs. This is the single most common "why is my date axis broken" report in a Flot codebase. Import order in your Vite entry matters.

Retina / high-DPI looks soft. Flot renders to a canvas at CSS-pixel resolution by default. The bundle's era predates the common devicePixelRatio fix; expect fuzzy text on modern laptops unless you implement the ratio-scaling trick yourself.

Large datasets stall the main thread. Flot is unoptimised past a few thousand points per series. For high-cardinality dashboards, downsample server-side before sending the payload (e.g. ->take(500) with bucketing) — do not expect Flot to handle it gracefully.

Extension points to know, if you're stuck maintaining a fork.

  • The Twig extension class is the single seam: overriding it in your bundle (higher priority) lets you change normalisation without touching vendor code.
  • The Resources/views/ template can be overridden per-app by placing an identically named template in your app's Twig path — this is the practical way to change the emitted markup without forking.
  • Config defaults live under a single alias in DependencyInjection/Configuration.php; add keys there if you need per-env tuning.

Debugging checklist when a chart renders blank.

  1. Browser console — any jQuery/Flot import errors?
  2. $('#chart').width() — a zero-width container (hidden tab, flexbox not yet laid out) means Flot draws nothing. Render after the element has dimensions, or call $.plot() on tab activation.
  3. Series parsed correctly? console.log(JSON.parse(el.dataset.series)).
  4. Options valid? A typo like xaxisss is silently ignored.
  5. Date/time plugin loaded?

Version pinning is your friend. If you inherit a legacy Symfony2 app, pin the bundle and Flot versions in composer.json / package.json and add a comment with the migration ticket number. Without that, a well-meaning dependency-bump PR will silently change chart output and you'll be bisecting commits for a customer-visible regression.

Treat the repo as documentation, not code. Its value to a Laravel team is the ~20 lines of $.plot() boilerplate and the shape of the series/options contract. Copy the shape, own the code. Do not fork — 0 stars, 0 dependents means every bug you hit is yours to fix with no upstream and no Stack Overflow corpus behind you.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console