mivita/resources/views/user/abo/_abo_chart.blade.php
2026-04-10 17:15:27 +02:00

111 lines
4.1 KiB
PHP

@php
$chartId = 'aboChart_' . str_replace('.', '', microtime(true));
$chartDataJson = json_encode(array_values($chartData));
$chartLabelsJson = json_encode(array_values($chartMonths));
$nonNullValues = array_filter($chartData, fn($v) => $v !== null);
$maxVal = count($nonNullValues) ? max($nonNullValues) : 0;
// Großzügige Schritte für die Y-Achse
if ($maxVal <= 5) { $stepSize = 1; }
elseif ($maxVal <= 10) { $stepSize = 2; }
elseif ($maxVal <= 20) { $stepSize = 5; }
elseif ($maxVal <= 50) { $stepSize = 10; }
elseif ($maxVal <= 100) { $stepSize = 20; }
elseif ($maxVal <= 200) { $stepSize = 50; }
elseif ($maxVal <= 500) { $stepSize = 100; }
elseif ($maxVal <= 1000) { $stepSize = 200; }
else { $stepSize = 500; }
// Genug Platz nach oben, damit das Label nicht abgeschnitten wird
$suggestedMax = $maxVal + $stepSize;
@endphp
<div class="card mb-4">
<div class="card-body pb-2">
<div class="d-flex justify-content-between align-items-center flex-wrap">
<h6 class="font-weight-bold mb-2">
{{ __('abo.chart_monthly_abos') }}
<span class="text-muted font-weight-normal ml-1">{{ $chartYear }}</span>
</h6>
<div class="mb-2">
@foreach($chartYears as $y)
<a href="{{ url()->current() }}?year={{ $y }}"
class="btn btn-xs btn-sm {{ $chartYear == $y ? 'btn-secondary' : 'btn-outline-secondary' }} mr-1 mb-1">
{{ $y }}
</a>
@endforeach
</div>
</div>
</div>
<hr class="m-0">
<div class="card-body pt-3 pb-2">
<canvas id="{{ $chartId }}" height="80"></canvas>
</div>
</div>
<script src="/vendor/libs/chartjs/chartjs.js"></script>
<script>
(function () {
// Inline data-labels plugin für Chart.js v2
var dataLabelsPlugin = {
afterDatasetsDraw: function (chart) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i);
if (meta.hidden) { return; }
meta.data.forEach(function (bar, index) {
var value = dataset.data[index];
if (value === null || value === undefined || value === 0) { return; }
ctx.save();
ctx.fillStyle = '#495057';
ctx.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText(value, bar._model.x, bar._model.y - 3);
ctx.restore();
});
});
}
};
var ctx = document.getElementById('{{ $chartId }}').getContext('2d');
new Chart(ctx, {
type: 'bar',
plugins: [dataLabelsPlugin],
data: {
labels: {!! $chartLabelsJson !!},
datasets: [{
label: '{{ __('abo.chart_active_abos') }}',
data: {!! $chartDataJson !!},
backgroundColor: 'rgba(102, 110, 232, 0.2)',
borderColor: 'rgba(102, 110, 232, 0.8)',
borderWidth: 1
}]
},
options: {
responsive: true,
legend: { display: false },
tooltips: { enabled: false },
layout: {
padding: { top: 20 }
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: {{ $stepSize }},
suggestedMax: {{ $suggestedMax }},
callback: function (value) {
return Number.isInteger(value) ? value : null;
}
},
gridLines: { color: 'rgba(0,0,0,0.05)' }
}],
xAxes: [{
gridLines: { display: false }
}]
}
}
});
}());
</script>