hecht-a/ux-echarts
Laravel package that brings Apache ECharts into Blade views with a fluent PHP API. Build interactive line, bar, pie, and other charts from arrays or Eloquent data without writing JavaScript. Configurable themes, responsive rendering, and simple asset registration make it a drop-in fit for dashboards...
First, a framing correction that matters more than any install step: this is a Symfony UX bundle, not a Laravel package. hecht-a/ux-echarts ships a Symfony bundle, a Twig extension (render_echarts()), and a Stimulus controller — there is no service provider, no config/echarts.php, no facade. A Laravel developer should approach it in one of two ways:
composer require hecht-a/ux-echarts, enable the bundle, npm i echarts) and use it natively. Laravel and Symfony apps in the same shop can share the same ECharts option schema via a JSON endpoint.echarts.init() + setOption()." Reproduce that pattern in Laravel with a plain JSON endpoint and Alpine/Livewire.Where to look first: the README's chart examples and the Echarts PHP object/EchartsInterface. Those define the option schema you'll mirror in Laravel. Ignore the Twig/Stimulus plumbing — it doesn't port.
First use case (Laravel translation):
// app/Http/Controllers/ChartController.php
public function sales(): JsonResponse
{
return response()->json([
'tooltip' => ['trigger' => 'axis'],
'xAxis' => ['type' => 'category', 'data' => ['Mon', 'Tue', 'Wed']],
'yAxis' => ['type' => 'value'],
'series' => [['type' => 'bar', 'data' => [120, 200, 150]]],
]);
}
<div x-data="echarts(@js(route('chart.sales')))" x-ref="chart" style="height:400px"></div>
Chart-as-DTO. Follow the package's lead: don't scatter option arrays through controllers. Create one class per chart (SalesChart, LatencyHeatmap) that returns a plain array option payload. This makes charts testable by asserting JSON structure, and lets Blade, Inertia, and API consumers share one definition.
Endpoint + init pattern. The bundle's Stimulus controller is doing exactly three things: import * as echarts from 'echarts', echarts.init(el), chart.setOption(option). Mirror that in a small Alpine component or a resources/js/echarts.js module:
export default (url) => ({
chart: null,
async init() {
const option = await (await fetch(url)).json();
this.chart = echarts.init(this.$refs.chart);
this.chart.setOption(option);
new ResizeObserver(() => this.chart.resize()).observe(this.$refs.chart);
},
});
Livewire integration. When filters change, don't re-render the canvas — dispatch the new option payload and call setOption(option, { notMerge: true }) on the existing instance. Rendering the <div> inside a Livewire component means morphdom replaces the DOM node and your echarts.init handle points at a dead element.
Bundle size. ECharts full build is ~1MB. Use tree-shaken imports (echarts/core + only the charts/components you use) — the Symfony bundle can't do this for you, and it's the single biggest production concern for a dashboard app.
Testing. Assert the option array your DTO produces (axis types, series counts, units, formatting) in a PHPUnit feature test on the JSON endpoint. Never assert on canvas pixels.
height: 100% on a parent with no height renders nothing. Set style="height:400px" or use aspect-ratio.setOption merge semantics. Default is merge, which is usually what you want for incremental updates but not when series count shrinks — old series linger. Use { notMerge: true } for filter-driven redraws, or { replaceMerge: ['series'] } for targeted replacement.series type or a null in data yields a blank canvas with no console error. console.log(JSON.stringify(option)) first, then paste into the ECharts online editor to isolate PHP-side bugs from JS-side ones.ResizeObserver (better than window.resize, which misses sidebar collapses) and dispose() the instance on component teardown to avoid leaks in SPAs/Livewire.getDataURL() server-side via Node, or render a table fallback — don't expect the Symfony bundle (or any PHP ECharts wrapper) to solve this.EchartsInterface lets you swap the chart factory. In Laravel the equivalent is binding a ChartRenderer contract so you can swap ECharts for Chart.js without touching controllers.How can I help you explore Laravel packages today?