Di tutorial sebelumnya, kita sudah menampilkan data sederhana dari database ke grafik menggunakan Chart.js. Jika belum membaca tutorial sebelumnya tentang Menampilkan data dari database MySQL ke grafik di Laravel menggunakan Chart.js, bisa pelajari dulu agar lebih mudah memahami tutorial ini. Pada tutorial ini, kita akan menampilkan data dari tabel yang sama (sales), tetapi dengan beberapa fitur tambahan untuk membuat grafik lebih interaktif dan dinamis.

Fitur yang Akan Kita Buat:

Multiple Datasets: Menampilkan lebih dari satu set data pada grafik, misalnya menampilkan penjualan produk per bulan.

Filter Grafik Berdasarkan Rentang Waktu: Membuat filter untuk menampilkan data berdasarkan bulan atau tahun tertentu.

Dynamic Loading dengan AJAX: Memuat data secara dinamis tanpa perlu refresh halaman.

Langkah 1: Install Laravel dan Setup Database (Jika Belum Ada)

Jika Anda sudah mengikuti tutorial sebelumnya, Anda sudah memiliki model Sale dan tabel sales dengan data penjualan. Jika belum, ikuti langkah berikut untuk setup dasar Laravel dan database.

composer create-project --prefer-dist laravel/laravel laravel-chart
php artisan make:model Sale -m

Langkah 2: Update Tabel sales dengan Kolom month dan year

Kita perlu menambahkan kolom month dan year di tabel sales agar bisa memfilter data penjualan berdasarkan bulan dan tahun. Tambahkan kolom ini di migration:

public function up()
{
    Schema::create('sales', function (Blueprint $table) {
        $table->id();
        $table->string('product_name');
        $table->integer('quantity');
        $table->integer('month'); // Tambahkan kolom bulan
        $table->integer('year');  // Tambahkan kolom tahun
        $table->timestamps();
    });
}

Setelah itu, jalankan perintah migrasi:

php artisan migrate

Langkah 3: Isi Data Penjualan Secara Dinamis

Sekarang kita tambahkan data penjualan ke tabel sales untuk beberapa bulan dan tahun yang berbeda. Gunakan seeder atau isi data secara manual di database. Buat seeder dengan perintah 

php artisan make:seeder SalesTableSeeder

Isi data dummy di SalesTableSeeder.php

use App\Models\Sale;
use Illuminate\Database\Seeder;

class SalesTableSeeder extends Seeder
{
    public function run()
    {
        // Data untuk tahun 2023
        Sale::create(['product_name' => 'Product A', 'quantity' => 100, 'month' => 1, 'year' => 2023]);
        Sale::create(['product_name' => 'Product B', 'quantity' => 80, 'month' => 2, 'year' => 2023]);
        Sale::create(['product_name' => 'Product C', 'quantity' => 90, 'month' => 1, 'year' => 2023]);

        // Data untuk tahun 2024
        Sale::create(['product_name' => 'Product A', 'quantity' => 120, 'month' => 1, 'year' => 2024]);
        Sale::create(['product_name' => 'Product B', 'quantity' => 100, 'month' => 2, 'year' => 2024]);
        Sale::create(['product_name' => 'Product C', 'quantity' => 110, 'month' => 1, 'year' => 2024]);
    }
}

Jalankan seeder:

php artisan db:seed --class=SalesTableSeeder

Langkah 4: Buat Route untuk Filter Data dan Grafik

Tambahkan route untuk menampilkan halaman chart dan API yang akan digunakan untuk memfilter data dengan AJAX di routes/web.php:

use App\Http\Controllers\ChartController;

Route::get('/chart', [ChartController::class, 'index'])->name('chart.index');
Route::get('/chart/data', [ChartController::class, 'getData'])->name('chart.data');

Langkah 5: Buat Controller untuk Menangani Filter dan Fetch Data

Buka ChartController.php dan tambahkan logika untuk mengambil data dari database berdasarkan filter waktu:

namespace App\Http\Controllers;

use App\Models\Sale;
use Illuminate\Http\Request;

class ChartController extends Controller
{
    public function index()
    {
        return view('chart');
    }

