Documentation

Charts & Data Visualization

Charts & Data Visualization

UltraViolet Pro includes comprehensive charting capabilities using ApexCharts and Chart.js for creating interactive, responsive data visualizations.

Overview

The dashboard supports two powerful charting libraries:

  • ApexCharts: Modern, interactive charts with advanced features
  • Chart.js: Lightweight, flexible charting library

Both libraries are fully integrated and styled to match the UltraViolet theme.

ApexCharts

ApexCharts is the primary charting library used throughout UltraViolet, offering advanced features and beautiful animations.

Route: /admin/charts?page=apex

Line Charts

<div class="card">
    <div class="card-header">
        <h5 class="card-title mb-0">Revenue Trend</h5>
    </div>
    <div class="card-body">
        <div id="lineChart"></div>
    </div>
</div>

<script>
var options = {
    series: [{
        name: 'Revenue',
        data: [30, 40, 35, 50, 49, 60, 70, 91, 125]
    }],
    chart: {
        type: 'line',
        height: 350,
        toolbar: {
            show: false
        }
    },
    colors: ['#6366f1'],
    stroke: {
        curve: 'smooth',
        width: 3
    },
    xaxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
    },
    yaxis: {
        title: {
            text: 'Revenue ($)'
        }
    },
    tooltip: {
        theme: 'dark'
    }
};

var chart = new ApexCharts(document.querySelector("#lineChart"), options);
chart.render();
</script>

Area Charts

var options = {
    series: [{
        name: 'Sales',
        data: [30, 40, 35, 50, 49, 60, 70, 91, 125]
    }],
    chart: {
        type: 'area',
        height: 350,
        toolbar: {
            show: false
        }
    },
    colors: ['#6366f1'],
    dataLabels: {
        enabled: false
    },
    stroke: {
        curve: 'smooth'
    },
    fill: {
        type: 'gradient',
        gradient: {
            shadeIntensity: 1,
            opacityFrom: 0.7,
            opacityTo: 0.3,
            stops: [0, 90, 100]
        }
    },
    xaxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
    }
};

var chart = new ApexCharts(document.querySelector("#areaChart"), options);
chart.render();

Bar Charts

var options = {
    series: [{
        name: 'Sales',
        data: [44, 55, 57, 56, 61, 58, 63, 60, 66]
    }],
    chart: {
        type: 'bar',
        height: 350,
        toolbar: {
            show: false
        }
    },
    colors: ['#6366f1'],
    plotOptions: {
        bar: {
            horizontal: false,
            columnWidth: '55%',
            borderRadius: 4
        }
    },
    dataLabels: {
        enabled: false
    },
    xaxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep']
    },
    yaxis: {
        title: {
            text: 'Sales'
        }
    },
    fill: {
        opacity: 1
    }
};

var chart = new ApexCharts(document.querySelector("#barChart"), options);
chart.render();

Pie Charts

var options = {
    series: [44, 55, 13, 43, 22],
    chart: {
        type: 'pie',
        height: 350
    },
    labels: ['Team A', 'Team B', 'Team C', 'Team D', 'Team E'],
    colors: ['#6366f1', '#8b5cf6', '#10b981', '#f59e0b', '#ef4444'],
    legend: {
        position: 'bottom'
    },
    responsive: [{
        breakpoint: 480,
        options: {
            chart: {
                width: 300
            },
            legend: {
                position: 'bottom'
            }
        }
    }]
};

var chart = new ApexCharts(document.querySelector("#pieChart"), options);
chart.render();

Donut Charts

var options = {
    series: [44, 55, 41, 17],
    chart: {
        type: 'donut',
        height: 350
    },
    labels: ['Desktop', 'Mobile', 'Tablet', 'Other'],
    colors: ['#6366f1', '#8b5cf6', '#10b981', '#f59e0b'],
    legend: {
        position: 'bottom'
    },
    plotOptions: {
        pie: {
            donut: {
                size: '65%',
                labels: {
                    show: true,
                    total: {
                        show: true,
                        label: 'Total',
                        formatter: function (w) {
                            return w.globals.seriesTotals.reduce((a, b) => a + b, 0);
                        }
                    }
                }
            }
        }
    }
};

var chart = new ApexCharts(document.querySelector("#donutChart"), options);
chart.render();

Radial Bar Charts

