{{-- Inline SVG mini-chart — sin dependencias JS. Para trends y monthly breakdowns. Props: - data: array — valores (eje Y) - labels: ?array — etiquetas eje X (opcional) - type: 'line'|'bar' — tipo de chart - color: string — bootstrap color (primary, success, warning, etc.) - height: int — altura en px (default 40) - width: string|int — ancho (default '100%') - show-labels: bool — mostrar labels eje X (default false) - show-values: bool — mostrar valor encima de bar/punto final (default false) - format: ?callable — formateo de valores ej. fn($v) => '$'.number_format($v) --}} @props([ 'data' => [], 'labels' => [], 'type' => 'line', 'color' => 'primary', 'height' => 40, 'width' => '100%', 'showLabels' => false, 'showValues' => false, ]) @php $values = array_values(array_map(fn($v) => is_numeric($v) ? (float) $v : 0, $data)); $n = count($values); if ($n === 0) { $svg = ''; } else { $max = max($values); $min = min($values); $range = max(1, $max - min(0, $min)); $vbWidth = 100; $vbHeight = 30; $paddingY = 2; if ($type === 'line') { $points = []; foreach ($values as $i => $v) { $x = $n === 1 ? 50 : ($i / ($n - 1)) * $vbWidth; $y = $vbHeight - $paddingY - (($v - min(0, $min)) / $range) * ($vbHeight - 2 * $paddingY); $points[] = round($x, 2) . ',' . round($y, 2); } $polyline = implode(' ', $points); $lastPoint = end($points); [$lastX, $lastY] = explode(',', $lastPoint); } } @endphp @if($n === 0)
Sin datos
@else
@if($type === 'line') {{-- Area fill under line --}} {{-- Line --}} {{-- Last point dot --}} @elseif($type === 'bar') @php $barWidth = $vbWidth / max(1, $n); @endphp @foreach($values as $i => $v) @php $hPct = $range > 0 ? (($v - min(0, $min)) / $range) : 0; $barH = max(0.5, ($vbHeight - 2 * $paddingY) * $hPct); $x = $i * $barWidth + $barWidth * 0.15; $w = $barWidth * 0.7; $y = $vbHeight - $paddingY - $barH; @endphp @endforeach @endif @if($showLabels && !empty($labels))
@foreach($labels as $lbl) {{ $lbl }} @endforeach
@endif @if($showValues)
{{ $values[0] ?? '—' }} {{ end($values) }}
@endif
@endif