From c2fed26ac78593ca9be25d19223a531deacecdd8 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 16 Jul 2024 12:05:53 -0400 Subject: [PATCH 1/4] feat(wip): timeseries search type --- src/app/components/header/header.module.ts | 4 +- .../timeseries-header.component.html | 2 +- .../map-controls/map-controls.component.html | 2 +- src/app/components/map/map.component.ts | 3 +- .../draw-selector.component.html | 4 +- .../draw-selector/draw-selector.component.ts | 11 +- .../interaction-selector.component.html | 7 - .../interaction-selector.component.ts | 4 - src/app/dialogs/timeseries/index.ts | 3 - .../timeseries/timeseries.component.html | 51 ------ .../timeseries/timeseries.component.scss | 42 ----- .../timeseries/timeseries.component.ts | 147 ------------------ src/app/models/search.model.ts | 4 + src/app/pipes/filter-type.pipe.ts | 10 +- .../services/polygon-validation.service.ts | 5 + src/app/store/search/search.effect.ts | 4 +- src/app/store/user/user.effect.ts | 13 +- 17 files changed, 52 insertions(+), 264 deletions(-) delete mode 100644 src/app/dialogs/timeseries/index.ts delete mode 100644 src/app/dialogs/timeseries/timeseries.component.html delete mode 100644 src/app/dialogs/timeseries/timeseries.component.scss delete mode 100644 src/app/dialogs/timeseries/timeseries.component.ts diff --git a/src/app/components/header/header.module.ts b/src/app/components/header/header.module.ts index 9e6a9f20f..9a1ba1229 100644 --- a/src/app/components/header/header.module.ts +++ b/src/app/components/header/header.module.ts @@ -51,6 +51,7 @@ import { SarviewsEventTypeSelectorModule } from '@components/shared/selectors/sa import { Hyp3UrlModule } from '@components/shared/hyp3-url/hyp3-url.module'; import { SharedModule } from "@shared"; import { LanguageSelectorModule } from "@components/shared/selectors/language-selector/language-selector.module"; +import { BurstSelectorModule } from '@components/shared/selectors/burst-selector'; @NgModule({ declarations: [ @@ -100,7 +101,8 @@ import { LanguageSelectorModule } from "@components/shared/selectors/language-se Hyp3UrlModule, SharedModule, LanguageSelectorModule, - OnDemandUserSelectorModule + OnDemandUserSelectorModule, + BurstSelectorModule ], exports: [ HeaderComponent diff --git a/src/app/components/header/timeseries-header/timeseries-header.component.html b/src/app/components/header/timeseries-header/timeseries-header.component.html index 29c300301..5f0e48e05 100644 --- a/src/app/components/header/timeseries-header/timeseries-header.component.html +++ b/src/app/components/header/timeseries-header/timeseries-header.component.html @@ -7,7 +7,7 @@ -
+
diff --git a/src/app/components/map/map.component.ts b/src/app/components/map/map.component.ts index 12ed68f34..eea5bd722 100644 --- a/src/app/components/map/map.component.ts +++ b/src/app/components/map/map.component.ts @@ -32,7 +32,6 @@ import { StyleLike } from 'ol/style/Style'; import { Feature } from 'ol'; import Geometry from 'ol/geom/Geometry'; import { MatDialog } from '@angular/material/dialog'; -import { TimeseriesComponent} from '../../dialogs/timeseries' enum FullscreenControls { MAP = 'Map', @@ -282,7 +281,7 @@ export class MapComponent implements OnInit, OnDestroy { this.netcdfService.getTimeSeries(mousePos).pipe( first() ).subscribe( - response => this.dialog.open(TimeseriesComponent, {data: response}) + response => console.log(response) ); } ) diff --git a/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.html b/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.html index 9dd3bc86a..29cfb3f37 100644 --- a/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.html +++ b/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.html @@ -28,8 +28,9 @@ place {{ 'PLACE_A_POINT' | translate }} + @if(searchType !== searchTypes.TIMESERIES) { - + } diff --git a/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.ts b/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.ts index 6eb390697..887f1fbfc 100644 --- a/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.ts +++ b/src/app/components/shared/aoi-options/draw-selector/draw-selector.component.ts @@ -5,9 +5,10 @@ import { Store } from '@ngrx/store'; import { AppState } from '@store'; import * as mapStore from '@store/map'; import * as uiStore from '@store/ui'; +import * as searchStore from '@store/search'; import { ScreenSizeService } from '@services'; -import { MapDrawModeType, MapInteractionModeType, Breakpoints } from '@models'; +import { MapDrawModeType, MapInteractionModeType, Breakpoints, SearchType } from '@models'; @Component({ selector: 'app-draw-selector', @@ -20,6 +21,8 @@ export class DrawSelectorComponent implements OnInit, OnDestroy { private subs = new SubSink(); public breakpoint: Breakpoints; + public searchType: SearchType; + public searchTypes = SearchType; public breakpoints = Breakpoints; constructor( @@ -39,6 +42,12 @@ export class DrawSelectorComponent implements OnInit, OnDestroy { breakpoint => this.breakpoint = breakpoint ) ); + this.subs.add( + this.store$.select(searchStore.getSearchType).subscribe( + searchType => this.searchType = searchType + ) + ); + } public onNewDrawMode(mode: MapDrawModeType): void { diff --git a/src/app/components/shared/aoi-options/interaction-selector/interaction-selector.component.html b/src/app/components/shared/aoi-options/interaction-selector/interaction-selector.component.html index 5e3ded783..e136af517 100644 --- a/src/app/components/shared/aoi-options/interaction-selector/interaction-selector.component.html +++ b/src/app/components/shared/aoi-options/interaction-selector/interaction-selector.component.html @@ -19,13 +19,6 @@ draw - - stacks - this.onNewInteractionMode( - this.interaction === MapInteractionModeType.TIMERSERIES ? MapInteractionModeType.NONE : MapInteractionModeType.TIMERSERIES - ) public onEditSelected = () => this.onNewInteractionMode( this.interaction === MapInteractionModeType.EDIT ? MapInteractionModeType.NONE : MapInteractionModeType.EDIT diff --git a/src/app/dialogs/timeseries/index.ts b/src/app/dialogs/timeseries/index.ts deleted file mode 100644 index 30ff178ad..000000000 --- a/src/app/dialogs/timeseries/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { TimeseriesComponent } from "./timeseries.component"; -export { TimeseriesComponent }; - diff --git a/src/app/dialogs/timeseries/timeseries.component.html b/src/app/dialogs/timeseries/timeseries.component.html deleted file mode 100644 index 5cfa73018..000000000 --- a/src/app/dialogs/timeseries/timeseries.component.html +++ /dev/null @@ -1,51 +0,0 @@ -
-
-
Timeseries Analysis
- -
- close -
- -
-
- - - -
- - - - - - - - - - - - - ,'' ,'' - - - - - - - - - - - - - - - - - - -
No. {{element.position}} Unwrapped Phase {{element.unwrapped_phase}} Interferometric Correlation {{element.interferometric_correlation}} Temporal Coherence {{element.temporal_coherence}}
- -
\ No newline at end of file diff --git a/src/app/dialogs/timeseries/timeseries.component.scss b/src/app/dialogs/timeseries/timeseries.component.scss deleted file mode 100644 index 7c067bc3d..000000000 --- a/src/app/dialogs/timeseries/timeseries.component.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "asf-theme"; - -.timeseries-dialog-wrapper { - display: flex; - flex-direction: column; - height: 100%; - } - - -.dialog-header { - @include themify($themes) { - color: themed('dark-primary-text'); - } - - display: flex; - flex-direction: row; - justify-content: space-between; - font-size: 22px !important; -} -.dl-close-x { - position: absolute; - top: 6px; - right: 12px; - text-align: right; - float: right; - cursor: pointer; - z-index: 100; - - @include themify($themes) { - color: themed("dark-primary-text"); - } -} -#timeseriesChart { - height: 460px; - width: 680px; -} - -::ng-deep .timeseries-base { - @include themify($themes) { - fill: lighten(themed('dark-primary-text'), 45%); - } -} \ No newline at end of file diff --git a/src/app/dialogs/timeseries/timeseries.component.ts b/src/app/dialogs/timeseries/timeseries.component.ts deleted file mode 100644 index e5b9fc481..000000000 --- a/src/app/dialogs/timeseries/timeseries.component.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { Component, Inject, OnInit } from '@angular/core'; - -import { MAT_DIALOG_DATA, MatDialogContent, MatDialogRef, MatDialogTitle } from '@angular/material/dialog'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTableModule } from '@angular/material/table'; -import * as models from '@models'; -import * as d3 from 'd3'; - -@Component({ - selector: 'app-timeseries', - standalone: true, - imports: [MatDialogTitle, MatDialogContent, MatTableModule, MatIconModule], - templateUrl: './timeseries.component.html', - styleUrl: './timeseries.component.scss' -}) -export class TimeseriesComponent implements OnInit { - public json_data: string = ''; - private svg?: any; - public dataSource = []; - public averageData = {}; - public displayedColumns: string[] = ['position', 'unwrapped_phase', 'interferometric_correlation', 'temporal_coherence'] - private currentTransform; - private zoom; - private clipContainer; - private width = 640; - private height = 400; - private x; - private y; - private xAxis; - private yAxis; - private dots; - private margin = { top: 10, right: 30, bottom: 60, left: 20 }; - - - - - - constructor(@Inject(MAT_DIALOG_DATA) public data: models.TimeSeriesResult, - private dialogRef: MatDialogRef,) { - this.json_data = JSON.stringify(data, null, " ") - console.log(data) - for (let i = 0; i < data.time_series.unwrapped_phase.length; i++) { - this.dataSource.push({ - 'position': i, - 'unwrapped_phase': data.time_series.unwrapped_phase[i], - 'interferometric_correlation': data.time_series.interferometric_correlation[i], - 'temporal_coherence': data.time_series.temporal_coherence[0] - }) - } - this.averageData = ({ - 'position': 'average', - ...data.averages - }) - } - - public ngOnInit(): void { - - - this.svg = d3.select('#timeseriesChart').append('svg') - .attr('width', this.width + this.margin.left + this.margin.right) - .attr('height', this.height + this.margin.top + this.margin.bottom) - .append('g') - .attr('transform', `translate(${this.margin.left}, ${this.margin.top})`); - this.drawChart() - - } - - - private drawChart() { - const marginBottom = 40; - - this.x = d3.scaleLinear() - .domain([1, 100]) - .range([0, this.width]); - this.xAxis = this.svg.append('g') - .attr('transform', `translate(0, ${this.height})`); - this.y = d3.scaleLinear() - .domain([1, 100]) - .range([this.height, 0]); - this.yAxis = this.svg.append('g'); - this.svg.append("g") - .attr("transform", `translate(0,${this.height - marginBottom})`) - - - this.clipContainer = this.svg.append('g') - .attr('clip-path', 'url(#clip)'); - this.dots = this.clipContainer.append('g'); - this.updateCircles(); - this.zoom = d3.zoom() - .extent([[0, 0], [this.width, this.height]]) - .on('zoom', (eve: d3.D3ZoomEvent) => { - this.currentTransform = eve.transform; - this.updateChart(); - }); - d3.select('#timeseriesChart').selectChild().call(this.zoom) - - this.svg.append('defs').append('SVG:clipPath') - .attr('id', 'clip') - .append('SVG:rect') - .attr('width', this.width) - .attr('height', this.height) - .attr('x', 0) - .attr('y', 0); - this.updateChart(); - } - - private updateChart() { - const newX = this.currentTransform?.rescaleX(this.x) ?? this.x; - const newY = this.currentTransform?.rescaleY(this.y) ?? this.y; - const smallChart = this.width > 400; - this.xAxis.call( - d3.axisBottom(newX) - .tickSize(-this.height) - .ticks(smallChart ? 10 : 5, 's') - ); - this.yAxis.call( - d3.axisLeft(newY) - .tickSize(-this.width) - .ticks(smallChart ? 10 : 5, 's') - ); - - this.dots.selectAll('circle').data(this.dataSource).join('circle') - .attr('cx', d => newX(d.unwrapped_phase )) - .attr('cy', d => newY(d.interferometric_correlation)); - - } - - private updateCircles() { - - const transformedY = this.currentTransform?.rescaleY(this.y) ?? this.y; - const transformedX = this.currentTransform?.rescaleX(this.x) ?? this.x; - this.dots.selectAll('circle').data(this.dataSource).join('circle') - .attr('cx', d => {return transformedX(d.unwrapped_phase)}) - .attr('cy', d => transformedY(d.interferometric_correlation)) - .attr('r', 5) - .attr('class', 'timeseries-base') - } - - public updateAxis(_axis, _value) { - - } - - - public onClose(): void { - this.dialogRef.close(); - } -} diff --git a/src/app/models/search.model.ts b/src/app/models/search.model.ts index 3bd7be3f4..62ae13a70 100644 --- a/src/app/models/search.model.ts +++ b/src/app/models/search.model.ts @@ -20,6 +20,7 @@ export type FilterType = BaselineFiltersType | CustomProductFiltersType | SbasFiltersType | + TimeseriesFiltersType | SarviewsFiltersType; export interface ListFiltersType { @@ -98,3 +99,6 @@ export interface SarviewsFiltersType { pinnedProductIDs: string[]; selectedEventID: string; } +export interface TimeseriesFiltersType { + fullBurstIDs: string[]; +} \ No newline at end of file diff --git a/src/app/pipes/filter-type.pipe.ts b/src/app/pipes/filter-type.pipe.ts index 2f95bfbc2..9bf4acaeb 100644 --- a/src/app/pipes/filter-type.pipe.ts +++ b/src/app/pipes/filter-type.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { BaselineFiltersType, FilterType, GeographicFiltersType, ListFiltersType, SbasFiltersType } from '@models'; +import { BaselineFiltersType, FilterType, GeographicFiltersType, ListFiltersType, SbasFiltersType, TimeseriesFiltersType } from '@models'; @Pipe({ name: 'baselineFilter' @@ -19,6 +19,14 @@ export class SBASFilterPipe implements PipeTransform { } } +@Pipe({ + name: 'TimeseriesFilter' +}) +export class TimeseriesFilterPipe implements PipeTransform { + transform(input: FilterType): TimeseriesFiltersType { + return input as TimeseriesFiltersType; + } +} @Pipe({ name: 'geographicFilter' }) diff --git a/src/app/services/polygon-validation.service.ts b/src/app/services/polygon-validation.service.ts index e4dcd677e..79d8c49da 100644 --- a/src/app/services/polygon-validation.service.ts +++ b/src/app/services/polygon-validation.service.ts @@ -50,6 +50,11 @@ export class PolygonValidationService { ).subscribe(_ => _); } + public validateTimeseriesSelection(_sceneWKt: string) { + this.mapService.searchPolygon$.pipe( + ) + } + private getErrorFrom(resp) { if (resp.error) { return resp.error; diff --git a/src/app/store/search/search.effect.ts b/src/app/store/search/search.effect.ts index 847f00214..df9e356f6 100644 --- a/src/app/store/search/search.effect.ts +++ b/src/app/store/search/search.effect.ts @@ -103,6 +103,7 @@ export class SearchEffects { if (searchType === SearchType.CUSTOM_PRODUCTS) { return this.customProductsQuery$(); } + this.logCountries(); return this.asfApiQuery$; @@ -231,7 +232,7 @@ export class SearchEffects { public setMapInteractionModeBasedOnSearchType = createEffect(() => this.actions$.pipe( ofType(SearchActionType.SET_SEARCH_TYPE_AFTER_SAVE), - filter(action => action.payload === models.SearchType.DATASET), + filter(action => action.payload === models.SearchType.DATASET || action.payload === models.SearchType.TIMESERIES), map(_ => new mapStore.SetMapInteractionMode(models.MapInteractionModeType.DRAW)) )); @@ -428,6 +429,7 @@ export class SearchEffects { ); } + private nextCustomProduct$(next: string, latestScenes: models.CMRProduct[]): Observable { return this.hyp3Service.getJobsByUrl$(next).pipe( switchMap( diff --git a/src/app/store/user/user.effect.ts b/src/app/store/user/user.effect.ts index 06a437465..5b478c82a 100644 --- a/src/app/store/user/user.effect.ts +++ b/src/app/store/user/user.effect.ts @@ -14,7 +14,7 @@ import * as filterStore from '@store/filters'; import * as searchStore from '@store/search'; import { UserDataService } from '@services/user-data.service'; import * as models from '@models'; -import { BaselineFiltersType, GeographicFiltersType, SbasFiltersType, SearchType } from '@models'; +import { BaselineFiltersType, GeographicFiltersType, SbasFiltersType, TimeseriesFiltersType, SearchType } from '@models'; @Injectable() export class UserEffects { @@ -236,6 +236,8 @@ export class UserEffects { case SearchType.SBAS: actions = this.setSBASFilters(targetFilter.filters as SbasFiltersType); break; + case SearchType.TIMESERIES: + actions = this.setTimeseriesFilters(targetFilter.filters as TimeseriesFiltersType); default: break; } @@ -348,6 +350,15 @@ export class UserEffects { new filterStore.SetPerpendicularEnd(sbasFilter.perpendicular) ]; + return actions; + } + private setTimeseriesFilters(timeseriesFilter: TimeseriesFiltersType) { + + + const actions = [ + new filterStore.setFullBurst(timeseriesFilter.fullBurstIDs), + ] + return actions; } } From f1407c384caac136aee5a7976f76f15300f76032 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 16 Jul 2024 12:06:23 -0400 Subject: [PATCH 2/4] feat: search type api setup --- .../filters-dropdown.component.html | 7 ++ .../filters-dropdown.module.ts | 2 + .../timeseries-filters/index.ts | 2 + .../timeseries-filters.component.html | 21 ++++++ .../timeseries-filters.component.scss | 0 .../timeseries-filters.component.ts | 67 +++++++++++++++++++ .../timeseries-filters.module.ts | 38 +++++++++++ src/app/services/search-params.service.ts | 17 ++++- src/app/store/scenes/scenes.reducer.ts | 2 + src/app/store/search/search.action.ts | 8 +++ src/app/store/search/search.effect.ts | 54 ++++++++++++++- src/styles/_variables.scss | 4 +- 12 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 src/app/components/filters-dropdown/timeseries-filters/index.ts create mode 100644 src/app/components/filters-dropdown/timeseries-filters/timeseries-filters.component.html create mode 100644 src/app/components/filters-dropdown/timeseries-filters/timeseries-filters.component.scss create mode 100644 src/app/components/filters-dropdown/timeseries-filters/timeseries-filters.component.ts create mode 100644 src/app/components/filters-dropdown/timeseries-filters/timeseries-filters.module.ts diff --git a/src/app/components/filters-dropdown/filters-dropdown.component.html b/src/app/components/filters-dropdown/filters-dropdown.component.html index 9e17fbc62..e7b0df435 100644 --- a/src/app/components/filters-dropdown/filters-dropdown.component.html +++ b/src/app/components/filters-dropdown/filters-dropdown.component.html @@ -33,6 +33,10 @@ {{ 'EVENT_SEARCH' | translate }} + + @if(selectedSearchType === searchTypes.TIMESERIES) { + {{ 'TIMESERIES_SEARCH' | translate }} + }
@@ -62,6 +66,9 @@ + @if(selectedSearchType === searchTypes.TIMESERIES) { + + }