components/control-panel/control-panel.component.ts
Control panel with form fields to call hazard service.
                OnInit
    
| selector | app-control-panel | 
            
| imports | 
                            NshmpHazardModelFormComponent
                            NshmpHazardLocationFormComponent
                            NshmpMapSelectSiteComponent
                            NshmpHazardSiteClassFormComponent
                            NshmpHazardReturnPeriodFormComponent
                            NshmpHazardTruncationFormComponent
                            NshmpHazardMaxDirectionFormComponent
                            NshmpControlPanelButtonsComponent
                            NshmpSectionComponent
                            MatFormField
                            MatLabel
                            MatSelect
                            MatOption
                            ReactiveFormsModule
                 | 
            
| templateUrl | ./control-panel.component.html | 
            
| styleUrl | ./control-panel.component.scss | 
            
                        Properties | 
                
                        Methods | 
                
                        
  | 
                
| ngOnInit | 
ngOnInit()
                 | 
            
| 
                         
                            Returns :          
                void
                         | 
            
| Private onModelChange | 
                        
                    onModelChange()
                 | 
            
| 
                         
                            Returns :          
                void
                         | 
            
| onSubmit | 
onSubmit()
                 | 
            
| 
                         On form submit. 
                            Returns :          
                void
                         | 
            
| Private destroyRef | 
                        Default value : inject(DestroyRef)
                     | 
                
| formGroup | 
                        Default value : this.service.formGroup
                     | 
                
| 
                     Form field state  | 
            
| imts | 
                        Default value : computed(() => this.service.usage()?.response.model.imts)
                     | 
                
| Private nshmpService | 
                        Default value : inject(NshmpService)
                     | 
                
| returnPeriodBounds | 
                        Default value : RETURN_PERIOD_BOUNDS
                     | 
                
| 
                     Max and min bounds for return periods  | 
            
| returnPeriods | 
                        Default value : RETURN_PERIODS
                     | 
                
| 
                     List of return periods  | 
            
| service | 
                        Default value : inject(AppService)
                     | 
                
| siteClasses | 
                        Default value : computed(() => this.service.usage()?.response?.model.siteClasses)
                     | 
                
| 
                     List of site class   | 
            
| siteClassPlaceHolder | 
                        Default value : nshmpUtils.selectPlaceHolder()
                     | 
                
| 
                     Site class select menu holder  | 
            
import {Component, computed, DestroyRef, inject, OnInit, Signal} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {ReactiveFormsModule} from '@angular/forms';
import {MatOption} from '@angular/material/core';
import {MatFormField, MatLabel} from '@angular/material/form-field';
import {MatSelect} from '@angular/material/select';
import {
  NshmpHazardLocationFormComponent,
  NshmpHazardMaxDirectionFormComponent,
  NshmpHazardModelFormComponent,
  NshmpHazardReturnPeriodFormComponent,
  NshmpHazardSiteClassFormComponent,
  NshmpHazardTruncationFormComponent,
} from '@ghsc/nshmp-lib-ng/hazard';
import {NshmpMapSelectSiteComponent, SelectSiteDialogData} from '@ghsc/nshmp-lib-ng/map';
import {
  NshmpControlPanelButtonsComponent,
  NshmpSectionComponent,
  NshmpService,
  nshmpUtils,
  RETURN_PERIOD_BOUNDS,
  RETURN_PERIODS,
} from '@ghsc/nshmp-lib-ng/nshmp';
import {SourceType, sourceTypeToCapitalCase} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/model';
import {combineLatest} from 'rxjs';
import {environment} from '../../../../../environments/environment';
import {AppService} from '../../services/app.service';
/**
 * Control panel with form fields to call hazard service.
 */