var options = {
    series: [76, 67, 61, 90],
    chart: {
        type: 'radialBar',
        height: 350
    },
    plotOptions: {
        radialBar: {
            dataLabels: {
                name: {
                    fontSize: '16px'
                },
                value: {
                    fontSize: '14px'
                },
                total: {
                    show: true,
                    label: 'Total',
                    formatter: function (w) {
                        return '73%';
                    }
                }
            }
        }
    },
    labels: ['Apples', 'Oranges', 'Bananas', 'Berries'],
    colors: ['#6366f1', '#8b5cf6', '#10b981', '#f59e0b']
};

var chart = new ApexCharts(document.querySelector("#radialChart"), options);
chart.render();

Mixed Charts

var options = {
    series: [{
        name: 'Revenue',
        type: 'column',
        data: [440, 505, 414, 671, 227, 413, 201, 352, 752, 320, 257, 160]
    }, {
        name: 'Sales',
        type: 'line',
        data: [23, 42, 35, 27, 43, 22, 17, 31, 22, 22, 12, 16]
    }],
    chart: {
        height: 350,
        type: 'line',
        toolbar: {
            show: false
        }
    },
    stroke: {
        width: [0, 4]
    },
    colors: ['#6366f1', '#10b981'],
    dataLabels: {
        enabled: true,
        enabledOnSeries: [1]
    },
    labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    xaxis: {
        type: 'category'
    },
    yaxis: [{
        title: {
            text: 'Revenue'
        }
    }, {
        opposite: true,
        title: {
            text: 'Sales'
        }
    }]
};

var chart = new ApexCharts(document.querySelector("#mixedChart"), options);
chart.render();

Heatmap Charts

var options = {
    series: [{
        name: 'Metric1',
        data: generateData(20, {
            min: 0,
            max: 90
        })
    }, {
        name: 'Metric2',
        data: generateData(20, {
            min: 0,
            max: 90
        })
    }],
    chart: {
        height: 350,
        type: 'heatmap',
        toolbar: {
            show: false
        }
    },
    dataLabels: {
        enabled: false
    },
    colors: ["#6366f1"],
    xaxis: {
        type: 'category'
    }
};

var chart = new ApexCharts(document.querySelector("#heatmapChart"), options);
chart.render();

function generateData(count, range) {
    var data = [];
    for (var i = 0; i < count; i++) {
        data.push({
            x: 'w' + (i + 1),
            y: Math.floor(Math.random() * (range.max - range.min + 1)) + range.min
        });
    }
    return data;
}

Candlestick Charts

var options = {
    series: [{
        data: [
            {x: new Date(1538778600000), y: [6629.81, 6650.5, 6623.04, 6633.33]},
            {x: new Date(1538780400000), y: [6632.01, 6643.59, 6620, 6630.11]},
            {x: new Date(1538782200000), y: [6630.71, 6648.95, 6623.34, 6635.65]},
            // More data points
        ]
    }],
    chart: {
        type: 'candlestick',
        height: 350,
        toolbar: {
            show: false
        }
    },
    xaxis: {
        type: 'datetime'
    },
    yaxis: {
        tooltip: {
            enabled: true
        }
    }
};

var chart = new ApexCharts(document.querySelector("#candlestickChart"), options);
chart.render();

Chart.js

Chart.js provides a lightweight alternative with excellent browser support.

Route: /admin/charts?page=chartjs

Line Chart

<div class="card">
    <div class="card-header">
        <h5 class="card-title mb-0">Sales Trend</h5>
    </div>
    <div class="card-body">
        <canvas id="lineChartJs"></canvas>
    </div>
</div>

<script>
const ctx = document.getElementById('lineChartJs').getContext('2d');
const lineChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: ['January', 'February', 'March', 'April', 'May', 'June'],
        datasets: [{
            label: 'Sales',
            data: [12, 19, 3, 5, 2, 3],
            borderColor: '#6366f1',
            backgroundColor: 'rgba(99, 102, 241, 0.1)',
            tension: 0.4
        }]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            legend: {
                position: 'top'
            }
        },
        scales: {
            y: {
                beginAtZero: true
            }
        }
    }
});
</script>

Bar Chart

const ctx = document.getElementById('barChartJs').getContext('2d');
const barChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
        datasets: [{
            label: 'Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                '#ef4444',
                '#3b82f6',
                '#eab308',
                '#10b981',
                '#8b5cf6',
                '#f97316'
            ]
        }]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            legend: {
                display: false
            }
        },
        scales: {
            y: {
                beginAtZero: true
            }
        }
    }
});

Pie Chart

