Skip to main content

Charts & Data Visualization

Dashboard Laravel uses Chart.js for creating beautiful, responsive charts. The dashboard includes four main chart types: line, bar, pie, and doughnut charts for various data visualization needs.

Setup

Chart.js is loaded via CDN in the main layout file:
resources/views/layouts/app.blade.php
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
Chart.js is automatically available on all dashboard pages. No additional installation is required.

Chart Types

Dashboard Laravel implements four chart types used across different pages:

Line Chart

Used for displaying trends over time, such as monthly sales data.
resources/views/estadisticas.blade.php
<div class="card">
    <div class="card-header">
        <h5>Ventas Mensuales</h5>
    </div>
    <div class="card-body">
        <canvas id="ventasChart" height="200"></canvas>
    </div>
</div>

Bar Chart

Ideal for comparing quantities across categories, such as product sales.
resources/views/estadisticas.blade.php
new Chart(document.getElementById('productosChart').getContext('2d'), {
    type: 'bar',
    data: { 
        labels: ['Laptop','Smartphone','Auriculares','Tablet','Cámara'], 
        datasets: [{ 
            label: 'Unidades Vendidas', 
            data: [156, 342, 89, 67, 45], 
            backgroundColor: [
                'rgba(75,192,192,0.8)',
                'rgba(54,162,235,0.8)',
                'rgba(255,206,86,0.8)',
                'rgba(75,192,192,0.8)',
                'rgba(255,99,132,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        indexAxis: 'y',  // Horizontal bars
        plugins: { 
            legend: { display: false } 
        } 
    }
});
Setting indexAxis: 'y' creates horizontal bar charts, which work well for displaying ranked data like product sales.

Pie Chart

Perfect for showing percentage distribution across categories.
resources/views/estadisticas.blade.php
new Chart(document.getElementById('ingresosChart').getContext('2d'), {
    type: 'pie',
    data: { 
        labels: ['Electrónica','Accesorios','Servicios','Otros'], 
        datasets: [{ 
            data: [45, 25, 20, 10], 
            backgroundColor: [
                'rgba(75,192,192,0.8)',
                'rgba(54,162,235,0.8)',
                'rgba(255,206,86,0.8)',
                'rgba(255,99,132,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        plugins: { 
            legend: { 
                position: 'bottom' 
            } 
        } 
    }
});

Doughnut Chart

Similar to pie charts but with a center cutout, often used for demographic data.
resources/views/estadisticas.blade.php
new Chart(document.getElementById('generoChart').getContext('2d'), {
    type: 'doughnut',
    data: { 
        labels: ['Hombres','Mujeres','Otros'], 
        datasets: [{ 
            data: [55, 40, 5], 
            backgroundColor: [
                'rgba(54,162,235,0.8)',
                'rgba(255,99,132,0.8)',
                'rgba(255,206,86,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        plugins: { 
            legend: { 
                position: 'bottom' 
            } 
        } 
    }
});

Complete Page Example

Here’s a full example from the statistics page with multiple charts:
resources/views/estadisticas.blade.php
@extends('layouts.app')

@section('title', 'Estadísticas - Dashboard')
@section('nav_estadisticas', 'active')

@section('content')
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
    <h1 class="h2">Estadísticas</h1>
    <button class="btn btn-sm btn-outline-secondary">Exportar</button>
</div>

{{-- Stat Cards --}}
<div class="row mb-4">
    <div class="col-md-3">
        <div class="card text-white bg-primary mb-3">
            <div class="card-body">
                <h5 class="card-title"><i class="fas fa-users"></i> Usuarios Totales</h5>
                <p class="card-text display-6">5,432</p>
                <small class="text-white-50">+12% este mes</small>
            </div>
        </div>
    </div>
    <!-- More stat cards -->
</div>

{{-- Charts Row 1 --}}
<div class="row mb-4">
    <div class="col-md-6">
        <div class="card">
            <div class="card-header"><h5>Ventas Mensuales</h5></div>
            <div class="card-body">
                <canvas id="ventasChart" height="200"></canvas>
            </div>
        </div>
    </div>
    <div class="col-md-6">
        <div class="card">
            <div class="card-header"><h5>Género de Usuarios</h5></div>
            <div class="card-body">
                <canvas id="generoChart" height="200"></canvas>
            </div>
        </div>
    </div>
</div>

{{-- Charts Row 2 --}}
<div class="row mb-4">
    <div class="col-md-6">
        <div class="card">
            <div class="card-header"><h5>Productos Más Vendidos</h5></div>
            <div class="card-body">
                <canvas id="productosChart" height="200"></canvas>
            </div>
        </div>
    </div>
    <div class="col-md-6">
        <div class="card">
            <div class="card-header"><h5>Distribución de Ingresos</h5></div>
            <div class="card-body">
                <canvas id="ingresosChart" height="200"></canvas>
            </div>
        </div>
    </div>
</div>
@endsection

@section('scripts')
<script>
// Line Chart
new Chart(document.getElementById('ventasChart').getContext('2d'), {
    type: 'line',
    data: { 
        labels: ['Enero','Febrero','Marzo','Abril','Mayo','Junio'], 
        datasets: [{ 
            label: 'Ventas ($)', 
            data: [5000,7500,6800,9200,11500,14200], 
            borderColor: 'rgb(75,192,192)', 
            backgroundColor: 'rgba(75,192,192,0.1)', 
            tension: 0.3, 
            fill: true 
        }] 
    },
    options: { responsive: true }
});

// Doughnut Chart
new Chart(document.getElementById('generoChart').getContext('2d'), {
    type: 'doughnut',
    data: { 
        labels: ['Hombres','Mujeres','Otros'], 
        datasets: [{ 
            data: [55,40,5], 
            backgroundColor: [
                'rgba(54,162,235,0.8)',
                'rgba(255,99,132,0.8)',
                'rgba(255,206,86,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        plugins: { legend: { position: 'bottom' } } 
    }
});

// Bar Chart (Horizontal)
new Chart(document.getElementById('productosChart').getContext('2d'), {
    type: 'bar',
    data: { 
        labels: ['Laptop','Smartphone','Auriculares','Tablet','Cámara'], 
        datasets: [{ 
            label: 'Unidades Vendidas', 
            data: [156,342,89,67,45], 
            backgroundColor: [
                'rgba(75,192,192,0.8)',
                'rgba(54,162,235,0.8)',
                'rgba(255,206,86,0.8)',
                'rgba(75,192,192,0.8)',
                'rgba(255,99,132,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        indexAxis: 'y', 
        plugins: { legend: { display: false } } 
    }
});

// Pie Chart
new Chart(document.getElementById('ingresosChart').getContext('2d'), {
    type: 'pie',
    data: { 
        labels: ['Electrónica','Accesorios','Servicios','Otros'], 
        datasets: [{ 
            data: [45,25,20,10], 
            backgroundColor: [
                'rgba(75,192,192,0.8)',
                'rgba(54,162,235,0.8)',
                'rgba(255,206,86,0.8)',
                'rgba(255,99,132,0.8)'
            ] 
        }] 
    },
    options: { 
        responsive: true, 
        plugins: { legend: { position: 'bottom' } } 
    }
});
</script>
@endsection

Chart Configuration Options

Common Options

{
    responsive: true,
    maintainAspectRatio: false
}

Line Chart Options

{
    type: 'line',
    options: {
        scales: {
            y: {
                beginAtZero: true,
                ticks: {
                    callback: function(value) {
                        return '$' + value.toLocaleString();
                    }
                }
            }
        },
        elements: {
            line: {
                tension: 0.4,        // Curve smoothness (0 = straight)
                borderWidth: 2
            },
            point: {
                radius: 4,
                hoverRadius: 6
            }
        }
    }
}

Bar Chart Options

{
    type: 'bar',
    options: {
        indexAxis: 'y',              // 'x' for vertical, 'y' for horizontal
        scales: {
            x: {
                beginAtZero: true
            }
        },
        plugins: {
            legend: {
                display: false       // Hide legend for single dataset
            }
        }
    }
}

Color Schemes

Use colors from the design system for consistent branding:
const designSystemColors = {
    yellow:   'rgba(232, 212, 77, 0.8)',   // var(--card-yellow)
    pink:     'rgba(242, 167, 195, 0.8)',  // var(--card-pink)
    green:    'rgba(143, 187, 110, 0.8)',  // var(--card-green)
    blue:     'rgba(168, 200, 232, 0.8)',  // var(--card-blue)
    lavender: 'rgba(197, 184, 232, 0.8)',  // var(--card-lavender)
    peach:    'rgba(245, 184, 154, 0.8)',  // var(--card-peach)
    mint:     'rgba(143, 212, 192, 0.8)'   // var(--card-mint)
};

// Use in chart
backgroundColor: [
    designSystemColors.yellow,
    designSystemColors.pink,
    designSystemColors.green,
    designSystemColors.blue
]
Using the design system colors ensures charts match the overall dashboard aesthetic.

Dynamic Data with Laravel

Pass data from your controller to charts:

Controller

app/Http/Controllers/DashboardController.php
public function estadisticas()
{
    $ventasMensuales = [
        'labels' => ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'],
        'data' => [5000, 7500, 6800, 9200, 11500, 14200]
    ];

    return view('estadisticas', compact('ventasMensuales'));
}

View

resources/views/estadisticas.blade.php
@section('scripts')
<script>
const ventasData = @json($ventasMensuales);

new Chart(document.getElementById('ventasChart').getContext('2d'), {
    type: 'line',
    data: {
        labels: ventasData.labels,
        datasets: [{
            label: 'Ventas ($)',
            data: ventasData.data,
            borderColor: 'rgb(75,192,192)',
            backgroundColor: 'rgba(75,192,192,0.1)',
            tension: 0.3,
            fill: true
        }]
    },
    options: { responsive: true }
});
</script>
@endsection
Use @json() directive to safely pass PHP arrays to JavaScript. This escapes data properly and prevents XSS vulnerabilities.

Multiple Datasets

Compare multiple data series on a single chart:
new Chart(document.getElementById('comparisonChart').getContext('2d'), {
    type: 'line',
    data: {
        labels: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun'],
        datasets: [
            {
                label: 'Ventas 2025',
                data: [5000, 7500, 6800, 9200, 11500, 14200],
                borderColor: 'rgba(75,192,192,1)',
                backgroundColor: 'rgba(75,192,192,0.1)'
            },
            {
                label: 'Ventas 2024',
                data: [4200, 6100, 5900, 7800, 9300, 11200],
                borderColor: 'rgba(255,99,132,1)',
                backgroundColor: 'rgba(255,99,132,0.1)'
            }
        ]
    },
    options: {
        responsive: true,
        plugins: {
            legend: {
                position: 'top'
            }
        }
    }
});

Best Practices

  1. Place scripts in @section(‘scripts’): Keep chart initialization code in the scripts section
  2. Use unique canvas IDs: Each chart needs its own unique <canvas> element
  3. Set explicit height: Use height="200" on canvas for consistent sizing
  4. Enable responsive: Always set responsive: true in options
  5. Match design system: Use colors from dashboard.css variables
  6. Sanitize data: Use @json() for passing Laravel data to JavaScript
  7. Hide unnecessary legends: For single-dataset bar charts, hide the legend
  8. Format tooltips: Customize tooltips to display data appropriately (currency, percentages)

Advanced Features

Mixed Chart Types

new Chart(ctx, {
    data: {
        datasets: [
            {
                type: 'bar',
                label: 'Ventas',
                data: [10, 20, 30, 40]
            },
            {
                type: 'line',
                label: 'Objetivo',
                data: [15, 25, 35, 45]
            }
        ],
        labels: ['Q1', 'Q2', 'Q3', 'Q4']
    }
});

Custom Tooltips

options: {
    plugins: {
        tooltip: {
            callbacks: {
                label: function(context) {
                    let label = context.dataset.label || '';
                    if (label) {
                        label += ': ';
                    }
                    label += '$' + context.parsed.y.toLocaleString();
                    return label;
                }
            }
        }
    }
}

Troubleshooting

  • Ensure Chart.js is loaded before your script
  • Check that the canvas element ID matches the JavaScript selector
  • Verify the canvas is inside a visible element
  • Check browser console for JavaScript errors
  • Set explicit height attribute on canvas element
  • Use maintainAspectRatio: false in options
  • Ensure parent container has defined dimensions
  • Use chart.update() after changing data
  • Or destroy and recreate: chart.destroy(); new Chart(...)
  • Ensure backgroundColor/borderColor are properly formatted RGBA
  • Check for CSS conflicts overriding canvas styles

Resources

Next Steps

Blade Templates

Master Blade templating for building views

Design System

Explore the Soft UI design system

Build docs developers (and LLMs) love