{{-- A line over time, drawn on the server; app.js adds the crosshair and tooltip. $series list of ['name' => 'Views', 'values' => [Y-m-d => number], 'prev' => bool] (first = this period) $fmt 'n' or 'money' (micro-dollars) $bucket 'day' or 'week' $markers optional list of ['day' => Y-m-d, 'label' => 'Featured'] $label what the chart shows, for screen readers The plot stretches to the card; lines keep 2px (non-scaling strokes) and text stays HTML, so phones get readable labels. One y-axis only: other measures get their own chart. --}} @php $fmt ??= 'n'; $bucket ??= 'day'; $markers ??= []; $cur = $series[0]; $days = array_keys($cur['values']); $n = count($days); $max = 0; foreach ($series as $s) { $max = max($max, $s['values'] ? max(array_values($s['values'])) : 0); } [$top, $ticks] = \App\Support\Charts::scale((float) $max); $x = fn (int $i) => $n > 1 ? round($i * 1000 / ($n - 1), 2) : 500; $y = fn ($v) => round(100 - ($top > 0 ? $v / $top * 100 : 0), 3); $points = fn (array $vals) => implode(' ', array_map(fn ($i, $v) => $x($i).','.$y($v), array_keys(array_values($vals)), array_values($vals))); $curVals = array_values($cur['values']); $area = $n ? 'M0,100 L'.str_replace(' ', ' L', $points($cur['values'])).' L'.$x($n - 1).',100 Z' : ''; $xl = \App\Support\Charts::xLabels($days, $bucket); $data = [ 'fmt' => $fmt, 'labels' => array_map(fn ($d) => ($bucket === 'week' ? 'Week of ' : '').\Carbon\CarbonImmutable::parse($d)->format('D, M j, Y'), $days), 'series' => array_map(fn ($s) => ['name' => $s['name'], 'prev' => (bool) ($s['prev'] ?? false), 'values' => array_values($s['values'])], $series), ]; $last = $n ? $curVals[$n - 1] : 0; @endphp