const ctx = document.getElementById('pieChartJs').getContext('2d');
const pieChart = new Chart(ctx, {
    type: 'pie',
    data: {
        labels: ['Red', 'Blue', 'Yellow'],
        datasets: [{
            data: [300, 50, 100],
            backgroundColor: [
                '#ef4444',
                '#3b82f6',
                '#eab308'
            ]
        }]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            legend: {
                position: 'bottom'
            }
        }
    }
});

Doughnut Chart

const ctx = document.getElementById('doughnutChartJs').getContext('2d');
const doughnutChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
        labels: ['Direct', 'Organic', 'Referral', 'Social'],
        datasets: [{
            data: [45, 25, 20, 10],
            backgroundColor: [
                '#6366f1',
                '#10b981',
                '#f59e0b',
                '#8b5cf6'
            ]
        }]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            legend: {
                position: 'bottom'
            }
        },
        cutout: '70%'
    }
});

Real-time Charts with Livewire

Create live-updating charts with Laravel Livewire:

// Livewire Component
namespace App\Livewire;

use Livewire\Component;

class LiveChart extends Component
{
    public $data = [];
    public $labels = [];

    public function mount()
    {
        $this->refreshData();
    }

    public function refreshData()
    {
        $this->labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
        $this->data = Order::selectRaw('DATE(created_at) as date, COUNT(*) as count')
            ->whereBetween('created_at', [now()->subDays(7), now()])
            ->groupBy('date')
            ->pluck('count')
            ->toArray();

        $this->dispatch('chart-updated', [
            'labels' => $this->labels,
            'data' => $this->data
        ]);
    }

    public function render()
    {
        return view('livewire.live-chart');
    }
}
<!-- livewire/live-chart.blade.php -->
<div wire:poll.10s="refreshData">
    <canvas id="liveChart"></canvas>
</div>

<script>
let liveChart = null;

document.addEventListener('DOMContentLoaded', function() {
    const ctx = document.getElementById('liveChart').getContext('2d');
    liveChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: @json($labels),
            datasets: [{
                label: 'Orders',
                data: @json($data),
                borderColor: '#6366f1',
                tension: 0.4
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false
        }
    });
});

Livewire.on('chart-updated', (event) => {
    if (liveChart) {
        liveChart.data.labels = event.labels;
        liveChart.data.datasets[0].data = event.data;
        liveChart.update();
    }
});
</script>

Chart Customization

Theme Integration

Both charting libraries are configured to match the UltraViolet theme:

// ApexCharts Theme
const apexTheme = {
    theme: {
        mode: 'dark',
        palette: 'palette1'
    },
    colors: ['#6366f1', '#8b5cf6', '#10b981', '#f59e0b', '#ef4444'],
    chart: {
        background: 'transparent',
        foreColor: '#9ca3af'
    },
    grid: {
        borderColor: '#374151'
    },
    tooltip: {
        theme: 'dark'
    }
};

// Chart.js Theme
Chart.defaults.color = '#9ca3af';
Chart.defaults.borderColor = '#374151';

Responsive Charts

// Responsive configuration
const responsiveOptions = {
    responsive: true,
    maintainAspectRatio: false,
    aspectRatio: 2
};

Export Charts

// Export chart as image
function exportChart(chartElement) {
    const canvas = chartElement.querySelector('canvas');
    const image = canvas.toDataURL('image/png');

    const link = document.createElement('a');
    link.download = 'chart.png';
    link.href = image;
    link.click();
}

Performance Optimization

Lazy Loading

// Load charts only when visible
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const chartId = entry.target.id;
            initChart(chartId);
            observer.unobserve(entry.target);
        }
    });
});

document.querySelectorAll('.chart-container').forEach(el => {
    observer.observe(el);
});

Data Decimation

// Reduce data points for better performance
const options = {
    plugins: {
        decimation: {
            enabled: true,
            algorithm: 'lttb',
            samples: 50
        }
    }
};

Best Practices

  1. Choose the Right Chart: Select chart types that best represent your data
  2. Performance: Limit data points for large datasets
  3. Responsiveness: Ensure charts work on all screen sizes
  4. Accessibility: Include proper labels and ARIA attributes
  5. Color Contrast: Use colors with sufficient contrast
  6. Tooltips: Provide helpful tooltips for data context
  7. Loading States: Show loaders while data is fetching

Production Usage

Charts work in both the static HTML and Laravel Livewire editions. For real-time charts in the static HTML version, you can provide static snapshots or mock data.

// Chart initialization
if (typeof ApexCharts !== 'undefined') {
    // Initialize charts with ApexCharts
    initializeChart();
} else {
    console.warn('ApexCharts library not loaded');
}

Additional Resources