Milk Admin

ChartBuilder

The ChartBuilder class creates charts from database queries and integrates with the same filtering system used by tables and lists. It extends GetDataBuilder, but it does not paginate or limit results, so charts can aggregate the full dataset.

System Overview

ChartBuilder simplifies chart rendering by providing:

  • Query-driven charts: Use the fluent GetDataBuilder API to filter and aggregate
  • Structured datasets: Define axes and datasets with structure()
  • Chart.js integration: Render bar, line, pie, table, and other chart types
  • AJAX updates: getResponse() returns chart payloads for live updates
  • No pagination: The full query result is used to build the chart

Basic Usage

Quick Start

use Builders\ChartBuilder;

$chart = ChartBuilder::create($this->model, 'orders_chart')
    ->select(['month', 'SUM(total) AS total'])
    ->groupBy('month')
    ->orderBy('month', 'ASC')
    ->structure([
        'month' => ['label' => 'Month', 'axis' => 'x'],
        'total' => ['label' => 'Total', 'type' => 'bar'],
    ])
    ->type('bar')
    ->render();

echo $chart;

Structure Mapping

structure() maps fields from the SQL result to chart axes and datasets. You must define exactly one X axis; all other fields become datasets.

$chart = ChartBuilder::create($this->model, 'sales_chart')
    ->select(['month', 'SUM(total) AS total', 'COUNT(id) AS orders'])
    ->groupBy('month')
    ->orderBy('month', 'ASC')
    ->structure([
        'month' => ['label' => 'Month', 'axis' => 'x'],
        'total' => [
            'label' => 'Total',
            'type' => 'bar',
            'backgroundColor' => '#9BD0F5',
            'borderColor' => '#36A2EB',
            'borderWidth' => 1,
        ],
        'orders' => ['label' => 'Orders', 'type' => 'line'],
    ]);

Chart Options

Use options() or option() to pass Chart.js options or plugin-specific settings (like height or legend positioning).

$chart = ChartBuilder::create($this->model, 'orders_chart')
    ->option('height', 320)
    ->option('legend_position', 'bottom')
    ->option('show_datalabels', 'percent');

Using Filters with SearchBuilder

ChartBuilder uses the same filter system as tables. Filter names must match between SearchBuilder and ChartBuilder.

use Builders\ChartBuilder;
use Builders\SearchBuilder;
use App\Response;

$chart_id = 'orders_chart';

$chart = ChartBuilder::create($this->model, $chart_id)
    ->setRequestAction('home')
    ->select(['month', 'SUM(total) AS total'])
    ->filter('status_filter', function($query, $value) {
        $query->where('status = ?', [$value]);
    })
    ->groupBy('month')
    ->orderBy('month', 'ASC')
    ->structure([
        'month' => ['label' => 'Month', 'axis' => 'x'],
        'total' => ['label' => 'Total', 'type' => 'bar'],
    ]);

$search = SearchBuilder::create($chart_id)
    ->select('status_filter')
        ->label('Status')
        ->options([
            '' => 'All',
            'paid' => 'Paid',
            'pending' => 'Pending',
        ])
        ->layout('inline');

$response = array_merge($this->getCommonData(), $chart->getResponse());
$response['search_html'] = '';
$response['bottom_content'] = $search->render();

Response::render(MILK_DIR . '/Theme/SharedViews/list_page.php', $response);

Chart Tables

You can render a table from the same chart data. Set type to table and disable pagination with itemsPerPage = 0.

$data = $chart->getChartData();

echo Get::themePlugin('chart', [
    'id' => 'orders_table',
    'type' => 'table',
    'data' => $data,
    'options' => [
        'preset' => 'hoverable',
        'itemsPerPage' => 0,
    ],
]);

AJAX Response

ChartBuilder::getResponse() returns an array with html and chart keys so the frontend can update the chart without a full page reload.

$response = $chart->getResponse();

// $response['html'] contains the chart wrapper
// $response['chart'] contains { id, type, data, options }

Multiple Charts on One Page

If you render multiple charts in the same view, set a custom canvas id so Chart.js instances do not collide.

$chart = ChartBuilder::create($this->model, 'orders_chart')
    ->setCanvasId('orders_chart_canvas')
    ->render();
Loading...