Dashboard erweitert: Toggle zwischen Wochen- und 24-Stunden-Verlauf für alle Charts

This commit is contained in:
2025-08-02 14:25:07 +02:00
parent 9e025bd4c7
commit e5fbc14a34
2 changed files with 250 additions and 60 deletions

View File

@@ -19,6 +19,32 @@
.stats-label { color: #64748b; }
.stats-value { font-size: 1.5em; font-weight: bold; }
.chart-container { margin: 2em 0; }
.toggle-container {
display: flex;
justify-content: center;
margin-bottom: 1.5em;
gap: 0.5em;
}
.toggle-btn {
padding: 0.5em 1em;
border: 1px solid #d1d5db;
background: #f9fafb;
color: #6b7280;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
}
.toggle-btn.active {
background: #2563eb;
color: white;
border-color: #2563eb;
}
.toggle-btn:hover {
background: #e5e7eb;
}
.toggle-btn.active:hover {
background: #1d4ed8;
}
</style>
</head>
<body>
@@ -28,6 +54,12 @@
<div class="stats-label">Gesamt-Pageviews (7 Tage):</div>
<div class="stats-value">{{ pageviews }}</div>
</div>
<div class="toggle-container">
<button class="toggle-btn active" data-period="week">Wochenverlauf</button>
<button class="toggle-btn" data-period="day">24-Stunden-Verlauf</button>
</div>
<div class="chart-container">
<canvas id="imprChart" width="400" height="180"></canvas>
</div>
@@ -43,75 +75,196 @@
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
// Impressions pro Tag
// eslint-disable-next-line
const imprData = {{ impressions_per_day|tojson }};
const imprLabels = Object.keys(imprData);
const imprCounts = Object.values(imprData);
new Chart(document.getElementById('imprChart').getContext('2d'), {
type: 'line',
data: {
labels: imprLabels,
datasets: [{
label: 'Impressions/Tag',
data: imprCounts,
borderColor: '#059669',
backgroundColor: 'rgba(5,150,105,0.1)',
tension: 0.2,
fill: true
}]
},
options: {
plugins: { legend: { display: true } },
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
}
// Daten für verschiedene Zeiträume
const weekData = {{ impressions_per_day|tojson }};
const dayData = {{ impressions_per_hour|tojson }};
const weekFuncData = {{ func_counts|tojson }};
const dayFuncData = {{ func_counts_hourly|tojson }};
const weekApiData = {{ api_counts|tojson }};
const dayApiData = {{ api_counts_hourly|tojson }};
let currentPeriod = 'week';
let currentImprChart = null;
let currentFuncChart = null;
let currentApiChart = null;
// Toggle-Buttons Event Listener
document.querySelectorAll('.toggle-btn').forEach(btn => {
btn.addEventListener('click', function() {
// Aktiven Button aktualisieren
document.querySelectorAll('.toggle-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
// Zeitraum wechseln
currentPeriod = this.dataset.period;
updateAllCharts();
});
});
// Funktionsaufrufe
// eslint-disable-next-line
const funcCounts = {{ func_counts|tojson }};
const labels = Object.keys(funcCounts);
const data = Object.values(funcCounts);
new Chart(document.getElementById('funcChart').getContext('2d'), {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Funktionsaufrufe',
data: data,
backgroundColor: '#2563eb',
}]
},
options: {
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
function updateImpressionsChart() {
const ctx = document.getElementById('imprChart').getContext('2d');
// Bestehenden Chart zerstören
if (currentImprChart) {
currentImprChart.destroy();
}
});
// API-Nutzung
// eslint-disable-next-line
const apiCounts = {{ api_counts|tojson }};
if (Object.keys(apiCounts).length > 0 && document.getElementById('apiChart')) {
new Chart(document.getElementById('apiChart').getContext('2d'), {
type: 'bar',
let data, labels, counts;
if (currentPeriod === 'week') {
data = weekData;
labels = Object.keys(data);
counts = Object.values(data);
} else {
data = dayData;
labels = Object.keys(data);
counts = Object.values(data);
}
currentImprChart = new Chart(ctx, {
type: 'line',
data: {
labels: Object.keys(apiCounts),
labels: labels,
datasets: [{
label: 'API-Aufrufe nach Endpunkt',
data: Object.values(apiCounts),
backgroundColor: '#f59e42',
label: currentPeriod === 'week' ? 'Impressions/Tag' : 'Impressions/Stunde',
data: counts,
borderColor: '#059669',
backgroundColor: 'rgba(5,150,105,0.1)',
tension: 0.2,
fill: true
}]
},
options: {
plugins: { legend: { display: false } },
plugins: {
legend: { display: true },
title: {
display: true,
text: currentPeriod === 'week' ? 'Wochenverlauf' : '24-Stunden-Verlauf'
}
},
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
}
});
}
function updateFunctionChart() {
const ctx = document.getElementById('funcChart').getContext('2d');
// Bestehenden Chart zerstören
if (currentFuncChart) {
currentFuncChart.destroy();
}
let data, labels, counts;
if (currentPeriod === 'week') {
data = weekFuncData;
labels = Object.keys(data);
counts = Object.values(data);
} else {
// Für stündliche Daten: Summe aller Stunden für jede Funktion
const aggregatedData = {};
Object.values(dayFuncData).forEach(hourData => {
Object.keys(hourData).forEach(func => {
aggregatedData[func] = (aggregatedData[func] || 0) + hourData[func];
});
});
data = aggregatedData;
labels = Object.keys(data);
counts = Object.values(data);
}
currentFuncChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Funktionsaufrufe',
data: counts,
backgroundColor: '#2563eb',
}]
},
options: {
plugins: {
legend: { display: false },
title: {
display: true,
text: currentPeriod === 'week' ? 'Funktionsaufrufe (Woche)' : 'Funktionsaufrufe (24h)'
}
},
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
}
});
}
function updateApiChart() {
const apiChartElement = document.getElementById('apiChart');
if (!apiChartElement) return;
const ctx = apiChartElement.getContext('2d');
// Bestehenden Chart zerstören
if (currentApiChart) {
currentApiChart.destroy();
}
let data, labels, counts;
if (currentPeriod === 'week') {
data = weekApiData;
} else {
// Für stündliche Daten: Summe aller Stunden für jede API
const aggregatedData = {};
Object.values(dayApiData).forEach(hourData => {
Object.keys(hourData).forEach(api => {
aggregatedData[api] = (aggregatedData[api] || 0) + hourData[api];
});
});
data = aggregatedData;
}
if (Object.keys(data).length === 0) return;
labels = Object.keys(data);
counts = Object.values(data);
currentApiChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'API-Aufrufe nach Endpunkt',
data: counts,
backgroundColor: '#f59e42',
}]
},
options: {
plugins: {
legend: { display: false },
title: {
display: true,
text: currentPeriod === 'week' ? 'API-Nutzung (Woche)' : 'API-Nutzung (24h)'
}
},
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } }
}
}
});
}
function updateAllCharts() {
updateImpressionsChart();
updateFunctionChart();
updateApiChart();
}
// Initial Charts erstellen
updateAllCharts();
});
</script>
</body>