Skip to content
Snippets Groups Projects
metrics_charts.js 19.91 KiB
document.addEventListener('DOMContentLoaded', function() {
    function showAlert(message) {
        document.getElementById('alertMessage').textContent = message;
        $('#alertModal').modal('show');
    }
    function loadAndInitializeModal(taskId) {
        const container = document.getElementById('detailsModalContainer');

        const modalId = 'detailsModal';
        
        // Supprime l'ancien modal s'il existe
        const existingModal = container.querySelector(`#${modalId}`);
        if (existingModal) {
            existingModal.remove();
        }

        if (container.querySelector('#detailsModal')) {
            $('#detailsModal').modal('show');
            resetModal();
            initializeModal();
            return;
        }

        fetch(`/metric_details/${taskId}`)
            .then(response => {
                if (response.status === 404) {
                    showAlert('Aucun détail à afficher pour cette tâche.');
                    return; // Sortir de la fonction
                }
                return response.text();
            })
            .then(html => {
                container.innerHTML = html;
                $('#detailsModal').modal('show');
                resetModal();
                initializeModal();
            })
            .catch(error => console.error('Error loading modal content:', error));
    }

    function resetModal() {
        const typeSelect = document.getElementById('typeSelect');
        const chartTypeSelect = document.getElementById('chartTypeSelect');
        const dataTableContainer = document.getElementById('dataTableContainer');
        const chartContainer = document.getElementById('chartContainer');
        const userSelect = document.getElementById('userSelect');
        const timeSelect = document.getElementById('timeSelect');
        const customDateRange = document.getElementById('customDateRange');
        const startDate = document.getElementById('startDate');
        const endDate = document.getElementById('endDate');
    
        // Réinitialiser les sélections de type de données et de type de graphique
        if (typeSelect) {
            typeSelect.value = '';
        }
    
        if (chartTypeSelect) {
            chartTypeSelect.style.display = 'none';
            chartTypeSelect.value = ''; // Réinitialiser la sélection du type de graphique
        }
    
        // Réinitialiser les sélections d'utilisateurs
        if (userSelect) {
            $(userSelect).val(null).trigger('change'); // Utilise Select2 pour réinitialiser la sélection
        }
    
        // Réinitialiser la sélection de la période de temps
        if (timeSelect) {
            timeSelect.value = '';
        }
    
        // Réinitialiser les champs de date personnalisée
        if (customDateRange) {
            customDateRange.classList.add('d-none'); // Masquer les champs de date
        }
        if (startDate) {
            startDate.value = '';
        }
        if (endDate) {
            endDate.value = '';
        }
    
        // Réinitialiser l'affichage du tableau et du conteneur du graphique
        if (dataTableContainer) {
            dataTableContainer.style.display = 'none';
            const dataTable = document.getElementById('dataTable');
            if (dataTable) {
                dataTable.style.display = 'none';
            }
        }
    
        if (chartContainer) {
            chartContainer.style.display = 'none';
        }
    }
    

    function initializeModal() {
        console.log('Modal initialized');

        const typeSelect = document.getElementById('typeSelect');
        const chartTypeSelect = document.getElementById('chartTypeSelect');
        const userSelect = document.getElementById('userSelect');
        const timeSelect = document.getElementById('timeSelect');

        $('#userSelect').select2({
            placeholder: "Utilisateurs",
            allowClear: true,
            width: '100%', // Utiliser 100% pour une largeur cohérente
            closeOnSelect: false // Garder le sélecteur ouvert après une sélection
        });

        

        if (!typeSelect || !chartTypeSelect || !userSelect || !timeSelect) {
            console.error('Required select elements not found');
            return;
        }

        typeSelect.addEventListener('change', handleTypeChange);
        chartTypeSelect.addEventListener('click',  handleChartTypeChange );
        userSelect.addEventListener('change', handleDataFilter);
        timeSelect.addEventListener('change', handleDataFilter);

        function handleDataFilter(){            
            resetModal()
            filterData()
        }

        // Charger les données JSON
        const jsonDataElement = document.getElementById('jsonDataScript');
        if (!jsonDataElement) {
            console.error('JSON data script not found.');
            return;
        }
        window.data = JSON.parse(jsonDataElement.textContent);

        document.getElementById('timeSelect').addEventListener('change', function() {
            const selectedValue = this.value;
            const customDateRange = document.getElementById('customDateRange');
            
            if (selectedValue === 'custom') {
                customDateRange.classList.remove('d-none');
            } else {
                customDateRange.classList.add('d-none');
            }
        
            // Appeler la fonction de filtrage pour mettre à jour les données en fonction de la période sélectionnée
            filterData();
        });

    }

 
    function handleTypeChange(event) {
        const selectedType = event.target.value;
        console.log('Selected Type:', selectedType);
        const chartTypeSelect = document.getElementById('chartTypeSelect');
        chartTypeSelect.innerHTML = ''; // Réinitialiser les icônes de type de graphique

        if (selectedType) {
            const chartOptions = getChartOptionsForType(selectedType);
            chartOptions.forEach(option => {
                const iconButton = document.createElement('button');
                iconButton.className = 'btn btn-light'; // Utilisez les classes Bootstrap pour le style
                iconButton.innerHTML = `<i class="${option.icon}"></i>`;
                iconButton.value = option.value;
                iconButton.onclick = () => {
                    // Ajoutez ici la logique pour gérer le clic sur l'icône
                    console.log(`Selected chart type: ${option.value}`);
                };
                chartTypeSelect.appendChild(iconButton);
            });
            chartTypeSelect.style.display = ''; // Afficher le sélecteur de type de graphique
        }


        // Cacher le graphique et afficher le tableau
        const dataTableContainer = document.getElementById('dataTableContainer');
        if (dataTableContainer) {
            dataTableContainer.style.display = 'none';
            const dataTable = document.getElementById('dataTable');
            if (dataTable) {
                dataTable.style.display = 'none';
            }
        }

        const chartContainer = document.getElementById('chartContainer');
        if (chartContainer) {
            chartContainer.style.display = 'none';
        }

        // Filtrer les données
        filterData();
    }

    function getChartOptionsForType(type) {
        return [
            { value: 'table', label: 'Table', icon: 'bi bi-table' },
            { value: 'bar', label: 'Barres', icon: 'bi bi-bar-chart' },
            { value: 'line', label: 'Ligne', icon: 'bi bi-graph-up' },
            { value: 'pie', label: 'Camembert', icon: 'bi bi-pie-chart' },
            { value: 'doughnut', label: 'Donut', icon: 'bi bi-circle-fill' }, // Utilisation de 'circle-fill' pour le donut
            { value: 'radar', label: 'Radar', icon: 'bi bi-broadcast-pin' }, // Utilisation de 'broadcast-pin' pour le radar
            { value: 'polarArea', label: 'Zone Polaire', icon: 'bi bi-circle-half' }, // Utilisation de 'circle-half' pour la zone polaire
            { value: 'bubble', label: 'Bulle', icon: 'bi bi-chat-dots' }, // Utilisation de 'chat-dots' pour la bulle
            { value: 'scatter', label: 'Dispersion', icon: 'bi bi-grid-3x3' } // Utilisation de 'grid-3x3' pour la dispersion
        ];
    }
    


    function handleChartTypeChange(event) {
        
        if (event.target.tagName === 'BUTTON' || event.target.tagName === 'I') {
                const selectedButton = event.target.tagName === 'BUTTON' ? event.target : event.target.parentElement;
                const selectedValue = selectedButton.value;
                console.log(`Selected chart type: ${selectedValue}`);
                
                const selectedChartType = selectedValue;
                console.log('Selected Chart Type:', selectedChartType);

                const chartContainer = document.getElementById('chartContainer');
                const dataTableContainer = document.getElementById('dataTableContainer');
                const typeSelect = document.getElementById('typeSelect').value;

                if (selectedChartType === 'table') {
                    if (chartContainer) {
                        chartContainer.style.display = 'none';
                    }
                    if (dataTableContainer) {
                        dataTableContainer.style.display = '';
                        const dataTable = document.getElementById('dataTable');
                        if (dataTable) {
                            dataTable.style.display = '';
                        }
                        updateTable(); // Mettre à jour le tableau avec les données
                    }
                } else if (selectedChartType) {
                    if (chartContainer) {
                        chartContainer.style.display = '';
                    }
                    if (dataTableContainer) {
                        dataTableContainer.style.display = 'none';
                        const dataTable = document.getElementById('dataTable');
                        if (dataTable) {
                            dataTable.style.display = 'none';
                        }
                    }
                    updateChart(typeSelect, selectedChartType);
                } else {
                    if (chartContainer) {
                        chartContainer.style.display = 'none';
                    }
                    if (dataTableContainer) {
                        dataTableContainer.style.display = 'none';
                    }
                }
        }
        
        
    }

    function updateChart(type, chartType) {
        const canvas = document.getElementById('metricsChart');
        const ctx = canvas.getContext('2d');
    
        // Détruire le graphique existant, si nécessaire
        if (window.metricsChart && window.metricsChart instanceof Chart) {
            window.metricsChart.destroy(); // Détruire l'ancien graphique
        }
    
        // Réinitialiser le canvas pour éviter des problèmes de contexte
        canvas.width = canvas.width; // Réinitialiser le canvas
    
        const data = filterData(); // Utiliser les données filtrées
    
        if (data.length === 0) {
            console.log('No data available for chart.');
            return;
        }
    
        const formattedData = formatDataForChart(data, chartType);
    
        window.metricsChart = new Chart(ctx, {
            type: chartType,
            data: {
                labels: formattedData.labels,
                datasets: [{
                    label: 'Dataset',
                    data: formattedData.values,
                    backgroundColor: getChartColors(chartType, formattedData.labels.length),
                    borderColor: getChartColors(chartType, formattedData.labels.length, true),
                    borderWidth: 1
                }]
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true
                    }
                }
            }
        });
    }
    

    function formatDataForChart(data, chartType) {
        // Regrouper les données par type
        const groupedData = groupDataByValue(data);
    
        // Formater les données selon le type de graphique
        switch (chartType) {
            case 'bar':
            case 'horizontalBar':
                return formatBarData(groupedData);
            case 'line':
                return formatLineData(groupedData);
            case 'pie':
            case 'doughnut':
                return formatPieDoughnutData(groupedData);
            case 'radar':
                return formatRadarData(groupedData);
            case 'polarArea':
                return formatPolarAreaData(groupedData);
            case 'bubble':
                return formatBubbleData(groupedData);
            case 'scatter':
                return formatScatterData(groupedData);
            default:
                console.error(`Unsupported chart type: ${chartType}`);
                return { labels: [], values: [] };
        }
    }
    
    function groupDataByValue(data) {
        return data.reduce((acc, item) => {
            if (!acc[item.value]) {
                acc[item.value] = 0;
            }
            acc[item.value] += 1;
            return acc;
        }, {});
    }
    
    function formatBarData(groupedData) {
        const labels = Object.keys(groupedData);
        const values = labels.map(key => groupedData[key]);
    
        return {
            labels,
            values
        };
    }
    
    function formatLineData(groupedData) {
        const labels = Object.keys(groupedData);
        const values = labels.map(key => groupedData[key]);
    
        return {
            labels,
            values: values.map(value => ({ x: labels.indexOf(value.toString()) + 1, y: value }))
        };
    }
    
    function formatPieDoughnutData(groupedData) {
        const labels = Object.keys(groupedData);
        const values = labels.map(key => groupedData[key]);
    
        return {
            labels,
            values
        };
    }
    
    function formatRadarData(groupedData) {
        const labels = Object.keys(groupedData);
        const values = labels.map(key => groupedData[key]);
    
        return {
            labels,
            values
        };
    }
    
    function formatPolarAreaData(groupedData) {
        const labels = Object.keys(groupedData);
        const values = labels.map(key => groupedData[key]);
    
        return {
            labels,
            values
        };
    }
    
    function formatBubbleData(groupedData) {
        // Format pour les bulles : x, y, r
        const labels = Object.keys(groupedData);
        const values = labels.map((key, index) => ({
            x: index + 1, // Position en x
            y: groupedData[key],
            r: groupedData[key] // Taille des bulles
        }));
    
        return {
            labels,
            values
        };
    }
    
    function formatScatterData(groupedData) {
        // Format pour les graphiques de dispersion : x, y
        const labels = Object.keys(groupedData);
        const values = labels.map((key, index) => ({
            x: index + 1, // Position en x
            y: groupedData[key]
        }));
    
        return {
            labels,
            values
        };
    }
    

    function getChartColors(chartType, count, isBorder = false) {
        const colors = {
            bar: 'rgba(75, 192, 192, 0.2)',
            horizontalBar: 'rgba(75, 192, 192, 0.2)',
            line: 'rgba(75, 192, 192, 0.2)',
            pie: 'rgba(75, 192, 192, 0.2)',
            doughnut: 'rgba(75, 192, 192, 0.2)',
            radar: 'rgba(75, 192, 192, 0.2)',
            polarArea: 'rgba(75, 192, 192, 0.2)',
            bubble: 'rgba(75, 192, 192, 0.2)',
            scatter: 'rgba(75, 192, 192, 0.2)',
            area: 'rgba(75, 192, 192, 0.2)'
        };
        const borderColor = isBorder ? 'rgba(75, 192, 192, 1)' : colors[chartType] || 'rgba(0,0,0,0.1)';
        return Array(count).fill(borderColor);
    }

    function updateTable() {
        const table = document.getElementById('dataTable');
        const data = filterData(document.getElementById('typeSelect').value);
        const rows = data.map(item => `<tr><td>${item.type}</td><td>${item.value}</td></tr>`).join('');
        table.innerHTML = `<table class="table table-striped"><thead><tr><th>Type</th><th>Value</th></tr></thead><tbody>${rows}</tbody></table>`;
    }

    function filterData() {
        // Récupérer la sélection multiple des utilisateurs
        const userSelect = document.getElementById('userSelect');
        const userFilter = $(userSelect).val() || []; // Utilise jQuery pour obtenir les valeurs sélectionnées
        const timeSelect = document.getElementById('timeSelect').value || null;
        const type = document.getElementById('typeSelect').value || null;
    
        console.log('Filtering data based on DOM values.');
    
        const jsonDataElement = document.getElementById('jsonDataScript');
        if (!jsonDataElement) {
            console.error('JSON data script not found.');
            return [];
        }
        const jsonData = JSON.parse(jsonDataElement.textContent);
    
        // Fonction utilitaire pour vérifier si une valeur est considérée comme non fournie
        function isNotProvided(value) {
            return value === null || value === undefined || value === '';
        }
    
        // Fonction pour obtenir la date de début et de fin en fonction de la sélection de période
        function getDateRange(selection) {
            const now = new Date();
            let start = new Date();
            let end = new Date();
    
            switch (selection) {
                case 'today':
                    start = end = now;
                    break;
                case 'this_week':
                    start.setDate(now.getDate() - now.getDay());
                    end.setDate(start.getDate() + 6);
                    break;
                case 'this_month':
                    start.setDate(1);
                    end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
                    break;
                case 'this_year':
                    start = new Date(now.getFullYear(), 0, 1);
                    end = new Date(now.getFullYear(), 11, 31);
                    break;
                case 'custom':
                    start = new Date(document.getElementById('startDate').value);
                    end = new Date(document.getElementById('endDate').value);
                    break;
                default:
                    return { start: null, end: null };
            }
            return { start, end };
        }
    
        const { start, end } = getDateRange(timeSelect);
    
        // Filtrer les données en fonction des filtres
        const filteredData = jsonData.filter(item => {
            let match = true;
            if (!isNotProvided(type)) {
                match = match && item.type === type;
            }
            if (userFilter.length > 0) {
                if (userFilter.includes('all')) {
                    match = match && true; // Sélectionne tous les utilisateurs
                } else {
                    match = match && userFilter.includes(String(item.user_id));
                }
            }
            if (start && end) {
                const itemDate = new Date(item.date);
                console.log('Item date: ', itemDate, ' - start: ', start, ' - end: ', end)
                match = match && itemDate >= start && itemDate <= end;
            }
    
            return match;
        });
    
        if (filteredData.length === 0) {
            console.log('No data available for filtering.');
        } else {
            console.log('Filtered Data:', filteredData);
        }
        
    
        return filteredData;
    }
    
    

    document.querySelectorAll('.metrics-details').forEach(button => {
        button.addEventListener('click', function() {
            const taskId = this.dataset.task;
            loadAndInitializeModal(taskId);
        });
    });
});