    // Fetch data untuk grafik berdasarkan filter waktu
    public function getData(Request $request)
    {
        $year = $request->input('year', date('Y')); // Default ke tahun ini
        $month = $request->input('month'); // Bulan bisa null untuk mengambil semua bulan
        
        // Ambil data dari tabel sales
        $query = Sale::where('year', $year);
        if ($month) {
            $query->where('month', $month);
        }

        $sales = $query->get();
        
        // Mengelompokkan data berdasarkan produk
        $groupedSales = $sales->groupBy('product_name');
        $datasets = [];
        foreach ($groupedSales as $productName => $sales) {
            $datasets[] = [
                'label' => $productName,
                'data' => $sales->pluck('quantity'),
                'backgroundColor' => $this->getRandomColor(),
            ];
        }

        // Kembalikan data untuk Chart.js
        return response()->json([
            'labels' => $sales->pluck('month')->unique(), // Label berupa bulan
            'datasets' => $datasets,
        ]);
    }

    // Fungsi untuk mendapatkan warna acak
    private function getRandomColor()
    {
        $colors = ['rgba(75, 192, 192, 0.2)', 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)'];
        return $colors[array_rand($colors)];
    }
}

Langkah 6: Buat View untuk Menampilkan Grafik dengan Filter

Buat file resources/views/chart.blade.php. Di file ini, kita akan menambahkan form untuk memfilter data dan menggunakan AJAX untuk memuat data ke grafik tanpa refresh halaman:

@extends('layout')

@section('title', 'Sales Chart with Filter')

@section('content')
<div class="container mt-5">
    <h2 class="mb-4">Sales Data with Filter</h2>

    <!-- Filter Form -->
    <form id="filter-form">
        <div class="form-row">
            <div class="col-md-4 mb-3">
                <label for="year">Year</label>
                <select class="form-control" id="year" name="year">
                    <option value="2023">2023</option>
                    <option value="2024">2024</option>
                </select>
            </div>
            <div class="col-md-4 mb-3">
                <label for="month">Month</label>
                <select class="form-control" id="month" name="month">
                    <option value="">All</option>
                    <option value="1">January</option>
                    <option value="2">February</option>
                </select>
            </div>
            <div class="col-md-4 mb-3">
                <button type="submit" class="btn btn-primary mt-4">Apply Filter</button>
            </div>
        </div>
    </form>

    <!-- Canvas untuk Chart.js -->
    <canvas id="salesChart" width="400" height="200"></canvas>
</div>

<!-- Script Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>

<script>
    var $jq = jQuery.noConflict();

    $jq(document).ready(function() {
        // Fungsi untuk memuat data grafik dari server
        function loadChartData(year, month) {
            $jq.ajax({
                url: "{{ route('chart.data') }}",
                method: 'GET',
                data: { year: year, month: month },
                success: function(data) {
                    var ctx = document.getElementById('salesChart').getContext('2d');
                    
                    // Periksa jika chart sudah ada, lalu hilangkan
                    if (window.salesChart instanceof Chart) {
                        window.salesChart.destroy();
                    }

                    // Buat chart baru
                    window.salesChart = new Chart(ctx, {
                        type: 'bar',
                        data: {
                            labels: data.labels, // Bulan
                            datasets: data.datasets, // Dataset produk
                        },
                        options: {
                            scales: {
                                y: {
                                    beginAtZero: true
                                }
                            }
                        }
                    });
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.error('AJAX error:', textStatus, errorThrown);
                }
            });
        }

        // Muat data awal
        loadChartData($jq('#year').val(), $jq('#month').val());

        // Event listener untuk form filter
        $jq('#filter-form').submit(function(e) {
            e.preventDefault();
            loadChartData($jq('#year').val(), $jq('#month').val());
        });
    });
</script>

@endsection

Dan buat file layout.blade.php di halaman views dan tambahkan code berikut:
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'CRUD Posts')</title>

    <!-- Tambahkan Bootstrap CSS atau styling lainnya -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>

    <!-- Navbar -->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="{{ route('posts.index') }}">My Blog</a>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="{{ route('chart.index') }}">Chart</a>
                </li>
            </ul>
        </div>
    </nav>

    <!-- Main Content -->
    <div class="container mt-5">
        @if (session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @yield('content')
    </div>

    <!-- Tambahkan Bootstrap JS atau script lainnya -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>

Langkah 7: Uji Aplikasi

Jalankan server Laravel:

php artisan serve

Akses halaman grafik di browser Anda:

http://localhost:8000/chart

Sekarang Anda akan melihat grafik penjualan yang lebih kompleks dengan fitur multiple datasets untuk beberapa produk, filter berdasarkan bulan dan tahun, serta data yang dimuat secara dinamis menggunakan AJAX.

Jika berhasil step by stepnya, maka akan menghasilkan sebagai berikut: