Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('SelectCaseAppEffects', () => {
const
orientation: CaseOrientation = 'Imagery Perspective',
geoFilter: CaseGeoFilter = CaseGeoFilter.PinPoint,
timeFilter: CaseTimeFilter = 'Start - End',
timeFilter: CaseTimeFilter = CaseTimeFilter.StartEnd,
time: CaseTimeState = { type: 'absolute', from: new Date(0), to: new Date(0) },
region: CaseRegionState = {},
dataInputFilters: CaseDataInputFiltersState = { fullyChecked: true, filters: [], active: true },
Expand Down
10 changes: 5 additions & 5 deletions src/app/@ansyn/ansyn/app-effects/effects/filters.app.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ import {
import 'rxjs/add/operator/share';
import 'rxjs/add/observable/of';
import { SetBadgeAction } from '@ansyn/menu/actions/menu.actions';
import { selectFavoriteOverlays } from '@ansyn/core/reducers/core.reducer';
import { selectFavoriteOverlays, selectOverlaysCriteria } from '@ansyn/core/reducers/core.reducer';
import { CaseFacetsState, CaseFilter, FilterType } from '@ansyn/core/models/case.model';
import { Overlay } from '@ansyn/core/models/overlay.model';
import { Overlay, OverlaysCriteria } from '@ansyn/core/models/overlay.model';
import { FilterMetadata } from '@ansyn/menu-items/filters/models/metadata/filter-metadata.interface';
import { FiltersService } from '@ansyn/menu-items/filters/services/filters.service';
import { FilterModel } from '@ansyn/core/models/filter.model';
Expand Down Expand Up @@ -69,10 +69,10 @@ export class FiltersAppEffects {
*/
@Effect()
updateOverlayFilters$ = this.onFiltersChanges$
.withLatestFrom(this.overlaysArray$)
.mergeMap(([[filters, showOnlyFavorite, favoriteOverlays], overlaysArray]: [[Filters, boolean, Overlay[]], Overlay[]]) => {
.withLatestFrom(this.overlaysArray$, this.store$.select(selectOverlaysCriteria))
.mergeMap(([[filters, showOnlyFavorite, favoriteOverlays], overlaysArray, { time }]: [[Filters, boolean, Overlay[]], Overlay[], OverlaysCriteria]) => {
const filterModels: FilterModel[] = FiltersService.pluckFilterModels(filters);
const filteredOverlays: string[] = OverlaysService.buildFilteredOverlays(overlaysArray, filterModels, favoriteOverlays, showOnlyFavorite);
const filteredOverlays: string[] = OverlaysService.buildFilteredOverlays(overlaysArray, filterModels, favoriteOverlays, showOnlyFavorite, time);
const message = (filteredOverlays && filteredOverlays.length) ? overlaysStatusMessages.nullify : overlaysStatusMessages.noOverLayMatchFilters;
return [
new SetFilteredOverlaysAction(filteredOverlays),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const regionCoordinates = [
const fetchParams: any = {
limit: 250,
region: turf.geometry('Polygon', regionCoordinates),
timeRange: {start: new Date().toISOString(), end: new Date().toISOString()}
timeRange: [{start: new Date().toISOString(), end: new Date().toISOString()}]
};

const fetchParamsWithLimitZero: any = { ...fetchParams, limit: 0};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { Observable } from 'rxjs/Observable';
import { Inject, Injectable, InjectionToken } from '@angular/core';
import {
BaseOverlaySourceProvider, DateRange, IFetchParams, OverlayFilter,
BaseOverlaySourceProvider, IFetchParams, OverlayFilter,
StartAndEndDate
} from '@ansyn/overlays/models/base-overlay-source-provider.model';
import { Overlay, OverlaysFetchData } from '@ansyn/core/models/overlay.model';
import { Feature, Polygon } from 'geojson';
import { LoggerService } from '@ansyn/core/services/logger.service';
import { area, intersect, difference } from '@turf/turf';
import { DataInputFilterValue } from '@ansyn/core/models/case.model';
import { IDateRange } from '@ansyn/core/models/time.model';

export interface FiltersList {
name: string,
dates: DateRange[]
dates: IDateRange[]
sensorNames: string[],
coverage: number[][][][]
}
Expand Down Expand Up @@ -142,7 +143,7 @@ export class MultipleOverlaysSourceProvider extends BaseOverlaySourceProvider {
errors,
data: null,
limited: -1
}
};
}

return this.mergeOverlaysFetchData(overlays, fetchParams.limit, errors);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export class OpenAerialSourceProvider extends BaseOverlaySourceProvider {
platform: 'uav',
limit: `${fetchParams.limit + 1}`,
bbox: `${bbox[0]},${bbox[1]},${bbox[2]},${bbox[3]}`,
acquisition_from: fetchParams.timeRange.start.toISOString(),
acquisition_to: fetchParams.timeRange.end.toISOString()
acquisition_from: fetchParams.timeRange[0].start.toISOString(),
acquisition_to: fetchParams.timeRange[0].end.toISOString()
};

return this.http.get<any>(baseUrl, { params: params })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ export class PlanetSourceProvider extends BaseOverlaySourceProvider {
});
}

buildFilters(config: IPlanetFilter[], sensors?: string[]) {
buildFilters(config: IPlanetFilter[], sensors?: string[], filterType = 'AndFilter') {
return {
item_types: Array.isArray(sensors) ? sensors : this.planetOverlaysSourceConfig.itemTypes,
filter: {
type: 'AndFilter',
type: filterType,
config: config
}
};
Expand All @@ -86,10 +86,7 @@ export class PlanetSourceProvider extends BaseOverlaySourceProvider {
const limit = `${fetchParams.limit + 1}`;

const bboxFilter = { type: 'GeometryFilter', field_name: 'geometry', config: fetchParams.region };
const dateFilter = {
type: 'DateRangeFilter', field_name: 'acquired',
config: { gte: fetchParams.timeRange.start.toISOString(), lte: fetchParams.timeRange.end.toISOString() }
};
const dateFilter = this.buildDateFilter(fetchParams);

const filters: IPlanetFilter[] = [bboxFilter, dateFilter];

Expand Down Expand Up @@ -129,6 +126,39 @@ export class PlanetSourceProvider extends BaseOverlaySourceProvider {
});
}

// build date filter for single / multiple time ranges
buildDateFilter(fetchParams: IFetchParams) {
let dateFilter;
if (fetchParams.timeRange.length === 1) {
// single time range (like in start-end)
dateFilter = {
type: 'DateRangeFilter',
field_name: 'acquired',
config: {
gte: fetchParams.timeRange[0].start.toISOString(),
lte: fetchParams.timeRange[0].end.toISOString()
}
}
} else {
// multiple time ranges (like in intervals)
const dateRangeFilters = fetchParams.timeRange.map(tr => {
return {
type: 'DateRangeFilter',
field_name: 'acquired',
config: {
gte: tr.start.toISOString(),
lte: tr.end.toISOString()
}
}
});
dateFilter = {
type: 'OrFilter',
config: dateRangeFilters
};
}
return dateFilter;
}

getById(id: string, sourceType: string): Observable<Overlay> {
const baseUrl = this.planetOverlaysSourceConfig.baseUrl;
const body = this.buildFilters([{ type: 'StringInFilter', field_name: 'id', config: [id] }]);
Expand Down
6 changes: 0 additions & 6 deletions src/app/@ansyn/assets/styles/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,6 @@ button[disabled] {
}
}

input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}

@font-face {
font-family: 'AnSyn';
src: url('/assets/fonts/AnSyn/AnSyn.eot?mxpept&v=1');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<input type="date" #datePicker [disabled]="disabled">
<i class="icon-status-bar-time"></i>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@import "../../less/common";

:host {
position: relative;
input.flatpickr-input {
width: 130px;
height: 20px;
padding: 0 5px;
}
i {
position: absolute;
right: 10px;
top: 4px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { DatePickerComponent } from './ansyn-date-picker.component';


describe('DatePickerComponent', () => {
let component: DatePickerComponent;
let fixture: ComponentFixture<DatePickerComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DatePickerComponent]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(DatePickerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should be created', () => {
expect(component).toBeTruthy();
});
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import * as flatpickr from 'flatpickr';

@Component({
selector: 'ansyn-date-picker',
templateUrl: './ansyn-date-picker.component.html',
styleUrls: ['./ansyn-date-picker.component.less']
})

export class DatePickerComponent implements OnInit {

private _datePickerValue: Date;
private _datePickerInstance: any;

@ViewChild('datePicker') datePicker: ElementRef;
@Output() dateChange = new EventEmitter<Date>();

@Input() disabled = false;

@Input()
set date(val) {
this._datePickerValue = val;
if (this._datePickerInstance) {
this._datePickerInstance.setDate(this._datePickerValue, false);
}
}

constructor() {}

ngOnInit() {
// see API: https://flatpickr.js.org/options/
this._datePickerInstance = new (<any>flatpickr)(this.datePicker.nativeElement, {
// id: 'end',
time_24hr: true,
enableTime: true,
dateFormat: 'H:i d/m/Y',
defaultDate: this._datePickerValue ? this._datePickerValue : new Date(),
onChange: this.onDateChange.bind(this),
plugins: [this.confirmDatePlugin({})]
});
}

confirmDatePlugin(pluginConfig: any) {
const defaultConfig = {
confirmIcon: '<svg version=\'1.1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' width=\'17\' height=\'17\' viewBox=\'0 0 17 17\'> <g> </g> <path d=\'M15.418 1.774l-8.833 13.485-4.918-4.386 0.666-0.746 4.051 3.614 8.198-12.515 0.836 0.548z\' fill=\'#000000\' /> </svg>',
confirmText: 'OK ',
showAlways: false,
theme: 'light'
};

const config = Object.assign(defaultConfig, pluginConfig);

return function (fp) {
const hooks = {
onKeyDown: function onKeyDown(_, __, ___, e) {
if (fp.config.enableTime && e.key === 'Tab' && e.target === fp.amPM) {
e.preventDefault();
fp.confirmContainer.focus();
} else if (e.key === 'Enter' && e.target === fp.confirmContainer) {
fp.close();
}
},
onReady: function onReady() {
if (fp.calendarContainer === undefined) {
return;
}

fp.confirmContainer = fp._createElement('div', 'flatpickr-confirm ' + (config.showAlways ? 'visible' : '') + ' ' + config.theme + 'Theme', config.confirmText);

fp.confirmContainer.tabIndex = -1;
fp.confirmContainer.innerHTML += config.confirmIcon;

fp.confirmContainer.addEventListener('click', fp.close);
fp.calendarContainer.appendChild(fp.confirmContainer);
}
} as any;

if (!config.showAlways) {
hooks.onChange = function (dateObj, dateStr) {
const showCondition = fp.config.enableTime || fp.config.mode === 'multiple';
if (dateStr && !fp.config.inline && showCondition) {
return fp.confirmContainer.classList.add('visible');
}
fp.confirmContainer.classList.remove('visible');
};
}

return hooks;
};
}

onDateChange(event) {
if (this.disabled) {
return false;
}
this._datePickerValue = event[0];
this.dateChange.emit(this._datePickerValue);
}
}
2 changes: 2 additions & 0 deletions src/app/@ansyn/core/core.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AnsynCheckboxComponent } from './components/ansyn-checkbox/ansyn-checkbox.component';
import { DatePickerComponent } from './components/ansyn-date-picker/ansyn-date-picker.component';
import { ImageryStatusComponent } from './components/imagery-status/imagery-status.component';
import { PlaceholderComponent } from './components/placeholder/placeholder.component';
import { StoreModule } from '@ngrx/store';
Expand All @@ -18,6 +19,7 @@ import { StorageService } from '@ansyn/core/services/storage/storage.service';

const coreComponents = [
AnsynCheckboxComponent,
DatePickerComponent,
ImageryStatusComponent,
PlaceholderComponent,
ToastComponent,
Expand Down
1 change: 1 addition & 0 deletions src/app/@ansyn/core/less/common.less
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@overlays-dots-color-hover: #bd0fe2;
@menu-width: 90px;
@menu-color: #2E2D46;
@text-disabled-color: #9D9D9D;
@timeline-area-height: 110px;

.default-menu-item {
Expand Down
19 changes: 18 additions & 1 deletion src/app/@ansyn/core/models/case.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ export interface IContextEntity extends IVisualizerEntity {
}

export type CaseOrientation = 'Align North' | 'User Perspective' | 'Imagery Perspective';
export type CaseTimeFilter = 'Start - End';

export enum CaseTimeFilter {
'StartEnd' = 'Start - End',
'Intervals' = 'Intervals'
}

export enum CaseGeoFilter {
PinPoint = 'Point',
Expand Down Expand Up @@ -83,10 +86,24 @@ export interface CaseDataInputFiltersState {
active: boolean
}

export interface TimeIntervals {
interval: number // in milliseconds
criteria: CaseIntervalCriteria
}

export interface CaseTimeState {
type: 'absolute',
from: Date,
to: Date
intervals?: TimeIntervals;
}

export type CaseIntervalCriteriaType = 'best' | 'closest-before' | 'closest-after' | 'closest-both';

export interface CaseIntervalCriteria {
type: CaseIntervalCriteriaType,
before?: number,
after?: number,
}

export interface CaseBooleanFilterMetadata {
Expand Down
22 changes: 22 additions & 0 deletions src/app/@ansyn/core/models/intervals.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Overlay } from '@ansyn/core/models/overlay.model';

export interface IntervalTimeFrame {
startDate: Date;
endDate: Date;
span: number;
intervalsCount: number;
}

export interface IntervalTimeFrame {
startDate: Date;
endDate: Date;
span: number;
intervalsCount: number;
}

export interface Interval {
startTime: Date;
endTime: Date;
pivot: Date;
overlays: Array<Overlay>;
}
Loading