A Laravel charting data visualization library built on top of strucura/visualizations. Define your chart series as typed datasets backed by raw SQL expressions, expose them as API endpoints, and let your front-end render them with any chart library.
composer require strucura/charts| Concept | Description |
|---|---|
| Chart | Defines the base query, labels, and datasets (series) that are selected from it. Exposes schema and data endpoints. |
| Label | A grouping or axis field within a chart (e.g. dates, categories). Extends Visualizable. Use NullLabel for charts that have no label axis. |
| Dataset | A single named series within a chart. Extends Visualizable, so it carries a SQL select expression, supports filtering and sorting, and serializes to a typed schema. |
Use the Artisan generator to scaffold a new chart:
php artisan make:chart RevenueChartThis creates app/Charts/RevenueChart.php:
use Strucura\Charts\Abstracts\Chart;
use Strucura\Charts\Labels\Label;
use Strucura\Charts\Datasets\Bar;
class RevenueChart extends Chart
{
public function getLabel(): Label
{
return Label::make('order_date', 'date');
}
public function getDatasets(): Collection
{
return collect([
Bar::make('SUM(total)', 'revenue')->header('Revenue'),
Bar::make('SUM(refunds)', 'refunds')->header('Refunds'),
]);
}
public function getQuery(): Builder
{
return DB::table('orders')
->groupBy('order_date');
}
}Register chart routes in your routes/api.php (or any route file) using the chart route macro:
Route::chart(RevenueChart::class);This registers two endpoints automatically:
| Method | Path | Name | Description |
|---|---|---|---|
POST |
/charts/revenues/schema |
charts.revenues.schema |
Returns the chart schema (dataset definitions) |
POST |
/charts/revenues/data |
charts.revenues.data |
Returns the chart data, with optional filters and sorts |
The route path and name are derived from the class name. RevenueChart → /charts/revenues.
POST /charts/revenues/schema
{
"chart_key": "charts.revenues",
"label": { "field": "date", "header": "date", "meta": {} },
"datasets": [
{ "field": "revenue", "header": "Revenue", "type": "bar", "meta": {} },
{ "field": "refunds", "header": "Refunds", "type": "bar", "meta": {} }
]
}POST /charts/revenues/data
Optional request body:
{
"filter_sets": [
{
"filter_set_operator": "and",
"filters": [
{ "field": "date", "value": "2024-01-01", "filter_operator": "gte" }
]
}
],
"sorts": [
{ "field": "date", "sort_operator": "asc" }
]
}Response is an array of objects, one per row from the query:
[
{ "date": "2024-01-01", "revenue": 12000, "refunds": 300 },
{ "date": "2024-01-02", "revenue": 14500, "refunds": 150 }
]| Class | type value |
Extra methods |
|---|---|---|
Line |
line |
tension(float), filled() |
Bar |
bar |
stacked(), stackGroup(string) |
Area |
area |
tension(float) |
Pie |
pie |
— |
Doughnut |
doughnut |
cutout(string) |
Scatter |
scatter |
— |
All dataset types share the inherited Visualizable API:
Bar::make('SUM(total)', 'revenue')
->header('Total Revenue') // display label
->meta('color', '#4ade80'); // arbitrary front-end configImplement getPermissionName() on your chart class to gate both endpoints via Laravel's Gate::authorize():
public function getPermissionName(): string
{
return 'view-revenue-chart';
}Override getRoutePrefix(), getRouteName(), or getRoutePath() to take full control of the generated routes:
public function getRoutePrefix(): string
{
return 'reporting';
}composer testPlease see CHANGELOG for information on recent changes.
The MIT License (MIT). Please see License File for more information.