|
|
|
|
@ -1,11 +1,14 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using OxyPlot.Axes;
|
|
|
|
|
using SmartAquaViewer.Controls;
|
|
|
|
|
using SmartAquaViewer.DataAnalysis;
|
|
|
|
|
using SmartAquaViewer.Model;
|
|
|
|
|
|
|
|
|
|
@ -13,6 +16,9 @@ namespace SmartAquaViewer.ViewModel
|
|
|
|
|
{
|
|
|
|
|
public class EnergyViewModel : INotifyPropertyChanged
|
|
|
|
|
{
|
|
|
|
|
public GraphControlViewModel GraphControlVM { get; } = new GraphControlViewModel();
|
|
|
|
|
public ObservableCollection<GraphType> GraphTypes { get; }
|
|
|
|
|
|
|
|
|
|
public List<WaterQualityVO> WaterQualityList { get; set; }
|
|
|
|
|
|
|
|
|
|
private double _totalEnergy;
|
|
|
|
|
@ -141,37 +147,211 @@ namespace SmartAquaViewer.ViewModel
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int _selectedGraphIndex = -1;
|
|
|
|
|
public int SelectedGraphIndex
|
|
|
|
|
{
|
|
|
|
|
get => _selectedGraphIndex;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_selectedGraphIndex != value)
|
|
|
|
|
{
|
|
|
|
|
_selectedGraphIndex = value;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
// 인덱스가 바뀌면 enum도 맞춰준다
|
|
|
|
|
if (value >= 0 && value < GraphTypes.Count)
|
|
|
|
|
SelectedGraphType = GraphTypes[value];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private GraphType _selectedGraphType;
|
|
|
|
|
public GraphType SelectedGraphType
|
|
|
|
|
{
|
|
|
|
|
get => _selectedGraphType;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_selectedGraphType != value)
|
|
|
|
|
{
|
|
|
|
|
_selectedGraphType = value;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
OnPropertyChanged(nameof(ShowXSelector));
|
|
|
|
|
RebuildFieldCandidates();
|
|
|
|
|
|
|
|
|
|
var idx = GraphTypes.IndexOf(value);
|
|
|
|
|
if (idx != -1 && idx != _selectedGraphIndex)
|
|
|
|
|
{
|
|
|
|
|
_selectedGraphIndex = idx;
|
|
|
|
|
OnPropertyChanged(nameof(SelectedGraphIndex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private StepFieldKind _selectedKind = StepFieldKind.Sensor; // 기본값은 센서
|
|
|
|
|
public StepFieldKind SelectedKind
|
|
|
|
|
{
|
|
|
|
|
get => _selectedKind;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_selectedKind != value)
|
|
|
|
|
{
|
|
|
|
|
_selectedKind = value;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool ShowXSelector => SelectedGraphType == GraphType.SCATTER;
|
|
|
|
|
|
|
|
|
|
// [필드 후보 목록] 탭/시스템에 따라 달라짐
|
|
|
|
|
public ObservableCollection<FieldItem> AvailableFields { get; } = new();
|
|
|
|
|
|
|
|
|
|
// [X축 후보/선택]
|
|
|
|
|
public ObservableCollection<FieldItem> XFieldCandidates { get; } = new();
|
|
|
|
|
private FieldItem? _selectedXField;
|
|
|
|
|
public FieldItem? SelectedXField
|
|
|
|
|
{
|
|
|
|
|
get => _selectedXField;
|
|
|
|
|
set { if (_selectedXField != value) { _selectedXField = value; OnPropertyChanged(); } }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// [Y축 후보/선택] — Line/Step: 다중, Scatter/Box: 단일
|
|
|
|
|
public ObservableCollection<FieldItem> YFieldCandidates { get; } = new();
|
|
|
|
|
|
|
|
|
|
// 다중 선택(Y)용
|
|
|
|
|
public ObservableCollection<FieldItem> SelectedYFields { get; } = new();
|
|
|
|
|
|
|
|
|
|
// 단일 선택(Y)용
|
|
|
|
|
private FieldItem? _selectedYField;
|
|
|
|
|
public FieldItem? SelectedYField
|
|
|
|
|
{
|
|
|
|
|
get => _selectedYField;
|
|
|
|
|
set { if (_selectedYField != value) { _selectedYField = value; OnPropertyChanged(); } }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool _showMarkers; // Line
|
|
|
|
|
public bool ShowMarkers { get => _showMarkers; set { _showMarkers = value; OnPropertyChanged(); } }
|
|
|
|
|
|
|
|
|
|
private bool _showLegends;
|
|
|
|
|
public bool ShowLegends { get => _showLegends; set { _showLegends = value; OnPropertyChanged(); } }
|
|
|
|
|
|
|
|
|
|
public ICommand DrawGraphCommand { get; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public EnergyViewModel()
|
|
|
|
|
{
|
|
|
|
|
WaterQualityList = Datas.GetWaterQualityVO();
|
|
|
|
|
|
|
|
|
|
TotalSandFilterEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Filtering.SandFilterEnergy") ?? 0);
|
|
|
|
|
TotalCirculationPumpEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Filtering.CirculationPumpEnergy") ?? 0);
|
|
|
|
|
TotalHeatPumpEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Filtering.HeatPumpEnergy") ?? 0);
|
|
|
|
|
TotalAirBlowerEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Filtering.AirBlowerEnergy") ?? 0);
|
|
|
|
|
TotalOzoneGeneratorEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Sterilizing.OzoneGeneratorEnergy") ?? 0);
|
|
|
|
|
TotalUVSterilizerEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Sterilizing.UVSterilizerEnergy") ?? 0);
|
|
|
|
|
TotalOzoneDissolverEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Sterilizing.OzoneDissolverEnergy") ?? 0);
|
|
|
|
|
TotalExcessOzoneDestroyerEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "Sterilizing.ExcessOzoneDestroyerEnergy") ?? 0);
|
|
|
|
|
TotalEnergy = WaterQualityList.Sum(vo => ResolveEnergyField(vo, "TotalEnergy") ?? 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private double? ResolveEnergyField(WaterQualityVO vo, string fieldName)
|
|
|
|
|
{
|
|
|
|
|
return fieldName switch
|
|
|
|
|
{
|
|
|
|
|
"Filtering.SandFilterEnergy" => vo.Filtering.SandFilterEnergy,
|
|
|
|
|
"Filtering.CirculationPumpEnergy" => vo.Filtering.CirculationPumpEnergy,
|
|
|
|
|
"Filtering.HeatPumpEnergy" => vo.Filtering.HeatPumpEnergy,
|
|
|
|
|
"Filtering.AirBlowerEnergy" => vo.Filtering.AirBlowerEnergy,
|
|
|
|
|
"Sterilizing.OzoneGeneratorEnergy" => vo.Sterilizing.OzoneGeneratorEnergy,
|
|
|
|
|
"Sterilizing.UVSterilizerEnergy" => vo.Sterilizing.UVSterilizerEnergy,
|
|
|
|
|
"Sterilizing.OzoneDissolverEnergy" => vo.Sterilizing.OzoneDissolverEnergy,
|
|
|
|
|
"Sterilizing.ExcessOzoneDestroyerEnergy" => vo.Sterilizing.ExcessOzoneDestroyerEnergy,
|
|
|
|
|
"TotalEnergy" => vo.TotalEnergy,
|
|
|
|
|
_ => null
|
|
|
|
|
GraphTypes = new ObservableCollection<GraphType>
|
|
|
|
|
{
|
|
|
|
|
GraphType.LINE,
|
|
|
|
|
GraphType.STACKAREA,
|
|
|
|
|
GraphType.PIE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TotalSandFilterEnergy = WaterQualityList.Sum(vo => vo.Filtering.SandFilterEnergy);
|
|
|
|
|
TotalCirculationPumpEnergy = WaterQualityList.Sum(vo => vo.Filtering.CirculationPumpEnergy);
|
|
|
|
|
TotalHeatPumpEnergy = WaterQualityList.Sum(vo => vo.Filtering.HeatPumpEnergy);
|
|
|
|
|
TotalAirBlowerEnergy = WaterQualityList.Sum(vo => vo.Filtering.AirBlowerEnergy);
|
|
|
|
|
TotalOzoneGeneratorEnergy = WaterQualityList.Sum(vo => vo.Sterilizing.OzoneGeneratorEnergy);
|
|
|
|
|
TotalUVSterilizerEnergy = WaterQualityList.Sum(vo => vo.Sterilizing.UVSterilizerEnergy);
|
|
|
|
|
TotalOzoneDissolverEnergy = WaterQualityList.Sum(vo => vo.Sterilizing.OzoneDissolverEnergy);
|
|
|
|
|
TotalExcessOzoneDestroyerEnergy = WaterQualityList.Sum(vo => vo.Sterilizing.ExcessOzoneDestroyerEnergy);
|
|
|
|
|
TotalEnergy = WaterQualityList.Sum(vo => vo.TotalEnergy);
|
|
|
|
|
|
|
|
|
|
SelectedKind = StepFieldKind.Energy; // 기본적으로 에너지 관련 필드만 표시
|
|
|
|
|
|
|
|
|
|
DrawGraphCommand = new RelayCommand(DrawGraph);
|
|
|
|
|
|
|
|
|
|
RebuildAvailableFields();
|
|
|
|
|
RebuildFieldCandidates();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DrawGraph(object obj)
|
|
|
|
|
{
|
|
|
|
|
switch (SelectedGraphType)
|
|
|
|
|
{
|
|
|
|
|
case GraphType.LINE:
|
|
|
|
|
GraphControlVM.SetMultiLineGraph(WaterQualityList, SelectedYFields, ShowMarkers, ShowLegends);
|
|
|
|
|
break;
|
|
|
|
|
case GraphType.STACKAREA:
|
|
|
|
|
GraphControlVM.SetStackAreaPlot(WaterQualityList, SelectedYFields, ShowMarkers, ShowLegends);
|
|
|
|
|
break;
|
|
|
|
|
case GraphType.PIE:
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RebuildAvailableFields()
|
|
|
|
|
{
|
|
|
|
|
AvailableFields.Clear();
|
|
|
|
|
|
|
|
|
|
// 공통 시간
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "RecordedTime", Display = "시간", DataType = typeof(DateTime) });
|
|
|
|
|
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "TotalEnergy", Display = "총 전력", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Filtering.SandFilterEnergy", Display = "모래여과기", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Filtering.CirculationPumpEnergy", Display = "순환펌프", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Filtering.HeatPumpEnergy", Display = "히트펌프", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Filtering.AirBlowerEnergy", Display = "에어브로와", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Sterilizing.OzoneGeneratorEnergy", Display = "오존발생기", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Sterilizing.UVSterilizerEnergy", Display = "자외선 살균기", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Sterilizing.OzoneDissolverEnergy", Display = "오존용해장치", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
AvailableFields.Add(new FieldItem { Name = "Sterilizing.ExcessOzoneDestroyerEnergy", Display = "배오존장치", DataType = typeof(double), Kind = StepFieldKind.Energy });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RebuildFieldCandidates()
|
|
|
|
|
{
|
|
|
|
|
// 후보 초기화
|
|
|
|
|
XFieldCandidates.Clear();
|
|
|
|
|
YFieldCandidates.Clear();
|
|
|
|
|
|
|
|
|
|
// X축: 시간 우선
|
|
|
|
|
foreach (var f in AvailableFields)
|
|
|
|
|
{
|
|
|
|
|
XFieldCandidates.Add(f);
|
|
|
|
|
if (SelectedGraphType == GraphType.LINE || SelectedGraphType == GraphType.STACKAREA) break;
|
|
|
|
|
}
|
|
|
|
|
SelectedXField = AvailableFields.FirstOrDefault(f => f.DataType == typeof(DateTime))
|
|
|
|
|
?? AvailableFields.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
IEnumerable<FieldItem> src = AvailableFields.Where(f => f.Kind == SelectedKind);
|
|
|
|
|
|
|
|
|
|
if (SelectedGraphType is GraphType.LINE or GraphType.STACKAREA or GraphType.PIE)
|
|
|
|
|
{
|
|
|
|
|
// 수치형만 (LINE/STACKAREA/PIE 연속값 위주)
|
|
|
|
|
src = src.Where(f => f.DataType == typeof(double));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Y축 후보: 수치형
|
|
|
|
|
foreach (var f in src)
|
|
|
|
|
{
|
|
|
|
|
if (SelectedGraphType == GraphType.STACKAREA && f.Name.Equals("TotalEnergy")) continue;
|
|
|
|
|
YFieldCandidates.Add(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 기본 선택 세팅 (타입별)
|
|
|
|
|
SelectedYFields.Clear();
|
|
|
|
|
SelectedYField = null;
|
|
|
|
|
|
|
|
|
|
switch (SelectedGraphType)
|
|
|
|
|
{
|
|
|
|
|
case GraphType.LINE:
|
|
|
|
|
//var def = YFieldCandidates.FirstOrDefault();
|
|
|
|
|
//if (def != null) SelectedYFields.Add(def);
|
|
|
|
|
break;
|
|
|
|
|
case GraphType.STACKAREA:
|
|
|
|
|
SelectedYField = YFieldCandidates.FirstOrDefault();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GraphType.PIE:
|
|
|
|
|
SelectedYField = YFieldCandidates.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
OnPropertyChanged(nameof(SelectedYFields));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
|