@props([ 'title', 'subtitle' => null, 'weekSeries' => [], 'monthSeries' => [], 'unit' => 'min', ]) @php $datasets = [ 'week' => ['label' => '7 jours', 'series' => $weekSeries], 'month' => ['label' => '30 jours', 'series' => $monthSeries], ]; $chartId = md5($title . $subtitle . $unit); $seriesColors = [ 'var(--dashboard-green)', 'var(--dashboard-blue)', 'var(--dashboard-amber)', 'var(--dashboard-red)', '#b7e06a', '#c79bf2', ]; $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 $series = collect($dataset['series']); $allValues = $series ->flatMap(fn ($item) => collect(data_get($item, 'points', []))->map(fn ($point) => data_get($point, 'value'))) ->filter(fn ($value) => $value !== null) ->map(fn ($value) => (float) $value) ->values(); $actualMinValue = (float) ($allValues->min() ?? 0); $actualMaxValue = (float) ($allValues->max() ?? 0); [$axisMin, $axisMax, $rangeValue] = $buildAxis($actualMinValue, $actualMaxValue); $firstPoints = collect(data_get($series->first(), 'points', [])); $firstLabel = data_get($firstPoints->first(), 'label', ''); $lastLabel = data_get($firstPoints->last(), 'label', ''); $averageValue = $allValues->isNotEmpty() ? (float) $allValues->avg() : 0; $plotLeft = 2; $plotRight = 98; $plotTop = 8; $plotBottom = 88; $plotWidth = $plotRight - $plotLeft; $plotHeight = $plotBottom - $plotTop; $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); $labels = $firstPoints->map(fn ($point) => (string) data_get($point, 'label', ''))->values(); $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
@if ($series->isNotEmpty())
@foreach ($axisTicks as $tick) @endforeach @foreach ($series as $index => $item) @php $points = collect(data_get($item, 'points', [])); $values = $points->map(fn ($point) => data_get($point, 'value'))->values(); $count = max(1, $values->count()); $svgSegments = []; $currentSegment = []; $color = $seriesColors[$index % count($seriesColors)]; foreach ($values as $pointIndex => $value) { if ($value === null) { continue; } $floatValue = (float) $value; $x = $count === 1 ? $plotLeft + ($plotWidth / 2) : $plotLeft + (($pointIndex / ($count - 1)) * $plotWidth); $y = $plotBottom - ((($floatValue - $axisMin) / $rangeValue) * $plotHeight); $currentSegment[] = number_format($x, 2, '.', '') . ',' . number_format($y, 2, '.', ''); } if ($currentSegment !== []) { $svgSegments[] = implode(' ', $currentSegment); } @endphp @foreach ($svgSegments as $segment) @endforeach @endforeach
@foreach ($series as $index => $item) @php $points = collect(data_get($item, 'points', [])); $values = $points->map(fn ($point) => data_get($point, 'value'))->values(); $count = max(1, $values->count()); $color = $seriesColors[$index % count($seriesColors)]; @endphp @foreach ($values as $pointIndex => $value) @continue($value === null) @php $floatValue = (float) $value; $x = $count === 1 ? $plotLeft + ($plotWidth / 2) : $plotLeft + (($pointIndex / ($count - 1)) * $plotWidth); $y = $plotBottom - ((($floatValue - $axisMin) / $rangeValue) * $plotHeight); $pointLabel = (string) data_get($points->get($pointIndex), 'label', ''); $pointDate = (string) data_get($points->get($pointIndex), 'date', ''); $seriesName = (string) data_get($item, 'name', ''); @endphp @endforeach @endforeach
{{ $firstLabel }} → {{ $lastLabel }} {{ __('Moy.') }} {{ $formatValue($averageValue) }} {{ __('Max') }} {{ $formatValue($actualMaxValue) }} {{ $dataset['label'] }}
@else
{{ __('Aucune donnée par type sur cette période.') }}
@endif
@endforeach