From 58cdcec6ed16c7b94f7746fbd1ed45b108b7a748 Mon Sep 17 00:00:00 2001 From: dhanabalan Date: Thu, 31 Jul 2025 16:52:58 +0530 Subject: [PATCH] Added trend chart analysis chart file --- app/Filament/Widgets/TrendChartAnalysis.php | 553 ++++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 app/Filament/Widgets/TrendChartAnalysis.php diff --git a/app/Filament/Widgets/TrendChartAnalysis.php b/app/Filament/Widgets/TrendChartAnalysis.php new file mode 100644 index 000000000..f384e715a --- /dev/null +++ b/app/Filament/Widgets/TrendChartAnalysis.php @@ -0,0 +1,553 @@ + [], + 'datasets' => [], + ]; + } + + $fromDateTime = Carbon::parse($fromDatetime); + $toDateTime = Carbon::parse($toDatetime); + + if ($fromDateTime->gt($toDateTime) || $fromDateTime->gt(now()) || $toDateTime->gt(now())) { + return [ + 'labels' => [], + 'datasets' => [], + ]; + } + + $durationHours = $fromDateTime->diffInHours($toDateTime); + //dd($durationHours); + if ($durationHours < 1 || $durationHours > 24) { + return [ + 'labels' => [], + 'datasets' => [], + ]; + } + + $intervalCount = $durationHours > 12 ? 12 : 10; + $intervalMinutes = $durationHours > 12 ? 120 : floor(($durationHours * 60) / $intervalCount); + + $labels = []; + + if ($parameter == 'Phase Voltage') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $voltageRYSummary = $dataAggregation('voltage_ry'); + $voltageYBSummary = $dataAggregation('voltage_yb'); + $voltageBRSummary = $dataAggregation('voltage_br'); + $frequencySummary = $dataAggregation('frequency'); + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'Voltage RY Min', 'Voltage RY Max', 'Voltage RY Avg', + 'Voltage YB Min', 'Voltage YB Max', 'Voltage YB Avg', + 'Voltage BR Min', 'Voltage BR Max', 'Voltage BR Avg', + 'Frequency Min', 'Frequency Max', 'Frequency Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $voltageRYSummary['min'], $voltageRYSummary['max'], $voltageRYSummary['avg'], + $voltageYBSummary['min'], $voltageYBSummary['max'], $voltageYBSummary['avg'], + $voltageBRSummary['min'], $voltageBRSummary['max'], $voltageBRSummary['avg'], + $frequencySummary['min'], $frequencySummary['max'], $frequencySummary['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else if ($parameter == 'Line Voltage') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $voltageRNSummary = $dataAggregation('voltage_r_n'); + $voltageYNSummary = $dataAggregation('voltage_y_n'); + $voltageBNSummary = $dataAggregation('voltage_b_n'); + $frequencySummary = $dataAggregation('frequency'); + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'Voltage RN Min', 'Voltage RN Max', 'Voltage RN Avg', + 'Voltage YN Min', 'Voltage YN Max', 'Voltage YN Avg', + 'Voltage BN Min', 'Voltage BN Max', 'Voltage BN Avg', + 'Frequency Min', 'Frequency Max', 'Frequency Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $voltageRNSummary['min'], $voltageRNSummary['max'], $voltageRNSummary['avg'], + $voltageYNSummary['min'], $voltageYNSummary['max'], $voltageYNSummary['avg'], + $voltageBNSummary['min'], $voltageBNSummary['max'], $voltageBNSummary['avg'], + $frequencySummary['min'], $frequencySummary['max'], $frequencySummary['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else if ($parameter == 'Current') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $curR = $dataAggregation('current_r'); + $curY = $dataAggregation('current_y'); + $curB = $dataAggregation('current_b'); + $curN = $dataAggregation('current_n'); + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'Current R Min', 'Current R Max', 'Current R Avg', + 'Current Y Min', 'Current Y Max', 'Current Y Avg', + 'Current B Min', 'Current B Max', 'Current B Avg', + 'Current N Min', 'Current N Max', 'Current N Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $curR['min'], $curR['max'], $curR['avg'], + $curY['min'], $curY['max'], $curY['avg'], + $curB['min'], $curB['max'], $curB['avg'], + $curN['min'], $curN['max'], $curN['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else if ($parameter == 'Active Power') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $activePowR = $dataAggregation('active_power_r'); + $activePowY = $dataAggregation('active_power_y'); + $activePowB = $dataAggregation('active_power_b'); + $activePowTot = $dataAggregation('active_power_total'); + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'ActivePow R Min', 'ActivePow R Max', 'ActivePow R Avg', + 'ActivePow Y Min', 'ActivePow Y Max', 'ActivePow Y Avg', + 'ActivePow B Min', 'ActivePow B Max', 'ActivePow B Avg', + 'ActivePow Tot Min', 'ActivePow Tot Max', 'ActivePow Tot Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $activePowR['min'], $activePowR['max'], $activePowR['avg'], + $activePowY['min'], $activePowY['max'], $activePowY['avg'], + $activePowB['min'], $activePowB['max'], $activePowB['avg'], + $activePowTot['min'], $activePowTot['max'], $activePowTot['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else if ($parameter == 'Power Factor') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $powFacR = $dataAggregation('power_factor_r'); + $powFacY = $dataAggregation('power_factor_y'); + $powFacB = $dataAggregation('power_factor_b'); + $powFacTot = $dataAggregation('power_factor_total'); + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'PowerFac R Min', 'PowerFac R Max', 'PowerFac R Avg', + 'PowerFac Y Min', 'PowerFac Y Max', 'PowerFac Y Avg', + 'PowerFac B Min', 'PowerFac B Max', 'PowerFac B Avg', + 'PowerFac Tot Min', 'PowerFac Tot Max', 'PowerFac Tot Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $powFacR['min'], $powFacR['max'], $powFacR['avg'], + $powFacY['min'], $powFacY['max'], $powFacY['avg'], + $powFacB['min'], $powFacB['max'], $powFacB['avg'], + $powFacTot['min'], $powFacTot['max'], $powFacTot['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else if ($parameter == 'Units') { + + // Helper function to get min, max, avg for a column with PostgreSQL casting + $dataAggregation = function (string $column) use ($fromDateTime, $toDateTime, $meterId) { + $min = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->min(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $max = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->max(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + $avg = MfmReading::whereBetween('created_at', [$fromDateTime, $toDateTime]) + ->where('mfm_meter_id', $meterId) + ->avg(\Illuminate\Support\Facades\DB::raw("{$column}::double precision")); + + return [ + 'min' => round($min ?? 0, 2), + 'max' => round($max ?? 0, 2), + 'avg' => round($avg ?? 0, 2), + ]; + }; + + // Get aggregated data for all relevant columns + $appEneRec = $dataAggregation('apparent_energy_received'); + $reaEneRec = $dataAggregation('reactive_energy_received'); + $actEneRec = $dataAggregation('active_energy_received'); + + + // Labels for each bar on X-axis (min, max, avg per column) + $labels = [ + 'AppEneRec Min', 'AppEneRec Max', 'AppEneRec Avg', + 'ReaEneRec Min', 'ReaEneRec Max', 'ReaEneRec Avg', + 'ActEneRec Min', 'ActEneRec Max', 'ActEneRec Avg', + ]; + + // Ordered data values matching labels above + $dataValues = [ + $appEneRec['min'], $appEneRec['max'], $appEneRec['avg'], + $reaEneRec['min'], $reaEneRec['max'], $reaEneRec['avg'], + $actEneRec['min'], $actEneRec['max'], $actEneRec['avg'], + ]; + + // Colors by aggregation type: Min - yellow, Max - green, Avg - blue + $aggregationColors = [ + 'rgba(204, 163, 0, 0.8)', // Darker yellow (Min) + 'rgba(30, 120, 120, 0.8)', // Darker teal/green (Max) + 'rgba(30, 90, 140, 0.8)', // Darker blue (Avg) + ]; + + // Each set of 3 bars per column repeats the colors: min, max, avg + $backgroundColorArray = []; + foreach (range(1, 4) as $group) { // 4 column groups + foreach ($aggregationColors as $color) { + $backgroundColorArray[] = $color; + } + } + + // Construct chart data structure + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => 'Phase Voltage & Frequency Stats', + // Bar values array: 12 bars total (4 groups × 3 stats each) + 'data' => $dataValues, + 'backgroundColor' => $backgroundColorArray, + 'borderColor' => array_map(fn ($clr) => str_replace('0.6', '1', $clr), $backgroundColorArray), + 'borderWidth' => 1, + ], + ], + ]; + } + else + { + $data = []; + $labels = []; + $currentStart = $fromDateTime->copy(); + return [ + 'labels' => $labels, + 'datasets' => [ + [ + 'label' => ucfirst(str_replace('_', ' ', $parameter)), + 'data' => $data, + 'backgroundColor' => 'rgba(75, 192, 192, 0.2)', + 'borderColor' => 'rgba(75, 192, 192, 1)', + 'fill' => false, + 'tension' => 0.3, + 'pointRadius' => 5, + 'pointHoverRadius' => 7, + ], + ], + ]; + } + } + protected function getOptions(): array + { + return [ + 'plugins' => [ + 'datalabels' => [ + 'anchor' => 'start', + 'align' => 'start', + 'offset' => -15, + 'color' => '#000', + 'font' => [ + 'weight' => 'bold', + ], + 'formatter' => RawJs::make('function(value) { + return value; + }'), + ], + ], + 'scales' => [ + 'y' => [ + 'beginAtZero' => true, + 'ticks' => [ + 'stepSize' => 1, + ], + ], + ], + ]; + } + + + + protected function getType(): string + { + return 'bar'; + } +}