diff --git a/dbapp/mainapp/templates/mainapp/statistics.html b/dbapp/mainapp/templates/mainapp/statistics.html index 3a9a105..cf8eae1 100644 --- a/dbapp/mainapp/templates/mainapp/statistics.html +++ b/dbapp/mainapp/templates/mainapp/statistics.html @@ -113,6 +113,19 @@ .card-body canvas:active { cursor: grabbing; } + + /* Summary rows in satellite table */ + .table-warning.fw-bold td { + border-bottom: 2px solid #ffc107 !important; + } + + .table-info.fw-bold td { + border-bottom: 2px solid #0dcaf0 !important; + } + + .satellite-stat-row:hover { + background-color: #f8f9fa !important; + } {% endblock %} @@ -326,6 +339,17 @@ + + + Всего + + {{ total_points }} + + + {{ total_sources }} + + + {% for stat in satellite_stats %} {{ stat.parameter_obj__id_satellite__name }} @@ -373,6 +397,30 @@ + +
+
+
+
+ Распределение объектов по спутникам +
+
+ +
+
+
+
+
+
+ Выбранные спутники по количеству объектов +
+
+ +
+
+
+
+
+
+ + +
+
+ +
@@ -588,7 +650,9 @@ document.addEventListener('DOMContentLoaded', function() { const dailyLabels = dailyData.map(d => { if (d.date) { const date = new Date(d.date); - return date.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year:"2-digit" }); + const dateStr = date.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year:"2-digit" }); + const dayStr = date.toLocaleDateString('ru-RU', { weekday: 'short' }); + return dateStr + ' (' + dayStr + ')'; } return ''; }); @@ -743,6 +807,9 @@ document.addEventListener('DOMContentLoaded', function() { barChart.data.datasets[0].backgroundColor = barColors; barChart.update(); } + + // Update source charts + updateSourceCharts(); } // Initialize charts @@ -829,10 +896,12 @@ document.addEventListener('DOMContentLoaded', function() { color: '#333', font: { weight: 'bold', - size: 11 + size: 12 }, - formatter: function(value) { - return value; + formatter: function(value, context) { + const total = context.dataset.data.reduce((a, b) => a + b, 0); + const percentage = ((value / total) * 100).toFixed(1); + return percentage + '%\n(' + value + ')'; } } }, @@ -890,10 +959,149 @@ document.addEventListener('DOMContentLoaded', function() { } } + // Source object charts (similar to satellite charts but for sources count) + let sourcePieChart = null; + let sourceBarChart = null; + + // Initialize source charts + function initSourceCharts() { + const filteredStats = getFilteredSatelliteData(); + + // Source Pie Chart + if (filteredStats.length > 0) { + const sourcePieLabels = filteredStats.map(s => s.parameter_obj__id_satellite__name); + const sourcePieData = filteredStats.map(s => s.sources_count); + const sourcePieColors = filteredStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]); + + sourcePieChart = new Chart(document.getElementById('sourcePieChart'), { + type: 'doughnut', + data: { + labels: sourcePieLabels, + datasets: [{ + data: sourcePieData, + backgroundColor: sourcePieColors + }] + }, + options: { + responsive: true, + plugins: { + legend: { + position: 'right', + labels: { + boxWidth: 12, + font: { + size: 11 + } + } + }, + datalabels: { + color: '#fff', + font: { + weight: 'bold', + size: 10 + }, + formatter: function(value, context) { + const total = context.dataset.data.reduce((a, b) => a + b, 0); + const percentage = ((value / total) * 100).toFixed(1); + if (percentage < 3) return ''; + return value + '\n(' + percentage + '%)'; + }, + textAlign: 'center' + } + } + } + }); + } + + // Source Bar Chart (top 15) + if (filteredStats.length > 0) { + const topSourceStats = filteredStats.slice(0, 15); + const sourceBarLabels = topSourceStats.map(s => s.parameter_obj__id_satellite__name); + const sourceBarData = topSourceStats.map(s => s.sources_count); + const sourceBarColors = topSourceStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]); + + sourceBarChart = new Chart(document.getElementById('sourceBarChart'), { + type: 'bar', + data: { + labels: sourceBarLabels, + datasets: [{ + label: 'Количество объектов', + data: sourceBarData, + backgroundColor: sourceBarColors + }] + }, + options: { + responsive: true, + indexAxis: 'y', + interaction: { + intersect: false, + mode: 'index' + }, + plugins: { + legend: { + display: false + }, + datalabels: { + anchor: 'end', + align: 'end', + color: '#333', + font: { + weight: 'bold', + size: 12 + }, + formatter: function(value, context) { + const total = context.dataset.data.reduce((a, b) => a + b, 0); + const percentage = ((value / total) * 100).toFixed(1); + return percentage + '%\n(' + value + ')'; + } + } + }, + scales: { + x: { + beginAtZero: true, + grace: '10%' + } + } + } + }); + } + } + + // Update source charts based on satellite selection + function updateSourceCharts() { + const filteredStats = getFilteredSatelliteData(); + + // Update source pie chart + if (sourcePieChart) { + const sourcePieLabels = filteredStats.map(s => s.parameter_obj__id_satellite__name); + const sourcePieData = filteredStats.map(s => s.sources_count); + const sourcePieColors = filteredStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]); + + sourcePieChart.data.labels = sourcePieLabels; + sourcePieChart.data.datasets[0].data = sourcePieData; + sourcePieChart.data.datasets[0].backgroundColor = sourcePieColors; + sourcePieChart.update(); + } + + // Update source bar chart (limit to top 15 for readability) + if (sourceBarChart) { + const topSourceStats = filteredStats.slice(0, 15); + const sourceBarLabels = topSourceStats.map(s => s.parameter_obj__id_satellite__name); + const sourceBarData = topSourceStats.map(s => s.sources_count); + const sourceBarColors = topSourceStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]); + + sourceBarChart.data.labels = sourceBarLabels; + sourceBarChart.data.datasets[0].data = sourceBarData; + sourceBarChart.data.datasets[0].backgroundColor = sourceBarColors; + sourceBarChart.update(); + } + } + // Initialize satellite functionality initSatelliteCheckboxes(); initSatelliteButtons(); initCharts(); + initSourceCharts(); // Note: Zoom functionality temporarily disabled due to plugin loading issues // Can be re-enabled when zoom plugin is properly configured @@ -913,9 +1121,13 @@ document.addEventListener('DOMContentLoaded', function() { 'show-daily-chart': 'daily-chart-block', 'show-satellite-table': 'satellite-table-block', - // Individual charts + // Satellite charts 'show-pie-chart': 'pie-chart-block', - 'show-bar-chart': 'bar-chart-block' + 'show-bar-chart': 'bar-chart-block', + + // Source object charts + 'show-source-pie-chart': 'source-pie-chart-block', + 'show-source-bar-chart': 'source-bar-chart-block' }; // Load settings from localStorage @@ -997,6 +1209,18 @@ document.addEventListener('DOMContentLoaded', function() { satelliteChartsBlock.classList.add('hidden'); } } + + // Source charts block + const sourceChartsVisible = ['show-source-pie-chart', 'show-source-bar-chart'] + .some(id => !document.getElementById(blockSettings[id])?.classList.contains('hidden')); + const sourceChartsBlock = document.getElementById('source-charts-block'); + if (sourceChartsBlock) { + if (sourceChartsVisible) { + sourceChartsBlock.classList.remove('hidden'); + } else { + sourceChartsBlock.classList.add('hidden'); + } + } } // Initialize settings @@ -1044,7 +1268,7 @@ document.addEventListener('DOMContentLoaded', function() { if (selectChartsOnlyBtn) { selectChartsOnlyBtn.addEventListener('click', function() { - const chartKeys = ['show-daily-chart', 'show-satellite-table', 'show-pie-chart', 'show-bar-chart']; + const chartKeys = ['show-daily-chart', 'show-satellite-table', 'show-pie-chart', 'show-bar-chart', 'show-source-pie-chart', 'show-source-bar-chart']; Object.keys(blockSettings).forEach(key => { currentSettings[key] = chartKeys.includes(key); });