197 lines
5.6 KiB
TypeScript
197 lines
5.6 KiB
TypeScript
|
|
import { Component, OnInit, ViewChild, ElementRef, ChangeDetectorRef } 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';
|
||
|
|
|
||
|
|
Chart.register(...registerables);
|
||
|
|
|
||
|
|
@Component({
|
||
|
|
selector: 'app-actualgraph',
|
||
|
|
standalone: true,
|
||
|
|
imports: [CommonModule],
|
||
|
|
templateUrl: './actualgraph.component.html',
|
||
|
|
styleUrls: ['./actualgraph.component.scss']
|
||
|
|
})
|
||
|
|
export class ActualgraphComponent implements OnInit {
|
||
|
|
@ViewChild('chartCanvas', { static: false }) chartCanvas?: ElementRef<HTMLCanvasElement>;
|
||
|
|
private chart: Chart | undefined;
|
||
|
|
selectedButton: string = 'npk1';
|
||
|
|
isLoading: boolean = true;
|
||
|
|
isNoData: boolean = false;
|
||
|
|
greeting = '';
|
||
|
|
|
||
|
|
constructor(
|
||
|
|
private sensorService: SensorService,
|
||
|
|
private cdr: ChangeDetectorRef
|
||
|
|
) {}
|
||
|
|
|
||
|
|
ngOnInit(): void {
|
||
|
|
this.updateGreeting();
|
||
|
|
this.loadData('npk1');
|
||
|
|
}
|
||
|
|
|
||
|
|
loadData(sensorType: string): void {
|
||
|
|
this.selectedButton = sensorType;
|
||
|
|
this.isLoading = true;
|
||
|
|
this.isNoData = false;
|
||
|
|
|
||
|
|
this.sensorService.getLatestData().subscribe(
|
||
|
|
(response: ApiResponse) => {
|
||
|
|
if (response.statusCode === 200) {
|
||
|
|
const selectedData = (response.data as { [key: string]: any[] })[sensorType];
|
||
|
|
|
||
|
|
if (selectedData && selectedData.length > 0) {
|
||
|
|
const npkData: ParameterSensor = selectedData[0];
|
||
|
|
|
||
|
|
if (sensorType === 'npk1' || sensorType === 'npk2') {
|
||
|
|
const actualData = [
|
||
|
|
{ x: npkData.soilnitrogen ?? 0, y: 0 },
|
||
|
|
{ x: npkData.soilphosphorus ?? 0, y: 1 },
|
||
|
|
{ x: npkData.soilpotassium ?? 0, y: 2 }
|
||
|
|
];
|
||
|
|
|
||
|
|
this.chartData.datasets[0].data = actualData;
|
||
|
|
this.isLoading = false;
|
||
|
|
this.cdr.detectChanges();
|
||
|
|
|
||
|
|
setTimeout(() => {
|
||
|
|
this.initializeChart();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
this.isNoData = true;
|
||
|
|
this.isLoading = false;
|
||
|
|
this.cdr.detectChanges();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
console.error('Error loading data: ', response.message);
|
||
|
|
this.isLoading = false;
|
||
|
|
this.cdr.detectChanges();
|
||
|
|
}
|
||
|
|
},
|
||
|
|
(error) => {
|
||
|
|
console.error('Error loading data:', error);
|
||
|
|
this.isLoading = false;
|
||
|
|
this.cdr.detectChanges();
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
private initializeChart(): void {
|
||
|
|
if (this.chartCanvas?.nativeElement) {
|
||
|
|
const ctx = this.chartCanvas.nativeElement.getContext('2d');
|
||
|
|
if (ctx) {
|
||
|
|
this.chart = new Chart(ctx, {
|
||
|
|
type: 'bar',
|
||
|
|
data: this.chartData,
|
||
|
|
options: this.chartOptions
|
||
|
|
});
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
console.warn('Chart canvas is not available');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
updateGreeting(): void {
|
||
|
|
const hour = new Date().getHours();
|
||
|
|
this.greeting = hour < 12 ? 'Good Morning' : hour < 18 ? 'Good Afternoon' : 'Good Evening';
|
||
|
|
}
|
||
|
|
|
||
|
|
public chartData = {
|
||
|
|
labels: ['Nitrogen', 'Phosphor', 'Kalium'],
|
||
|
|
datasets: [
|
||
|
|
{
|
||
|
|
label: 'Actual Data',
|
||
|
|
data: [],
|
||
|
|
backgroundColor: 'rgb(18, 55, 42)',
|
||
|
|
borderColor: 'rgb(18, 55, 42)',
|
||
|
|
borderWidth: 1,
|
||
|
|
type: 'bubble'
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Start Data Range',
|
||
|
|
data: [
|
||
|
|
{ x: 100, y: 0 },
|
||
|
|
{ x: 90, y: 1 },
|
||
|
|
{ x: 220, y: 2 }
|
||
|
|
],
|
||
|
|
backgroundColor: 'rgba(0,0,0,0)',
|
||
|
|
borderWidth: 0,
|
||
|
|
type: 'bar',
|
||
|
|
stack: 'range',
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Standard Data Range',
|
||
|
|
data: [
|
||
|
|
{ x: 100, y: 0 },
|
||
|
|
{ x: 35, y: 1 },
|
||
|
|
{ x: 200, y: 2 }
|
||
|
|
],
|
||
|
|
backgroundColor: 'rgb(212, 231, 197)',
|
||
|
|
borderWidth: 1,
|
||
|
|
type: 'bar',
|
||
|
|
stack: 'range'
|
||
|
|
}
|
||
|
|
]
|
||
|
|
};
|
||
|
|
|
||
|
|
public chartOptions = {
|
||
|
|
responsive: true,
|
||
|
|
maintainAspectRatio: false,
|
||
|
|
indexAxis: 'y',
|
||
|
|
scales: {
|
||
|
|
x: {
|
||
|
|
title: {
|
||
|
|
display: true,
|
||
|
|
text: 'Value (mg/L)',
|
||
|
|
},
|
||
|
|
min: 0,
|
||
|
|
max: 300,
|
||
|
|
type: 'linear',
|
||
|
|
},
|
||
|
|
y: {
|
||
|
|
title: {
|
||
|
|
display: true,
|
||
|
|
text: 'Sensor Parameter',
|
||
|
|
},
|
||
|
|
stacked: true,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
plugins: {
|
||
|
|
tooltip: {
|
||
|
|
callbacks: {
|
||
|
|
title: function (tooltipItem: any) {
|
||
|
|
return tooltipItem[0].label;
|
||
|
|
},
|
||
|
|
label: function (tooltipItem: any) {
|
||
|
|
const dataset = tooltipItem.dataset;
|
||
|
|
const dataIndex = tooltipItem.dataIndex;
|
||
|
|
const data = dataset.data[dataIndex];
|
||
|
|
|
||
|
|
let tooltipText = `Actual Value: ${data.x} mg/L`;
|
||
|
|
|
||
|
|
if (dataset.type === 'bar') {
|
||
|
|
const startRangeDataset = tooltipItem.chart.data.datasets.find((ds: any) => ds.label === 'Start Data Range');
|
||
|
|
const standardRangeDataset = tooltipItem.chart.data.datasets.find((ds: any) => ds.label === 'Standard Data Range');
|
||
|
|
|
||
|
|
const startRangeValue = startRangeDataset?.data.find((point: any) => point.y === data.y)?.x;
|
||
|
|
const standardRangeValue = standardRangeDataset?.data.find((point: any) => point.y === data.y)?.x;
|
||
|
|
|
||
|
|
if (startRangeValue !== undefined && standardRangeValue !== undefined) {
|
||
|
|
const minValue = startRangeValue;
|
||
|
|
const maxValue = startRangeValue + standardRangeValue;
|
||
|
|
tooltipText = `(Standard Range: ${minValue} - ${maxValue} mg/L)`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return tooltipText;
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
}
|