Spaces:
Configuration error
Configuration error
| // main.js | |
| Chart.defaults.color = '#a0aabf'; | |
| Chart.defaults.font.family = "'Outfit', sans-serif"; | |
| let rawData = []; | |
| let voltageChart = null; | |
| let currentChart = null; | |
| const colors = { | |
| app1: 'rgba(0, 240, 255, 1)', // Neon Blue | |
| app2: 'rgba(189, 0, 255, 1)', // Purple | |
| app3: 'rgba(0, 255, 102, 1)', // Neon Green | |
| alert: 'rgba(255, 0, 85, 0.8)' // Red for alert | |
| }; | |
| document.addEventListener('DOMContentLoaded', () => { | |
| loadCSVData(); | |
| document.getElementById('apply-btn').addEventListener('click', updateDashboard); | |
| document.getElementById('csv-upload').addEventListener('change', handleFileUpload); | |
| }); | |
| function loadCSVData() { | |
| Papa.parse('donnees_appareils (1).csv', { | |
| download: true, | |
| header: true, | |
| dynamicTyping: true, | |
| skipEmptyLines: true, | |
| complete: function(results) { | |
| console.log("CSV Parsed:", results.data); | |
| rawData = results.data; | |
| // Vérifier si le CSV est valide (s'il contient bien la colonne 'Date') | |
| // PapaParse peut parfois lire une page d'erreur 404 comme un CSV | |
| if (rawData.length === 0 || !rawData[0] || !rawData[0].hasOwnProperty('Date')) { | |
| console.warn("Le fichier CSV est introuvable ou invalide. Affichage de l'upload manuel."); | |
| document.getElementById('upload-group').style.display = 'block'; | |
| return; | |
| } | |
| if (rawData.length > 0) { | |
| // Initialiser les dates min et max | |
| const dates = rawData.map(d => d.Date).filter(d => d); | |
| if (dates.length > 0) { | |
| const minDate = dates[0]; | |
| const maxDate = dates[dates.length - 1]; | |
| document.getElementById('start-date').value = minDate; | |
| document.getElementById('end-date').value = maxDate; | |
| document.getElementById('start-date').min = minDate; | |
| document.getElementById('start-date').max = maxDate; | |
| document.getElementById('end-date').min = minDate; | |
| document.getElementById('end-date').max = maxDate; | |
| } | |
| } | |
| initializeCharts(); | |
| updateDashboard(); | |
| }, | |
| error: function(err) { | |
| console.error("Erreur CSV:", err); | |
| document.getElementById('upload-group').style.display = 'block'; | |
| console.log("Affichage du champ de chargement manuel activé."); | |
| } | |
| }); | |
| } | |
| function handleFileUpload(event) { | |
| const file = event.target.files[0]; | |
| if (!file) return; | |
| Papa.parse(file, { | |
| header: true, | |
| dynamicTyping: true, | |
| skipEmptyLines: true, | |
| complete: function(results) { | |
| console.log("Uploaded CSV Parsed:", results.data); | |
| rawData = results.data; | |
| if (rawData.length > 0) { | |
| const dates = rawData.map(d => d.Date).filter(d => d); | |
| if (dates.length > 0) { | |
| const minDate = dates[0]; | |
| const maxDate = dates[dates.length - 1]; | |
| document.getElementById('start-date').value = minDate; | |
| document.getElementById('end-date').value = maxDate; | |
| document.getElementById('start-date').min = minDate; | |
| document.getElementById('start-date').max = maxDate; | |
| document.getElementById('end-date').min = minDate; | |
| document.getElementById('end-date').max = maxDate; | |
| } | |
| } | |
| if (!voltageChart || !currentChart) { | |
| initializeCharts(); | |
| } | |
| updateDashboard(); | |
| document.getElementById('upload-label').innerText = "Fichier chargé avec succès !"; | |
| document.getElementById('upload-label').style.color = "#00ff66"; | |
| }, | |
| error: function(err) { | |
| console.error("Erreur lors du parse du fichier uploadé:", err); | |
| alert("Erreur lors de la lecture du fichier uploadé."); | |
| } | |
| }); | |
| } | |
| function initializeCharts() { | |
| const ctxVoltage = document.getElementById('voltageChart').getContext('2d'); | |
| const ctxCurrent = document.getElementById('currentChart').getContext('2d'); | |
| const commonOptions = { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { position: 'top', labels: { color: '#fff', usePointStyle: true, boxWidth: 8 } }, | |
| tooltip: { mode: 'index', intersect: false, backgroundColor: 'rgba(20, 25, 40, 0.9)', titleColor: '#fff', bodyColor: '#a0aabf', borderColor: 'rgba(255,255,255,0.1)', borderWidth: 1 }, | |
| annotation: { annotations: {} } | |
| }, | |
| scales: { | |
| x: { grid: { color: 'rgba(255, 255, 255, 0.05)' }, title: { display: true, text: 'Date / Heure' } }, | |
| y: { grid: { color: 'rgba(255, 255, 255, 0.05)' } } | |
| }, | |
| elements: { line: { tension: 0.4, borderWidth: 2 }, point: { radius: 0, hitRadius: 10, hoverRadius: 6 } }, | |
| interaction: { mode: 'nearest', axis: 'x', intersect: false } | |
| }; | |
| voltageChart = new Chart(ctxVoltage, { | |
| type: 'line', data: { labels: [], datasets: [] }, | |
| options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, title: { display: true, text: 'Tension (V)' } } } } | |
| }); | |
| currentChart = new Chart(ctxCurrent, { | |
| type: 'line', data: { labels: [], datasets: [] }, | |
| options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, title: { display: true, text: 'Intensité (A)' } } } } | |
| }); | |
| } | |
| function updateDashboard() { | |
| if (!rawData || rawData.length === 0) return; | |
| const startDateStr = document.getElementById('start-date').value; | |
| const endDateStr = document.getElementById('end-date').value; | |
| const selectedAppareil = document.querySelector('input[name="appareil"]:checked').value; | |
| const threshVol = parseFloat(document.getElementById('threshold-voltage').value); | |
| const threshCur = parseFloat(document.getElementById('threshold-current').value); | |
| // Filtrer par date | |
| let filteredData = rawData; | |
| if (startDateStr && endDateStr) { | |
| filteredData = rawData.filter(d => { | |
| if (!d.Date) return false; | |
| // On peut comparer directement les strings YYYY-MM-DD | |
| return d.Date >= startDateStr && d.Date <= endDateStr; | |
| }); | |
| } | |
| const labels = filteredData.map(d => `${d.Date} ${d.Heure}`); | |
| // Calcul des sommes et préparation des datasets | |
| let sumVoltage = 0; | |
| let sumCurrent = 0; | |
| let voltDatasets = []; | |
| let currDatasets = []; | |
| // Fonction d'aide pour ajouter un dataset et cumuler les sommes | |
| const processAppareil = (appNum, color) => { | |
| const keyVol = `Tension_Appareil_${appNum}`; | |
| const keyCur = `Intensite_Appareil_${appNum}`; | |
| const volData = filteredData.map(d => { | |
| const val = parseFloat(d[keyVol]) || 0; | |
| sumVoltage += val; | |
| return val; | |
| }); | |
| const curData = filteredData.map(d => { | |
| const val = parseFloat(d[keyCur]) || 0; | |
| sumCurrent += val; | |
| return val; | |
| }); | |
| voltDatasets.push(createDataset(`Tension App ${appNum}`, volData, color)); | |
| currDatasets.push(createDataset(`Intensité App ${appNum}`, curData, color)); | |
| }; | |
| if (selectedAppareil === '1' || selectedAppareil === 'all') processAppareil(1, colors.app1); | |
| if (selectedAppareil === '2' || selectedAppareil === 'all') processAppareil(2, colors.app2); | |
| if (selectedAppareil === '3' || selectedAppareil === 'all') processAppareil(3, colors.app3); | |
| // Mise à jour de l'UI des sommes | |
| document.getElementById('sum-voltage').innerText = sumVoltage.toLocaleString('fr-FR', {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' V'; | |
| document.getElementById('sum-current').innerText = sumCurrent.toLocaleString('fr-FR', {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' A'; | |
| // Mise à jour des graphiques | |
| voltageChart.data.labels = labels; | |
| voltageChart.data.datasets = voltDatasets; | |
| setAlertAnnotation(voltageChart, threshVol); | |
| voltageChart.update(); | |
| currentChart.data.labels = labels; | |
| currentChart.data.datasets = currDatasets; | |
| setAlertAnnotation(currentChart, threshCur); | |
| currentChart.update(); | |
| } | |
| function createDataset(label, data, color) { | |
| return { | |
| label: label, | |
| data: data, | |
| borderColor: color, | |
| backgroundColor: color.replace('1)', '0.1)'), | |
| fill: true, | |
| pointBackgroundColor: color, | |
| pointBorderColor: '#fff', | |
| }; | |
| } | |
| function setAlertAnnotation(chartInstance, thresholdValue) { | |
| if (!isNaN(thresholdValue) && thresholdValue > 0) { | |
| chartInstance.options.plugins.annotation.annotations = { | |
| line1: { | |
| type: 'line', yMin: thresholdValue, yMax: thresholdValue, | |
| borderColor: colors.alert, borderWidth: 2, borderDash: [5, 5], | |
| label: { display: true, content: 'SEUIL ALERTE', position: 'end', backgroundColor: colors.alert, color: '#fff', font: { size: 10, weight: 'bold' } } | |
| } | |
| }; | |
| } else { | |
| chartInstance.options.plugins.annotation.annotations = {}; | |
| } | |
| } | |