import { Component, OnInit, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core'; import { Chart, registerables } from 'chart.js'; import { SensorService } from '../../../../cores/services/sensor.service'; import { ApiResponse, ParameterSensor} from '../../../../cores/interface/sensor-data'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; Chart.register(...registerables); const parameterColors: { [key: string]: string } = { vicitemperature: '#8F5A62', vicihumidity: '#16423C', viciluminosity: '#DF9B55', soiltemperature: '#8F5A62', soilhumidity: '#54909c', soilconductivity: '#661311', soilph: '#664735', soilnitrogen: '#3a6635', soilphosphorus: '#3f3566', soilpotassium: '#5f3566', }; @Component({ selector: 'app-graph', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './graph.component.html', styleUrls: ['./graph.component.scss'] }) export class GraphComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('myChart', { static: false }) chartElement!: ElementRef; selectedSensor: string = ''; selectedParameter: string = ''; parameters: string[] = []; isLoading: boolean = true; sensorParameters: { [key: string]: string[] } = { dht: ['vicitemperature', 'vicihumidity', 'viciluminosity'], npk1: ['soiltemperature', 'soilhumidity', 'soilconductivity', 'soilph', 'soilnitrogen', 'soilphosphorus', 'soilpotassium'], npk2: ['soiltemperature', 'soilhumidity', 'soilconductivity', 'soilph', 'soilnitrogen', 'soilphosphorus', 'soilpotassium'], }; parameterDisplayNames: { [key: string]: string } = { vicitemperature: 'Temperature (°C)', vicihumidity: 'Humidity (%)', viciluminosity: 'Luminosity (lux)', soiltemperature: 'Soil Temperature (°C)', soilhumidity: 'Soil Humidity (%)', soilconductivity: 'Conductivity (μS/cm)', soilph: 'pH', soilnitrogen: 'Nitrogen (PPM)', soilphosphorus: 'Phosphorus (PPM)', soilpotassium: 'Potassium (PPM)', }; chart: Chart | undefined; labelsHourly: string[] = []; private resizeListener!: () => void; constructor(private sensorService: SensorService) {} ngOnInit(): void { this.selectedSensor = 'dht'; this.updateParameters(); this.selectedParameter = 'vicitemperature'; this.updateChart(); this.resizeListener = this.onResize.bind(this); window.addEventListener('resize', this.resizeListener); } ngAfterViewInit(): void { this.updateChart(); } ngOnDestroy(): void { window.removeEventListener('resize', this.resizeListener); } onResize(): void { if (this.chart) { this.chart.destroy(); this.updateChart(); } } getDataFromResponse(response: ApiResponse, sensor: string, parameter: string): { data: number[], labels: string[] } { const sensorData = response.data[sensor as keyof typeof response.data]; const data: number[] = []; const labels: string[] = []; if (sensorData) { sensorData.forEach(item => { data.push(item[parameter as keyof ParameterSensor] ?? 0); labels.push(`${item.hour}.00`); }); } else { console.error('No data found for sensor:', sensor); } return { data, labels }; } createChart(data: number[], parameter: string, labels: string[]): void { const canvas = this.chartElement.nativeElement; const ctx = canvas.getContext('2d'); if (this.chart) { this.chart.destroy(); } if (ctx) { const displayName = this.parameterDisplayNames[parameter] || parameter; const borderColor = parameterColors[parameter] || '#000000'; const backgroundColor = `${borderColor}4D`; this.chart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: displayName, data, borderColor, borderWidth: 1.5, fill: true, backgroundColor, tension: 0.5, pointRadius: 0, pointHoverRadius: 0, pointBackgroundColor: borderColor, }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { tooltip: { enabled: true, mode: 'nearest', intersect: false, callbacks: { label: (tooltipItem) => { const paramLabel = displayName; const value = tooltipItem.formattedValue; return `${paramLabel}: ${value}`; } } }, legend: { display: false } }, scales: { x: { grid: { display: false }, beginAtZero: true }, y: { grid: { display: false }, beginAtZero: true } } } }); } } getParameterKey(displayName: string): string { return Object.keys(this.parameterDisplayNames).find(key => this.parameterDisplayNames[key] === displayName) || ''; } onSensorChange(event: Event): void { const select = event.target as HTMLSelectElement; this.selectedSensor = select.value; this.updateParameters(); if (this.selectedSensor === 'dht') { this.selectedParameter = 'vicitemperature'; } else if (this.selectedSensor === 'npk1' || this.selectedSensor === 'npk2') { this.selectedParameter = 'soiltemperature'; } this.updateChart(); } updateParameters(): void { this.parameters = this.sensorParameters[this.selectedSensor].map(param => this.parameterDisplayNames[param]); this.selectedParameter = this.parameters[1]; } updateChart(): void { this.isLoading = true; const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); const day = String(today.getDate()).padStart(2, '0'); const startEnd= `${year}-${month}-${day}`; const timeRange = 'HOURLY'; this.sensorService.getSensorData(this.selectedSensor, this.selectedParameter, startEnd, timeRange).subscribe( (response: ApiResponse) => { if (response.statusCode === 200) { const { data, labels } = this.getDataFromResponse(response, this.selectedSensor, this.selectedParameter); this.createChart(data, this.selectedParameter, labels); } else { console.error('Error fetching data:', response.message); } this.isLoading = false; }, (error) => { console.error('API Error:', error); this.isLoading = false; } ); } }