@Component({
  imports: [
    NshmpHazardModelFormComponent,
    NshmpHazardLocationFormComponent,
    NshmpMapSelectSiteComponent,
    NshmpHazardSiteClassFormComponent,
    NshmpHazardReturnPeriodFormComponent,
    NshmpHazardTruncationFormComponent,
    NshmpHazardMaxDirectionFormComponent,
    NshmpControlPanelButtonsComponent,
    NshmpSectionComponent,
    MatFormField,
    MatLabel,
    MatSelect,
    MatOption,
    ReactiveFormsModule,
  ],
  selector: 'app-control-panel',
  styleUrl: './control-panel.component.scss',
  templateUrl: './control-panel.component.html',
})
export class ControlPanelComponent implements OnInit {
  service = inject(AppService);
  private nshmpService = inject(NshmpService);
  private destroyRef = inject(DestroyRef);
  /** Max and min bounds for return periods */
  returnPeriodBounds = RETURN_PERIOD_BOUNDS;
  /** List of return periods */
  returnPeriods = RETURN_PERIODS;
  /** Site class select menu holder */
  siteClassPlaceHolder = nshmpUtils.selectPlaceHolder();
  /** Form field state */
  formGroup = this.service.formGroup;
  /** Data for select site component */
  selectSiteData: Signal<SelectSiteDialogData> = computed(() => {
    const usage = this.service.usage();
    const nshmService = this.service.nshmService();
    if (usage === null || nshmService === undefined) {
      return;
    }
    const services = environment.webServices.nshmpHazWs.services.curveServices;
    return {
      faultSectionsUrl: `${nshmService.url}${services.features}?featureType=FAULT&polygons=false&raw=true`,
      mapUrl: `${nshmService.url}${services.map}?raw=true`,
      sitesUrl: `${nshmService.url}${services.sites}?raw=true`,
    };
  });
  /** List of site class `Parameter`s */
  siteClasses = computed(() => this.service.usage()?.response?.model.siteClasses);
  /** Get available source types */
  sourceTypes = computed(() => {
    const serviceResponse = this.service.serviceResponse();
    if (serviceResponse === null || serviceResponse === undefined) {
      return [sourceTypeToCapitalCase(SourceType.TOTAL)];
    }
    return serviceResponse.response.hazardCurves[0].data.map(data => data.component);
  });
  imts = computed(() => this.service.usage()?.response.model.imts);
  ngOnInit(): void {
    const controls = this.formGroup.controls;
    controls.model.valueChanges
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(() => this.onModelChange());
    combineLatest([
      controls.latitude.valueChanges,
      controls.longitude.valueChanges,
      controls.vs30.valueChanges,
    ])
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(() => {
        this.service.resetState();
        const values = this.formGroup.getRawValue();
        if (values.latitude && values.longitude) {
          this.selectSiteData().site = {
            latitude: values.latitude,
            longitude: values.longitude,
          };
        }
      });
    combineLatest([
      controls.maxDirection.valueChanges,
      controls.truncate.valueChanges,
      controls.returnPeriod.valueChanges,
      controls.sourceType.valueChanges,
      controls.imt.valueChanges,
    ])
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(() => {
        this.service.createPlots();
      });
  }
  /**
   * On form submit.
   */
  onSubmit(): void {
    this.service.callService();
    this.nshmpService.selectPlotControl();
  }
  private onModelChange(): void {
    const {latitude, longitude} = this.formGroup.getRawValue();
    const latitudeBounds = this.service.usage().response.latitude;
    const longitudeBounds = this.service.usage().response.longitude;
    if (
      !(
        latitude >= latitudeBounds.min &&
        latitude <= latitudeBounds.max &&
        longitude >= longitudeBounds.min &&
        longitude <= longitudeBounds.max
      )
    ) {
      this.formGroup.patchValue({
        latitude: NaN,
        longitude: NaN,
      });
    }
    this.formGroup.controls.latitude.markAsPristine();
    this.formGroup.controls.longitude.markAsPristine();
    this.service.resetState();
  }
}
    <!-- Control Panel -->
<form class="height-full overflow-auto" [formGroup]="formGroup" (submit)="onSubmit()">
  <!-- Model -->
  <nshmp-hazard-model-form
    [modelControl]="formGroup.controls.model"
    [models]="service.availableModels()"
  />
  <!-- Latitude -->
  <nshmp-hazard-location-form
    class="latitude-input"
    [locationControl]="formGroup.controls.latitude"
    label="Latitude"
    [bounds]="service.usage()?.response?.latitude"
  />
  <!-- Longitude -->
  <nshmp-hazard-location-form
    class="longitude-input"
    [locationControl]="formGroup.controls.longitude"
    label="Longitude"
    [bounds]="service.usage()?.response?.longitude"
  />
  <!-- Select site -->
  <nshmp-map-select-site [data]="selectSiteData()" (siteSelect)="service.setLocation($event)" />
  <!-- Site Class -->
  <div class="grid-row grid-gap-1">
    <!-- Site classes -->
    <nshmp-hazard-site-class-form
      label="Site Class Presets"
      [siteClassControl]="formGroup.controls.siteClass"
      [siteClasses]="siteClasses()"
      [modelControl]="formGroup.controls.model"
      [vs30Control]="formGroup.controls.vs30"
      [vs30Bounds]="service.usage()?.response.vs30"
    />
  </div>
  <nshmp-section label="Plot Options">
    <!-- Return Period Controls -->
    <nshmp-hazard-return-period-form
      [returnPeriodControl]="formGroup.controls.returnPeriod"
      [commonReturnPeriodControl]="formGroup.controls.commonReturnPeriods"
    />
    <!-- Source Type Control -->
    <mat-form-field class="grid-col-12 source-type-select">
      <mat-label>Source Type</mat-label>
      <mat-select [formControl]="formGroup.controls.sourceType">
        @for (sourceType of sourceTypes(); track sourceType) {
          <mat-option [value]="sourceType">
            {{ sourceType }}
          </mat-option>
        }
      </mat-select>
    </mat-form-field>
    <!-- Imt Control -->
    <mat-form-field class="grid-col-12 imt-select">
      <mat-label>IMT for Sources</mat-label>
      <mat-select [formControl]="formGroup.controls.imt">
        @for (imt of imts(); track imt) {
          <mat-option [value]="imt.value">
            {{ imt.display }}
          </mat-option>
        }
      </mat-select>
    </mat-form-field>
    <!-- Truncation -->
    <nshmp-hazard-truncation-form [truncationControl]="formGroup.controls.truncate" />
    <!-- Max Direction -->
    <nshmp-hazard-max-direction-form [maxDirectionControl]="formGroup.controls.maxDirection" />
  </nshmp-section>
  <nshmp-control-panel-buttons
    [plotDisabled]="formGroup.invalid"
    [serviceCallInfo]="service.serviceCallInfo()"
    [resetDisabled]="formGroup.pristine"
    (resetClick)="service.resetControlPanel()"
  />
</form>