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) { + + } -
+
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/services/search-params.service.ts b/src/app/services/search-params.service.ts index 2e14aa069..234c664e6 100644 --- a/src/app/services/search-params.service.ts +++ b/src/app/services/search-params.service.ts @@ -224,6 +224,19 @@ export class SearchParamsService { ) ); + private timeseriesParams$ = combineLatest([ + this.searchPolygon$, + this.burstParams$, + this.maxResults$, + this.selectedDataset$, + ]).pipe( + map((params: any[]) => params + .reduce( + (total, param) => ({ ...total, ...param }), + {}) + ) + ) + public getParams = combineLatest([ this.store$.select(getSearchType), @@ -231,8 +244,9 @@ export class SearchParamsService { ).pipe( withLatestFrom(this.listParam$), withLatestFrom(this.filterSearchParams$), + withLatestFrom(this.timeseriesParams$), map( - ([[[searchType, baselineParams], listParam], filterParams]) => { + ([[[[searchType, baselineParams], listParam], filterParams], timeseriesParams]) => { switch (searchType) { case models.SearchType.LIST: { return listParam; @@ -249,6 +263,9 @@ export class SearchParamsService { case models.SearchType.CUSTOM_PRODUCTS: { return listParam; } + case models.SearchType.TIMESERIES: { + return timeseriesParams; + } default: { return filterParams; } diff --git a/src/app/store/scenes/scenes.action.ts b/src/app/store/scenes/scenes.action.ts index 67c0ee523..dedb50ce6 100644 --- a/src/app/store/scenes/scenes.action.ts +++ b/src/app/store/scenes/scenes.action.ts @@ -8,6 +8,7 @@ export enum ScenesActionType { CLEAR = '[Granules] Clear Scenes', SET_SARVIEWS_EVENTS = '[SARViews] Set SARViews Events', SET_SARVIEWS_EVENT_PRODUCTS = '[SARViews] Set Selected SARViews Event Products', + SET_TIMESERIES_PRODUCTS = '[Timeseries] Set Selected Timeseries Products', SET_IMAGE_BROWSE_PRODUCTS = '[Products-Browse] Set product browse image view', diff --git a/src/app/store/scenes/scenes.reducer.ts b/src/app/store/scenes/scenes.reducer.ts index ac1e387dc..7073b57ea 100644 --- a/src/app/store/scenes/scenes.reducer.ts +++ b/src/app/store/scenes/scenes.reducer.ts @@ -19,6 +19,7 @@ export interface ScenesState { selectedPair: string[] | null; areResultsLoaded: boolean; scenes: {[id: string]: string[]}; + timeseriesResults: any; unzipped: {[id: string]: UnzippedFolder[]}; openUnzippedProduct: string | null; productUnzipLoading: string | null; @@ -49,6 +50,7 @@ export const initState: ScenesState = { openUnzippedProduct: null, products: {}, areResultsLoaded: false, + timeseriesResults: {}, selected: null, master: null, @@ -381,6 +383,7 @@ export function scenesReducer(state = initState, action: ScenesActions): ScenesS }; } + case ScenesActionType.SET_SELECTED_SARVIEW_PRODUCT: { return { ...state, diff --git a/src/app/store/search/search.action.ts b/src/app/store/search/search.action.ts index 08d206d25..32e9ba8b8 100644 --- a/src/app/store/search/search.action.ts +++ b/src/app/store/search/search.action.ts @@ -23,6 +23,7 @@ export enum SearchActionType { LOAD_ON_DEMAND_SCENES_LIST = '[Search] Load on Demand Scenes List', SARVIEWS_SEARCH_RESPONSE = '[Search] SARViews Search Response', + TIMESERIES_SEARCH_RESPONSE = '[Search] Timeseries Search Response', MAKE_EVENT_PRODUCT_CMR_SEARCH = '[Search] Make a search for CMR Products with SARVIEWS Products', EVENT_PRODUCT_CMR_RESPONSE = '[Search] Event Monitoring CMR Search Response', SET_SEARCH_OUT_OF_DATE = '[Search] Set if Search is Out of Date' @@ -74,6 +75,12 @@ export class SarviewsEventsResponse implements Action { constructor(public payload: {events: SarviewsEvent[]}) {} } +export class TimeseriesSearchResponse implements Action { + public readonly type = SearchActionType.TIMESERIES_SEARCH_RESPONSE; + + constructor(public payload: any) {} +} + export class SearchError implements Action { public readonly type = SearchActionType.SEARCH_ERROR; @@ -132,4 +139,5 @@ export type SearchActions = | LoadOnDemandScenesList | SetSearchTypeAfterSave | SarviewsEventsResponse + | TimeseriesSearchResponse | SetSearchOutOfDate; diff --git a/src/app/store/search/search.effect.ts b/src/app/store/search/search.effect.ts index 847f00214..188b29074 100644 --- a/src/app/store/search/search.effect.ts +++ b/src/app/store/search/search.effect.ts @@ -10,12 +10,14 @@ import { map, withLatestFrom, switchMap, catchError, filter, first, tap, debounc import { AppState } from '../app.reducer'; import { SetSearchAmount, EnableSearch, DisableSearch, SetSearchType, SetNextJobsUrl, - Hyp3BatchResponse, SarviewsEventsResponse, SetSearchOutOfDate + Hyp3BatchResponse, SarviewsEventsResponse, SetSearchOutOfDate, + TimeseriesSearchResponse } from './search.action'; import * as scenesStore from '@store/scenes'; import * as filtersStore from '@store/filters'; import * as mapStore from '@store/map'; import * as uiStore from '@store/ui'; +import moment2 from 'moment'; import * as services from '@services'; @@ -52,6 +54,7 @@ export class SearchEffects { private sarviewsService: services.SarviewsEventsService, private http: HttpClient, private notificationService: services.NotificationService, + private netCdfService: services.NetcdfServiceService ) { } public clearMapInteractionModeOnSearch = createEffect(() => this.actions$.pipe( @@ -103,6 +106,11 @@ export class SearchEffects { if (searchType === SearchType.CUSTOM_PRODUCTS) { return this.customProductsQuery$(); } + if (searchType === SearchType.TIMESERIES) { + return this.timeseriesQuery$(); + } + + this.logCountries(); return this.asfApiQuery$; @@ -219,6 +227,103 @@ export class SearchEffects { ]) )); + // switchMap(action => { + // let output : any[] = [ + // new scenesStore.SetScenes({ + // products: action.payload.files, + // searchType: action.payload.searchType + // }) + // ]; + // if(action.payload.totalCount) { + // output.push(new SetSearchAmount(action.payload.totalCount)) + // } + // return output + // }) + + public timeseriesSearchResponse = createEffect(() => this.actions$.pipe( + ofType(SearchActionType.TIMESERIES_SEARCH_RESPONSE), + withLatestFrom(this.store$.select(getSearchType)), + filter(([_, searchType]) => searchType === SearchType.TIMESERIES), + switchMap(([action, _]) => { + console.log('SEARCH RESPONSE') + console.log(action) + + return [ + new scenesStore.SetScenes({ + products: [{ + name: "test", + productTypeDisplay: "test", + file: "test", + id: "test", + downloadUrl: "test", + bytes: 1234, + browses: [], + thumbnail: "string", + dataset: "sentinel-1", + groupId: "string", + isUnzippedFile: false, + isDummyProduct: false, + + metadata: { + date: moment2(), + stopDate: moment2(), + polygon: "POLYGON ((-120.6596489990334 38.10046393341369, -120.7165475579197 38.10851198053945, -120.766930740861 38.11562044217759, -120.8205210213509 38.12315205210022, -120.8714495693995 38.13028813229113, -120.9237420515751 38.13758904376237, -120.9763848233747 38.14491322663075, -121.0284993874585 38.15213949038783, -121.0805374061872 38.15933042899581, -121.1317842372317 38.16638876359664, -121.1831324092139 38.17343685331883, -121.2343267090171 38.1804400907544, -121.2851343767767 38.18736716519965, -121.3356959243903 38.19423758535788, -121.3861081098637 38.20106467487116, -121.4362721727969 38.20783544395677, -121.48323466170885 38.21415300334824, -121.4961042842803 38.15636388218255, -121.5433137463578 38.16270254678292, -121.5911446754841 38.1691031129965, -121.6386899947014 38.17544523556456, -121.6861407154369 38.18175427917799, -121.7332794261246 38.18800202289999, -121.7803915044837 38.19422601057961, -121.827141292521 38.20038272861196, -121.8737037166488 38.20649520761842, -121.9200946535652 38.21256588219698, -121.9662943385527 38.21859236147657, -122.0122835841423 38.22457236130022, -122.0581361973249 38.23051573928061, -122.1041763492786 38.23646390681441, -122.149693424194 38.24232638029159, -122.1961235981019 38.24828575950047, -122.242840340764 38.25426186141181, -122.2851111656349 38.25965821461571, -122.3300033441712 38.2653676014464, -122.3758025278513 38.27117216227268, -122.4195396691845 38.27670031010642, -122.3858453485523 38.44296136955153, -122.3532454174394 38.60872264056508, -122.321281901071 38.77481263179438, -122.2870678391941 38.9402423639722, -122.28657198358258 38.94018057384403, -122.2484647545139 39.10551216594683, -122.2139845790114 39.27116104878576, -122.1797260176706 39.4367089374228, -122.1454462898122 39.60250573468526, -122.1112187045845 39.76830723022915, -122.0657227757032 39.76272908715357, -122.0199986201785 39.75710391072595, -121.974167995761 39.75144665647245, -121.9280106375743 39.74573006489359, -121.8819129486135 39.74000139035989, -121.8355618840318 39.73422190999039, -121.7893509902118 39.72844019721962, -121.7438269303752 39.72272426697831, -121.6969816389773 39.71682457472104, -121.6515073229837 39.71107635608378, -121.6043191954164 39.70509395348859, -121.5584565168173 39.69925815820748, -121.5109102827927 39.69319018010273, -121.4645931051444 39.68725740118437, -121.4191841855194 39.68142061388765, -121.3710837028612 39.67522101887367, -121.3249639873766 39.66925411189222, -121.2737070377029 39.66260665395009, -121.23414991223851 39.657450537553174, -121.2225423730193 39.71501508524592, -121.1765350243167 39.70900995464177, -121.1256787673412 39.70235510426308, -121.0761429466098 39.6958485542612, -121.0248065795119 39.68908396631235, -120.9731471040036 39.68225266837984, -120.9238122923641 39.67570292460091, -120.8690679290765 39.66841567043333, -120.8147668765373 39.66115958039808, -120.7685909543843 39.65495848719279, -120.7156528937689 39.64783419415447, -120.663007754518 39.64072322969391, -120.6113623558398 39.6337213126097, -120.5575229174151 39.62639828522865, -120.4998084040708 39.61852276683964, -120.4452699517613 39.61104894626836, -120.3863396198317 39.60294709422497, -120.3350203072667 39.59585767211257, -120.2794058786818 39.5881523754319, -120.2276117469398 39.58094649107327, -120.22744443645614 39.58092314818873, -120.2134545404021 39.63753782618391, -120.1722737074452 39.6317932200585, -120.1244336159495 39.62510726553644, -120.0702567931258 39.61751657755807, -120.022269227435 39.61076456269333, -119.9734628265665 39.60387622000747, -119.9205724742573 39.59639065119934, -119.8710716027977 39.58935798135493, -119.8176837356334 39.58175135017377, -119.7678667295637 39.57462631850627, -119.7172666919774 39.56736632596481, -119.6677829890141 39.56024234859523, -119.6164294368659 39.55282685903347, -119.5655855530352 39.54546030402012, -119.5122825240406 39.53771380091477, -119.4596714762434 39.53004121358733, -119.4118356441431 39.52303826133494, -119.3539548115401 39.51454620335684, -119.2999598520621 39.50659276685604, -119.242172282983 39.49805375475951, -119.1867112941332 39.48982722325655, -119.2279582300632 39.32389259181299, -119.2695651047809 39.15814430461985, -119.3154157605841 38.99290396440068, -119.3553955782568 38.82692456194625, -119.4076391719693 38.66278010421749, -119.46426202130762 38.48267405863559, -119.4994803127931 38.33275776186966, -119.5473964124392 38.1679932576986, -119.5759619696445 38.00032674732519, -119.6328594358995 38.00892055228446, -119.685940538886 38.01691396436385, -119.735510021753 38.02435806698762, -119.7876843769492 38.0321663403309, -119.8349767585424 38.03922663419335, -119.8827140678868 38.04633197874039, -119.9336830819589 38.05389196505576, -119.9837372437618 38.06129369064131, -120.029196677421 38.0680003062205, -120.0790441003354 38.07532784287181, -120.1269111066452 38.08234457142717, -120.1767641224129 38.08962794955193, -120.2211977375846 38.09610549717873, -120.2696883291999 38.10314938009251, -120.3131576383198 38.10945036625376, -120.3570069870991 38.11578848698885, -120.4046282389668 38.12264764067351, -120.4517936234199 38.12942103705984, -120.48468630063608 38.134130553754865, -120.4964144795629 38.07720256883281, -120.5521610008301 38.08517268978709, -120.6049996926634 38.09270374285773, -120.6596489990334 38.10046393341369))", + + productType: "", + beamMode: "", + polarization: "", + flightDirection: null, + + path: 1, + frame: 1, + absoluteOrbit: [1], + + stackSize: 1, + // ALOS PALSAR + faradayRotation: null, + offNadirAngle: null, + + // AVNIR-2 + instrument: null, + pointingAngle: null, + + // UAVSAR + missionName: null, + + // AIRSAR + flightLine: null, + + // Baseline + perpendicular: null, + temporal: null, + canInSAR: false, + + // SLC BURST + burst: null, + + // OPERA-S1 + opera: null, + + fileName: null, + job:null, + + // versioning + pgeVersion: null, + + // BURST XML, OPERA-S1 + subproducts: [], + parentID: "", + + // ARIA S1 GUNW + ariaVersion: null, + } + }], + searchType: action.payload.searchType + }) + ] + }) + )) + public showResultsMenuOnSearchResponse = createEffect(() => this.actions$.pipe( ofType(SearchActionType.SEARCH_RESPONSE), map(_ => new uiStore.OpenResultsMenu()), @@ -229,10 +334,23 @@ export class SearchEffects { map(_ => new uiStore.OpenResultsMenu()), )); + public showTimeseriesResultsMenuOnSearchResponse = createEffect(() => this.actions$.pipe( + ofType(SearchActionType.TIMESERIES_SEARCH_RESPONSE), + map(_ => new uiStore.OpenResultsMenu()), + )); + public setMapInteractionModeBasedOnSearchType = createEffect(() => this.actions$.pipe( ofType(SearchActionType.SET_SEARCH_TYPE_AFTER_SAVE), - filter(action => action.payload === models.SearchType.DATASET), - map(_ => new mapStore.SetMapInteractionMode(models.MapInteractionModeType.DRAW)) + filter(action => action.payload === models.SearchType.DATASET || action.payload === models.SearchType.TIMESERIES), + switchMap((action) => { + let output : any[] = [ + new mapStore.SetMapInteractionMode(models.MapInteractionModeType.DRAW) + ]; + if (action.payload === models.SearchType.TIMESERIES) { + output.push(new mapStore.SetMapDrawMode(models.MapDrawModeType.POINT)) + } + return output; + }) )); public clearResultsWhenSearchTypeChanges = createEffect(() => this.actions$.pipe( @@ -428,6 +546,7 @@ export class SearchEffects { ); } + private nextCustomProduct$(next: string, latestScenes: models.CMRProduct[]): Observable { return this.hyp3Service.getJobsByUrl$(next).pipe( switchMap( @@ -454,6 +573,41 @@ export class SearchEffects { ); } + private timeseriesQuery$() { + return this.searchParams$.getParams.pipe( + switchMap( + (params) => + this.asfApiService.query(params).pipe( + withLatestFrom(combineLatest([ + this.store$.select(getSearchType), + this.store$.select(getIsCanceled), + this.netCdfService.getTimeSeries({'lon': 1, 'lat':1}) // eventually grab params for points in this part + ] + )), + map(([response, [searchType, isCanceled, timseries]]) => { + const files = this.productService.fromResponse(response) + return !isCanceled ? + new TimeseriesSearchResponse({ + files, + totalCount: files.length, + searchType, + timseries + }) : + new SearchCanceled() + } + ), + catchError( + (err: HttpErrorResponse) => { + if (err.status !== 400) { + return of(new SearchError(`Unknown Error`)); + } + return EMPTY; + } + ), + )) + ); + } + private hyp3JobToProducts(jobs, products) { const virtualProducts = jobs .filter(job => products[job.job_parameters.granules[0]]) diff --git a/src/app/store/search/search.reducer.ts b/src/app/store/search/search.reducer.ts index 2125f73de..97f9902c0 100644 --- a/src/app/store/search/search.reducer.ts +++ b/src/app/store/search/search.reducer.ts @@ -89,6 +89,15 @@ export function searchReducer(state = initState, action: SearchActions): SearchS }; } + case SearchActionType.TIMESERIES_SEARCH_RESPONSE: { + return { + ...state, + totalResults: 1, + isLoading: false, + isCanceled: false, + } + } + case SearchActionType.SEARCH_ERROR: { return { ...state, 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; } } diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index b950334bd..3eb3acc41 100644 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -1,7 +1,7 @@ // variables -$asf-font-size: '16px'; -$asf-line-height: '17px'; +$asf-font-size: 16px; +$asf-line-height: 17px; $asf-ribbon-icon-size: 18px; $uaf-primary-blue: #236192;