Связанные точки (0):
@@ -1764,33 +1745,6 @@ function showSourceDetails(sourceId) {
// Hide loading spinner
document.getElementById('modalLoadingSpinner').style.display = 'none';
- // Show marks if available
- if (data.marks && data.marks.length > 0) {
- document.getElementById('marksSection').style.display = 'block';
- document.getElementById('marksCount').textContent = data.marks.length;
-
- const marksTableBody = document.getElementById('marksTableBody');
- marksTableBody.innerHTML = '';
-
- data.marks.forEach(mark => {
- const row = document.createElement('tr');
-
- let markBadge = '
-';
- if (mark.mark === true) {
- markBadge = '
Есть';
- } else if (mark.mark === false) {
- markBadge = '
Нет';
- }
-
- row.innerHTML = '
' + markBadge + ' | ' +
- '
' + mark.timestamp + ' | ' +
- '
' + mark.created_by + ' | ';
- marksTableBody.appendChild(row);
- });
- } else {
- document.getElementById('marksSection').style.display = 'none';
- }
-
if (data.objitems && data.objitems.length > 0) {
// Show content
document.getElementById('modalContent').style.display = 'block';
diff --git a/dbapp/mainapp/templates/mainapp/statistics.html b/dbapp/mainapp/templates/mainapp/statistics.html
index 95f3f8c..3a9a105 100644
--- a/dbapp/mainapp/templates/mainapp/statistics.html
+++ b/dbapp/mainapp/templates/mainapp/statistics.html
@@ -80,6 +80,39 @@
.stats-block.hidden {
display: none !important;
}
+
+ /* Satellite selection styles */
+ .satellite-selection-container {
+ background-color: #f8f9fa;
+ }
+
+ .satellite-selection-container .form-check {
+ padding: 0.25rem 0.5rem;
+ margin: 0;
+ border-radius: 0.25rem;
+ transition: background-color 0.2s;
+ }
+
+ .satellite-selection-container .form-check:hover {
+ background-color: #e9ecef;
+ }
+
+ .satellite-selection-container .form-check-label {
+ font-size: 0.875rem;
+ cursor: pointer;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ }
+
+ /* Chart zoom hint */
+ .card-body canvas {
+ cursor: grab;
+ }
+
+ .card-body canvas:active {
+ cursor: grabbing;
+ }
{% endblock %}
@@ -331,7 +364,7 @@
+
+
+
+ Спутники для диаграмм
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -520,10 +580,10 @@ document.addEventListener('DOMContentLoaded', function() {
presetBtns.forEach(b => b.classList.remove('active'));
});
- // Register datalabels plugin
+ // Register plugins
Chart.register(ChartDataLabels);
- // Daily Chart
+ // Daily Chart with zoom
const dailyData = {{ daily_data|safe }};
const dailyLabels = dailyData.map(d => {
if (d.date) {
@@ -535,8 +595,9 @@ document.addEventListener('DOMContentLoaded', function() {
const dailyPoints = dailyData.map(d => d.points);
const dailySources = dailyData.map(d => d.sources);
+ let dailyChart = null;
if (dailyData.length > 0) {
- new Chart(document.getElementById('dailyChart'), {
+ dailyChart = new Chart(document.getElementById('dailyChart'), {
type: 'line',
data: {
labels: dailyLabels,
@@ -559,6 +620,10 @@ document.addEventListener('DOMContentLoaded', function() {
options: {
responsive: true,
maintainAspectRatio: false,
+ interaction: {
+ intersect: false,
+ mode: 'index'
+ },
plugins: {
legend: {
position: 'top',
@@ -576,103 +641,263 @@ document.addEventListener('DOMContentLoaded', function() {
});
}
- // Satellite Statistics
+ // Satellite Statistics with selection
const satelliteStats = {{ satellite_stats_json|safe }};
-
- // Pie Chart (top 10)
- const top10Stats = satelliteStats.slice(0, 10);
- const otherPoints = satelliteStats.slice(10).reduce((sum, s) => sum + s.points_count, 0);
-
- const pieLabels = top10Stats.map(s => s.parameter_obj__id_satellite__name);
- const pieData = top10Stats.map(s => s.points_count);
-
- if (otherPoints > 0) {
- pieLabels.push('Другие');
- pieData.push(otherPoints);
- }
+ const satelliteSettingsKey = 'statistics_satellite_selection';
const colors = [
'#0d6efd', '#198754', '#dc3545', '#ffc107', '#0dcaf0',
'#6f42c1', '#fd7e14', '#20c997', '#6c757d', '#d63384', '#adb5bd'
];
- if (pieData.length > 0) {
- new Chart(document.getElementById('satellitePieChart'), {
- type: 'doughnut',
- data: {
- labels: pieLabels,
- datasets: [{
- data: pieData,
- backgroundColor: colors.slice(0, pieData.length)
- }]
- },
- options: {
- responsive: true,
- plugins: {
- legend: {
- position: 'right',
- },
- datalabels: {
- color: '#fff',
- font: {
- weight: 'bold',
- size: 11
- },
- formatter: function(value, context) {
- const total = context.dataset.data.reduce((a, b) => a + b, 0);
- const percentage = ((value / total) * 100).toFixed(1);
- if (percentage < 5) return '';
- return value + '\n(' + percentage + '%)';
- },
- textAlign: 'center'
- }
- }
+ let pieChart = null;
+ let barChart = null;
+
+ // Load satellite selection settings
+ function loadSatelliteSettings() {
+ const saved = localStorage.getItem(satelliteSettingsKey);
+ if (saved) {
+ try {
+ return JSON.parse(saved);
+ } catch (e) {
+ console.warn('Failed to parse satellite settings:', e);
}
+ }
+ // Default: all satellites selected
+ return satelliteStats.reduce((acc, stat) => {
+ acc[stat.parameter_obj__id_satellite__name] = true;
+ return acc;
+ }, {});
+ }
+
+ // Save satellite selection settings
+ function saveSatelliteSettings(settings) {
+ localStorage.setItem(satelliteSettingsKey, JSON.stringify(settings));
+ }
+
+ // Initialize satellite checkboxes
+ function initSatelliteCheckboxes() {
+ const container = document.getElementById('satellite-checkboxes');
+ const settings = loadSatelliteSettings();
+
+ container.innerHTML = '';
+ satelliteStats.forEach((stat, index) => {
+ const satelliteName = stat.parameter_obj__id_satellite__name;
+ const isChecked = settings[satelliteName] !== false;
+
+ const checkboxHtml = `
+
+
+
+
+ `;
+ container.insertAdjacentHTML('beforeend', checkboxHtml);
+ });
+
+ // Add event listeners
+ container.querySelectorAll('.satellite-checkbox').forEach(checkbox => {
+ checkbox.addEventListener('change', function() {
+ const settings = loadSatelliteSettings();
+ settings[this.value] = this.checked;
+ saveSatelliteSettings(settings);
+ updateCharts();
+ });
});
}
- // Bar Chart (top 10) with data labels
- if (top10Stats.length > 0) {
- new Chart(document.getElementById('satelliteBarChart'), {
- type: 'bar',
- data: {
- labels: top10Stats.map(s => s.parameter_obj__id_satellite__name),
- datasets: [{
- label: 'Количество точек',
- data: top10Stats.map(s => s.points_count),
- backgroundColor: colors.slice(0, top10Stats.length)
- }]
- },
- options: {
- responsive: true,
- indexAxis: 'y',
- plugins: {
- legend: {
- display: false
- },
- datalabels: {
- anchor: 'end',
- align: 'end',
- color: '#333',
- font: {
- weight: 'bold',
- size: 11
+ // Get filtered satellite data based on selection
+ function getFilteredSatelliteData() {
+ const settings = loadSatelliteSettings();
+ return satelliteStats.filter(stat => settings[stat.parameter_obj__id_satellite__name] !== false);
+ }
+
+ // Update charts based on satellite selection
+ function updateCharts() {
+ const filteredStats = getFilteredSatelliteData();
+
+ // Update pie chart
+ if (pieChart) {
+ const pieLabels = filteredStats.map(s => s.parameter_obj__id_satellite__name);
+ const pieData = filteredStats.map(s => s.points_count);
+ const pieColors = filteredStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]);
+
+ pieChart.data.labels = pieLabels;
+ pieChart.data.datasets[0].data = pieData;
+ pieChart.data.datasets[0].backgroundColor = pieColors;
+ pieChart.update();
+ }
+
+ // Update bar chart (limit to top 15 for readability)
+ if (barChart) {
+ const topStats = filteredStats.slice(0, 15);
+ const barLabels = topStats.map(s => s.parameter_obj__id_satellite__name);
+ const barData = topStats.map(s => s.points_count);
+ const barColors = topStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]);
+
+ barChart.data.labels = barLabels;
+ barChart.data.datasets[0].data = barData;
+ barChart.data.datasets[0].backgroundColor = barColors;
+ barChart.update();
+ }
+ }
+
+ // Initialize charts
+ function initCharts() {
+ const filteredStats = getFilteredSatelliteData();
+
+ // Pie Chart
+ if (filteredStats.length > 0) {
+ const pieLabels = filteredStats.map(s => s.parameter_obj__id_satellite__name);
+ const pieData = filteredStats.map(s => s.points_count);
+ const pieColors = filteredStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]);
+
+ pieChart = new Chart(document.getElementById('satellitePieChart'), {
+ type: 'doughnut',
+ data: {
+ labels: pieLabels,
+ datasets: [{
+ data: pieData,
+ backgroundColor: pieColors
+ }]
+ },
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'right',
+ labels: {
+ boxWidth: 12,
+ font: {
+ size: 11
+ }
+ }
},
- formatter: function(value) {
- return value;
+ 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'
}
}
+ }
+ });
+ }
+
+ // Bar Chart (top 15)
+ if (filteredStats.length > 0) {
+ const topStats = filteredStats.slice(0, 15);
+ const barLabels = topStats.map(s => s.parameter_obj__id_satellite__name);
+ const barData = topStats.map(s => s.points_count);
+ const barColors = topStats.map((s, i) => colors[satelliteStats.indexOf(s) % colors.length]);
+
+ barChart = new Chart(document.getElementById('satelliteBarChart'), {
+ type: 'bar',
+ data: {
+ labels: barLabels,
+ datasets: [{
+ label: 'Количество точек',
+ data: barData,
+ backgroundColor: barColors
+ }]
},
- scales: {
- x: {
- beginAtZero: true,
- grace: '10%'
+ 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: 11
+ },
+ formatter: function(value) {
+ return value;
+ }
+ }
+ },
+ scales: {
+ x: {
+ beginAtZero: true,
+ grace: '10%'
+ }
}
}
- }
- });
+ });
+ }
}
+ // Satellite selection buttons
+ function initSatelliteButtons() {
+ const selectAllSatBtn = document.getElementById('select-all-satellites');
+ const selectTop10Btn = document.getElementById('select-top10-satellites');
+ const clearSatBtn = document.getElementById('clear-satellites');
+
+ if (selectAllSatBtn) {
+ selectAllSatBtn.addEventListener('click', function() {
+ const settings = {};
+ satelliteStats.forEach(stat => {
+ settings[stat.parameter_obj__id_satellite__name] = true;
+ });
+ saveSatelliteSettings(settings);
+ initSatelliteCheckboxes();
+ updateCharts();
+ });
+ }
+
+ if (selectTop10Btn) {
+ selectTop10Btn.addEventListener('click', function() {
+ const settings = {};
+ satelliteStats.forEach((stat, index) => {
+ settings[stat.parameter_obj__id_satellite__name] = index < 10;
+ });
+ saveSatelliteSettings(settings);
+ initSatelliteCheckboxes();
+ updateCharts();
+ });
+ }
+
+ if (clearSatBtn) {
+ clearSatBtn.addEventListener('click', function() {
+ const settings = {};
+ satelliteStats.forEach(stat => {
+ settings[stat.parameter_obj__id_satellite__name] = false;
+ });
+ saveSatelliteSettings(settings);
+ initSatelliteCheckboxes();
+ updateCharts();
+ });
+ }
+ }
+
+ // Initialize satellite functionality
+ initSatelliteCheckboxes();
+ initSatelliteButtons();
+ initCharts();
+
+ // Note: Zoom functionality temporarily disabled due to plugin loading issues
+ // Can be re-enabled when zoom plugin is properly configured
+
// Settings functionality
const settingsKey = 'statistics_display_settings_detailed';
diff --git a/dbapp/mainapp/views/api.py b/dbapp/mainapp/views/api.py
index 77158f9..28d05b5 100644
--- a/dbapp/mainapp/views/api.py
+++ b/dbapp/mainapp/views/api.py
@@ -199,8 +199,8 @@ class SourceObjItemsAPIView(LoginRequiredMixin, View):
'source_objitems__transponder',
'source_objitems__created_by__user',
'source_objitems__updated_by__user',
- 'marks',
- 'marks__created_by__user'
+ # 'marks',
+ # 'marks__created_by__user'
).get(id=source_id)
# Get all related ObjItems, sorted by created_at