diff --git a/pdb-js/src/app/app.module.ts b/pdb-js/src/app/app.module.ts index e8aaf6d..934f729 100644 --- a/pdb-js/src/app/app.module.ts +++ b/pdb-js/src/app/app.module.ts @@ -22,7 +22,7 @@ import { YAxisRangeComponent } from './y-axis-range/y-axis-range.component'; import { QueryAutocompleteComponent } from './query-autocomplete/query-autocomplete.component'; import { LimitByComponent } from './limit-by/limit-by.component'; import { PlotViewComponent } from './plot-view/plot-view.component'; -import { GalleryViewComponent, GalleryItemView } from './gallery-view/gallery-view.component'; +import { GalleryViewComponent, GalleryItemView, GalleryFilterView } from './gallery-view/gallery-view.component'; import { ImageToggleComponent } from './image-toggle/image-toggle.component'; @NgModule({ @@ -38,6 +38,7 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component'; PlotViewComponent, GalleryViewComponent, GalleryItemView, + GalleryFilterView, ImageToggleComponent ], imports: [ diff --git a/pdb-js/src/app/gallery-view/gallery-filter-view.component.html b/pdb-js/src/app/gallery-view/gallery-filter-view.component.html new file mode 100644 index 0000000..098f522 --- /dev/null +++ b/pdb-js/src/app/gallery-view/gallery-filter-view.component.html @@ -0,0 +1,26 @@ + + Filter By: + + none + max value + average + #values + #plotted values + + + + + + + + + + + + millis + seconds + minutes + hours + days + + \ No newline at end of file diff --git a/pdb-js/src/app/gallery-view/gallery-filter-view.component.scss b/pdb-js/src/app/gallery-view/gallery-filter-view.component.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pdb-js/src/app/gallery-view/gallery-filter-view.component.scss @@ -0,0 +1 @@ + diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.html b/pdb-js/src/app/gallery-view/gallery-view.component.html index b68101e..23d404c 100644 --- a/pdb-js/src/app/gallery-view/gallery-view.component.html +++ b/pdb-js/src/app/gallery-view/gallery-view.component.html @@ -13,9 +13,11 @@ -
- -
+ + + + + diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.ts b/pdb-js/src/app/gallery-view/gallery-view.component.ts index 0e4c104..9f4a535 100644 --- a/pdb-js/src/app/gallery-view/gallery-view.component.ts +++ b/pdb-js/src/app/gallery-view/gallery-view.component.ts @@ -1,7 +1,93 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, Output, ViewChild, EventEmitter } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { PlotService, PlotRequest, PlotResponse, PlotResponseStats } from '../plot.service'; +export class GalleryFilterData { + filterBy :string; + comparator :string; + value : number; + unit: string; + constructor(filterBy :string, comparator :string, value : number, unit: string){ + this.filterBy = filterBy; + this.comparator = comparator; + this.value = value; + this.unit = unit; + } +} + +@Component({ + selector: 'pdb-gallery-filter-view', + templateUrl: './gallery-filter-view.component.html', + styleUrls: ['./gallery-filter-view.component.scss'] +}) +export class GalleryFilterView { + compareImages = JSON.stringify([ + { + value: 'GREATER_EQUAL', + text: '≥', + title: 'greater or equal' + }, + { + value: 'LESS_EQUAL', + text: '≤', + title: 'less or equal' + } + ]); + + _filterBy = 'MAX_VALUE'; + + _comparator = 'GREATER_EQUAL'; + + _value : number = 0; + + _unit: string = 'SECONDS'; + + @Output() + valueChanged : EventEmitter = new EventEmitter(); + + comparatorChanged(newComparator: string){ + this._comparator = newComparator; + this.valueChanged.emit(undefined); + } + + set filterBy(filterBy: string){ + this._filterBy = filterBy; + this.valueChanged.emit(undefined); + } + + get filterBy() : string{ + return this._filterBy; + } + set unit(unit: string){ + this._unit = unit; + this.valueChanged.emit(undefined); + } + + get unit() : string{ + return this._unit; + } + + set comparator(comparator: string){ + this._comparator = comparator; + this.valueChanged.emit(undefined); + } + + get comparator() : string{ + return this._comparator; + } + + set value(value: number){ + this._value = value; + this.valueChanged.emit(undefined); + } + + get value() : number{ + return this._value; + } +} + + + @Component({ selector: 'pdb-gallery-view', templateUrl: './gallery-view.component.html', @@ -12,20 +98,26 @@ export class GalleryViewComponent implements OnInit { galleryItems: Array = new Array(); + show = false; splitByValuesQueue = new Array(); _sortBy= "NAME"; - sortOrder = 0; + sortOrder = 'ASC'; + + @ViewChild(GalleryFilterView, {static: false}) + filter : GalleryFilterView; ascDescImages = JSON.stringify([ { + value: 'ASC', imageUrl: 'assets/img/ascending-filter.svg', title: 'ascending' }, { + value: 'DESC', imageUrl: 'assets/img/descending-filter.svg', title: 'descending' } @@ -44,8 +136,17 @@ export class GalleryViewComponent implements OnInit { ngOnInit() { } + filteredSortedGalleryItems(): Array { + return this.galleryItems.filter(item => item.show); + } + + sortAndFilterGallery(){ + this.filterGallery(); + this.sortGallery(); + } + sortGallery() { - const orderFactor = this.sortOrder == 0 ? 1 : -1; // ASC=1, DESC=-1 + const orderFactor = this.sortOrder == 'ASC' ? 1 : -1; switch (this._sortBy) { case "NAME": @@ -66,6 +167,52 @@ export class GalleryViewComponent implements OnInit { } } + filterGallery(){ + const that = this; + this.galleryItems.forEach(function(item){ + const show = that.filterPredicate(item); + item.show = show; + }); + } + + filterPredicate(galleryItem: GalleryItem){ + const predicate = this.filter.comparator == 'LESS_EQUAL' + ? function(a, b) { return a <= b; } + : function(a, b) { return a >= b; }; + const millis = this.timeUnitToMillis(this.filter.value, this.filter.unit); + switch(this.filter.filterBy){ + case 'NONE': + case undefined: + return true; + case 'MAX_VALUE': + return predicate(galleryItem.stats.maxValue, millis); + case 'AVERAGE': + return predicate(galleryItem.stats.average, millis); + case 'VALUES': + return predicate(galleryItem.stats.values, this.filter.value); + case 'PLOTTED_VALUES': + return predicate(galleryItem.stats.plottedValues, this.filter.value); + } + throw "unhandled option: " + this.filter.filterBy; + } + + timeUnitToMillis(value, unit) + { + switch(unit){ + case 'MILLISECONDS': + return value; + case 'SECONDS': + return value*1000; + case 'MINUTES': + return value*1000*60; + case 'HOURS': + return value*1000*60*60; + case 'DAYS': + return value*1000*60*60*24; + } + throw "unknown unit: " + unit; + } + renderGallery(request: PlotRequest, splitByField: string) { const that=this; @@ -103,7 +250,7 @@ export class GalleryViewComponent implements OnInit { plotResponse.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl; let galleryItem = new GalleryItem(splitByValue, plotResponse); that.galleryItems.push(galleryItem); - that.sortGallery(); + that.sortAndFilterGallery(); that.renderGalleryRecursively(masterRequest, splitByField); }, error => { @@ -113,14 +260,18 @@ export class GalleryViewComponent implements OnInit { set sortBy(name: string) { this._sortBy = name; - this.sortGallery(); + this.sortAndFilterGallery(); } get sortBy(): string { return this._sortBy; } sortOrderChanged(event){ this.sortOrder = event; - this.sortGallery(); + this.sortAndFilterGallery(); + } + + filterChanged(event){ + this.sortAndFilterGallery(); } } @@ -160,11 +311,13 @@ export class GalleryItemView { } + export class GalleryItem { thumbnailUrl: string; imageUrl: string; stats: PlotResponseStats; splitByValue : string; + show : boolean; constructor(splitByValue: string, plotResponse: PlotResponse){ this.thumbnailUrl = plotResponse.thumbnailUrl; diff --git a/pdb-js/src/app/image-toggle/image-toggle.component.html b/pdb-js/src/app/image-toggle/image-toggle.component.html index 1738d6f..3c9e4c6 100644 --- a/pdb-js/src/app/image-toggle/image-toggle.component.html +++ b/pdb-js/src/app/image-toggle/image-toggle.component.html @@ -1 +1,10 @@ - + +
{{text}}
\ No newline at end of file diff --git a/pdb-js/src/app/image-toggle/image-toggle.component.scss b/pdb-js/src/app/image-toggle/image-toggle.component.scss index e69de29..137d553 100644 --- a/pdb-js/src/app/image-toggle/image-toggle.component.scss +++ b/pdb-js/src/app/image-toggle/image-toggle.component.scss @@ -0,0 +1,11 @@ +:host{ + cursor: pointer; + display: inline-block; + vertical-align: middle; + margin-right: 1ex; +} + +.image-toggle-text{ + font-size: 1.5em; + font-weight: normal; +} diff --git a/pdb-js/src/app/image-toggle/image-toggle.component.ts b/pdb-js/src/app/image-toggle/image-toggle.component.ts index 65d0c49..93c7035 100644 --- a/pdb-js/src/app/image-toggle/image-toggle.component.ts +++ b/pdb-js/src/app/image-toggle/image-toggle.component.ts @@ -10,29 +10,33 @@ export class ImageToggleComponent implements OnInit { @Input() images : string = ""; - value: number = 0; + index: number = 0; @Output() valueChanged : EventEmitter = new EventEmitter(); + text = undefined; + _states : Array; constructor() { } ngOnInit() { this._states = JSON.parse(this.images); + this.text = this._states[this.index].text; } imageUrl() : string { - return this._states[this.value].imageUrl; + return this._states[this.index].imageUrl; } title() : string { - return this._states[this.value].title; + return this._states[this.index].title; } toggle(event){ - this.value = (this.value+1) % this._states.length; - this.valueChanged.emit(this.value); + this.index = (this.index+1) % this._states.length; + this.text = this._states[this.index].text; + this.valueChanged.emit(this._states[this.index].value); } } diff --git a/pdb-js/src/styles.scss b/pdb-js/src/styles.scss index 4c24d1f..b725766 100644 --- a/pdb-js/src/styles.scss +++ b/pdb-js/src/styles.scss @@ -93,6 +93,9 @@ mat-form-field:last-child { mat-form-field.pdb-form-number { width: 3.5em; } +mat-form-field.pdb-form-number-long { + width: 7em; +} .pdb-form-icon-small { display: inline-block; width: 2em;