@props([ 'title', 'subtitle' => null, 'weekPoints' => [], 'monthPoints' => [], 'unit' => '', 'color' => 'green', ]) @php $datasets = [ 'week' => ['label' => '7 jours', 'points' => $weekPoints], 'month' => ['label' => '30 jours', 'points' => $monthPoints], ]; $chartId = md5($title . $subtitle . $unit . $color); $formatNumber = fn (mixed $value): string => rtrim(rtrim(number_format((float) $value, 1, ',', ' '), '0'), ','); $buildAxis = function (float $min, float $max): array { if ($min === $max) { $max = $min + 1; } $rawStep = ($max - $min) / 4; $magnitude = 10 ** floor(log10(max($rawStep, 1))); $normalized = $rawStep / $magnitude; $step = match (true) { $normalized <= 1 => $magnitude, $normalized <= 2 => 2 * $magnitude, $normalized <= 5 => 5 * $magnitude, default => 10 * $magnitude, }; $axisMin = $min < 0 ? floor($min / $step) * $step : 0; $axisMax = max($step, ceil($max / $step) * $step); return [$axisMin, $axisMax, max($step, $axisMax - $axisMin)]; }; $formatValue = function (mixed $value) use ($formatNumber, $unit): string { if (in_array($unit, ['min', 'minutes'], true)) { $minutes = max(0, (int) round((float) $value)); $hours = intdiv($minutes, 60); $remaining = $minutes % 60; return $hours > 0 ? $hours . 'h' . str_pad((string) $remaining, 2, '0', STR_PAD_LEFT) : $remaining . ' min'; } return trim($formatNumber($value) . ' ' . $unit); }; @endphp
merge(['class' => 'dashboard-panel module-chart-card module-chart-card--selectable']) }}>

{{ $subtitle }}

{{ $title }}

@foreach ($datasets as $key => $dataset) @php $points = collect($dataset['points']); $values = $points->map(fn ($point) => data_get($point, 'value'))->values(); $numericValues = $values->filter(fn ($value) => $value !== null)->map(fn ($value) => (float) $value)->values(); $labels = $points->map(fn ($point) => (string) data_get($point, 'label', ''))->values(); $actualMinValue = (float) ($numericValues->min() ?? 0); $actualMaxValue = (float) ($numericValues->max() ?? 0); [$axisMin, $axisMax, $rangeValue] = $buildAxis($actualMinValue, $actualMaxValue); $averageValue = $numericValues->isNotEmpty() ? (float) $numericValues->avg() : 0; $count = max(1, $values->count()); $plotLeft = 2; $plotRight = 98; $plotTop = 8; $plotBottom = 88; $plotWidth = $plotRight - $plotLeft; $plotHeight = $plotBottom - $plotTop; $svgSegments = []; $currentSegment = []; $dotPoints = []; $axisTicks = collect([1, 0.75, 0.5, 0.25, 0])->map(function (float $ratio) use ($axisMin, $rangeValue, $plotTop, $plotHeight) { return [ 'value' => $axisMin + ($rangeValue * $ratio), 'y' => $plotTop + ((1 - $ratio) * $plotHeight), ]; }); $averageY = $plotBottom - ((($averageValue - $axisMin) / $rangeValue) * $plotHeight); foreach ($values as $index => $value) { if ($value === null) { continue; } $floatValue = (float) $value; $x = $count === 1 ? $plotLeft + ($plotWidth / 2) : $plotLeft + (($index / ($count - 1)) * $plotWidth); $y = $plotBottom - ((($floatValue - $axisMin) / $rangeValue) * $plotHeight); $point = number_format($x, 2, '.', '') . ',' . number_format($y, 2, '.', ''); $currentSegment[] = $point; $dotPoints[] = [ 'x' => $x, 'y' => $y, 'value' => $floatValue, 'label' => (string) data_get($points->get($index), 'label', ''), 'date' => (string) data_get($points->get($index), 'date', ''), ]; } if ($currentSegment !== []) { $svgSegments[] = implode(' ', $currentSegment); } $firstLabel = $labels->first(); $lastLabel = $labels->last(); $lastValue = $numericValues->last() ?? 0; $totalValue = $numericValues->sum(); $xAxisLabels = $labels ->map(fn (string $label, int $index): array => [ 'label' => $label, 'x' => $labels->count() <= 1 ? 50 : $plotLeft + (($index / max(1, $labels->count() - 1)) * $plotWidth), 'index' => $index, ]) ->values(); @endphp
@foreach ($axisTicks as $tick) @endforeach @foreach ($svgSegments as $segment) @endforeach
@foreach ($dotPoints as $point) @endforeach
{{ $firstLabel }} → {{ $lastLabel }} {{ __('Dernier') }} {{ $formatValue($lastValue) }} {{ __('Min') }} {{ $formatValue($actualMinValue) }} {{ __('Moy.') }} {{ $formatValue($averageValue) }} {{ __('Max') }} {{ $formatValue($actualMaxValue) }} {{ __('Total') }} {{ $formatValue($totalValue) }}
@endforeach