Skip to main content

Data display

Chart code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/chart.blade.php

@props([
    'label' => null,
    'summary' => null,
    'type' => 'line',
    'labels' => [],
    'datasets' => [],
    'height' => 280,
    'grid' => false,
    'legend' => null,
    'stacked' => false,
    'valuePrefix' => '',
    'valueSuffix' => '',
])

@php
    /*
    | Chart.js wrapper — clean, minimal charts that re-theme from the Harbour
    | palette and follow the light/dark store automatically.
    |
    | type:    line | area | bar | pie | doughnut
    | labels:  x-axis / segment labels  ['Jan', 'Feb', ...]
    | datasets: one or more series. Each: [
    |     'label' => 'Revenue',
    |     'data'  => [12, 19, 3, ...],
    |     'color' => '#0f766e',          // optional, defaults to theme palette
    |     'colors' => ['#..', ...],      // optional per-segment (pie/doughnut)
    | ]
    | grid:    show horizontal gridlines (off by default for a cleaner look)
    | legend:  show the legend (defaults: on for pie/doughnut, off otherwise)
    |
    | Usage:
    |   <x-ui.chart
    |       type="area"
    |       :labels="['Mon','Tue','Wed','Thu','Fri']"
    |       :datasets="[['label' => 'Visits', 'data' => [120, 200, 150, 280, 240]]]"
    |   />
    */
    $isRadial = in_array($type, ['pie', 'doughnut'], true);
    $showLegend = $legend ?? ($isRadial || count($datasets) > 1);

    $config = [
        'type' => $type,
        'labels' => $labels,
        'datasets' => array_values($datasets),
        'options' => [
            'grid' => (bool) $grid,
            'legend' => (bool) $showLegend,
            'stacked' => (bool) $stacked,
            'valuePrefix' => $valuePrefix,
            'valueSuffix' => $valueSuffix,
        ],
    ];

    $seriesLabels = collect($datasets)
        ->pluck('label')
        ->filter()
        ->values()
        ->all();

    $pointCount = max(
        count($labels),
        max(array_map(fn (array $dataset) => count($dataset['data'] ?? []), $datasets) ?: [0]),
    );

    $accessibleLabel = $summary;

    if (! $accessibleLabel) {
        $accessibleLabel = trim(implode(' ', array_filter([
            $label ? $label.'.' : ($seriesLabels !== [] ? implode(', ', $seriesLabels).'.' : null),
            Str::headline($type).' chart.',
            $pointCount > 0 ? $pointCount.' data point'.($pointCount === 1 ? '' : 's').'.' : null,
        ])));

        if ($accessibleLabel === '') {
            $accessibleLabel = 'Chart';
        }
    }
@endphp

<div
    x-data="uiChart(@js($config))"
    wire:ignore
    {{ $attributes->merge(['class' => 'relative w-full']) }}
    style="height: {{ is_numeric($height) ? $height.'px' : $height }}"
>
    <canvas x-ref="canvas" role="img" aria-label="{{ $accessibleLabel }}"></canvas>
</div>