add filters for gallery
This commit is contained in:
@@ -22,7 +22,7 @@ import { YAxisRangeComponent } from './y-axis-range/y-axis-range.component';
|
|||||||
import { QueryAutocompleteComponent } from './query-autocomplete/query-autocomplete.component';
|
import { QueryAutocompleteComponent } from './query-autocomplete/query-autocomplete.component';
|
||||||
import { LimitByComponent } from './limit-by/limit-by.component';
|
import { LimitByComponent } from './limit-by/limit-by.component';
|
||||||
import { PlotViewComponent } from './plot-view/plot-view.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';
|
import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -38,6 +38,7 @@ import { ImageToggleComponent } from './image-toggle/image-toggle.component';
|
|||||||
PlotViewComponent,
|
PlotViewComponent,
|
||||||
GalleryViewComponent,
|
GalleryViewComponent,
|
||||||
GalleryItemView,
|
GalleryItemView,
|
||||||
|
GalleryFilterView,
|
||||||
ImageToggleComponent
|
ImageToggleComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<mat-form-field class="pdb-form-wide">
|
||||||
|
<mat-label>Filter By:</mat-label>
|
||||||
|
<mat-select [(value)]="filterBy">
|
||||||
|
<mat-option>none</mat-option>
|
||||||
|
<mat-option value="MAX_VALUE">max value</mat-option>
|
||||||
|
<mat-option value="AVERAGE">average</mat-option>
|
||||||
|
<mat-option value="VALUES">#values</mat-option>
|
||||||
|
<mat-option value="PLOTTED_VALUES">#plotted values</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<pdb-image-toggle *ngIf="filterBy" images="{{compareImages}}" (valueChanged)="comparatorChanged($event)"></pdb-image-toggle>
|
||||||
|
|
||||||
|
<mat-form-field *ngIf="filterBy" class="pdb-form-number-long">
|
||||||
|
<input matInput type="number" placeholder="" min="0" [(ngModel)]="value">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field *ngIf="filterBy == 'MAX_VALUE' || filterBy == 'AVERAGE'" class="pdb-form-mid">
|
||||||
|
<mat-select [(value)]="unit">
|
||||||
|
<mat-option value="MILLISECONDS">millis</mat-option>
|
||||||
|
<mat-option value="SECONDS">seconds</mat-option>
|
||||||
|
<mat-option value="MINUTES">minutes</mat-option>
|
||||||
|
<mat-option value="HOURS">hours</mat-option>
|
||||||
|
<mat-option value="DAYS">days</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -13,9 +13,11 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div class="pdb-form-icon-small">
|
|
||||||
<pdb-image-toggle images="{{ascDescImages}}" (valueChanged)="sortOrderChanged($event)"></pdb-image-toggle>
|
<pdb-image-toggle images="{{ascDescImages}}" (valueChanged)="sortOrderChanged($event)"></pdb-image-toggle>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<pdb-gallery-filter-view (valueChanged)="filterChanged($event)"></pdb-gallery-filter-view>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -23,6 +25,6 @@
|
|||||||
id="gallery"
|
id="gallery"
|
||||||
class="card-grid-300">
|
class="card-grid-300">
|
||||||
<pdb-gallery-item-view
|
<pdb-gallery-item-view
|
||||||
*ngFor="let galleryItem of galleryItems" [data]="galleryItem">
|
*ngFor="let galleryItem of filteredSortedGalleryItems()" [data]="galleryItem">
|
||||||
</pdb-gallery-item-view>
|
</pdb-gallery-item-view>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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 { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { PlotService, PlotRequest, PlotResponse, PlotResponseStats } from '../plot.service';
|
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<GalleryFilterData> = new EventEmitter<GalleryFilterData>();
|
||||||
|
|
||||||
|
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({
|
@Component({
|
||||||
selector: 'pdb-gallery-view',
|
selector: 'pdb-gallery-view',
|
||||||
templateUrl: './gallery-view.component.html',
|
templateUrl: './gallery-view.component.html',
|
||||||
@@ -12,20 +98,26 @@ export class GalleryViewComponent implements OnInit {
|
|||||||
|
|
||||||
galleryItems: Array<GalleryItem> = new Array<GalleryItem>();
|
galleryItems: Array<GalleryItem> = new Array<GalleryItem>();
|
||||||
|
|
||||||
|
|
||||||
show = false;
|
show = false;
|
||||||
|
|
||||||
splitByValuesQueue = new Array<string>();
|
splitByValuesQueue = new Array<string>();
|
||||||
|
|
||||||
_sortBy= "NAME";
|
_sortBy= "NAME";
|
||||||
|
|
||||||
sortOrder = 0;
|
sortOrder = 'ASC';
|
||||||
|
|
||||||
|
@ViewChild(GalleryFilterView, {static: false})
|
||||||
|
filter : GalleryFilterView;
|
||||||
|
|
||||||
ascDescImages = JSON.stringify([
|
ascDescImages = JSON.stringify([
|
||||||
{
|
{
|
||||||
|
value: 'ASC',
|
||||||
imageUrl: 'assets/img/ascending-filter.svg',
|
imageUrl: 'assets/img/ascending-filter.svg',
|
||||||
title: 'ascending'
|
title: 'ascending'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
value: 'DESC',
|
||||||
imageUrl: 'assets/img/descending-filter.svg',
|
imageUrl: 'assets/img/descending-filter.svg',
|
||||||
title: 'descending'
|
title: 'descending'
|
||||||
}
|
}
|
||||||
@@ -44,8 +136,17 @@ export class GalleryViewComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filteredSortedGalleryItems(): Array<GalleryItem> {
|
||||||
|
return this.galleryItems.filter(item => item.show);
|
||||||
|
}
|
||||||
|
|
||||||
|
sortAndFilterGallery(){
|
||||||
|
this.filterGallery();
|
||||||
|
this.sortGallery();
|
||||||
|
}
|
||||||
|
|
||||||
sortGallery() {
|
sortGallery() {
|
||||||
const orderFactor = this.sortOrder == 0 ? 1 : -1; // ASC=1, DESC=-1
|
const orderFactor = this.sortOrder == 'ASC' ? 1 : -1;
|
||||||
|
|
||||||
switch (this._sortBy) {
|
switch (this._sortBy) {
|
||||||
case "NAME":
|
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) {
|
renderGallery(request: PlotRequest, splitByField: string) {
|
||||||
const that=this;
|
const that=this;
|
||||||
|
|
||||||
@@ -103,7 +250,7 @@ export class GalleryViewComponent implements OnInit {
|
|||||||
plotResponse.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl;
|
plotResponse.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl;
|
||||||
let galleryItem = new GalleryItem(splitByValue, plotResponse);
|
let galleryItem = new GalleryItem(splitByValue, plotResponse);
|
||||||
that.galleryItems.push(galleryItem);
|
that.galleryItems.push(galleryItem);
|
||||||
that.sortGallery();
|
that.sortAndFilterGallery();
|
||||||
that.renderGalleryRecursively(masterRequest, splitByField);
|
that.renderGalleryRecursively(masterRequest, splitByField);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@@ -113,14 +260,18 @@ export class GalleryViewComponent implements OnInit {
|
|||||||
|
|
||||||
set sortBy(name: string) {
|
set sortBy(name: string) {
|
||||||
this._sortBy = name;
|
this._sortBy = name;
|
||||||
this.sortGallery();
|
this.sortAndFilterGallery();
|
||||||
}
|
}
|
||||||
|
|
||||||
get sortBy(): string { return this._sortBy; }
|
get sortBy(): string { return this._sortBy; }
|
||||||
|
|
||||||
sortOrderChanged(event){
|
sortOrderChanged(event){
|
||||||
this.sortOrder = event;
|
this.sortOrder = event;
|
||||||
this.sortGallery();
|
this.sortAndFilterGallery();
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChanged(event){
|
||||||
|
this.sortAndFilterGallery();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -160,11 +311,13 @@ export class GalleryItemView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class GalleryItem {
|
export class GalleryItem {
|
||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
stats: PlotResponseStats;
|
stats: PlotResponseStats;
|
||||||
splitByValue : string;
|
splitByValue : string;
|
||||||
|
show : boolean;
|
||||||
|
|
||||||
constructor(splitByValue: string, plotResponse: PlotResponse){
|
constructor(splitByValue: string, plotResponse: PlotResponse){
|
||||||
this.thumbnailUrl = plotResponse.thumbnailUrl;
|
this.thumbnailUrl = plotResponse.thumbnailUrl;
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
<img src="{{imageUrl()}}" (click)="toggle($event)" class="icon-small" title="{{title()}}" />
|
<img
|
||||||
|
*ngIf="imageUrl()"
|
||||||
|
src="{{imageUrl()}}"
|
||||||
|
(click)="toggle($event)"
|
||||||
|
class="icon-small"
|
||||||
|
title="{{title()}}" />
|
||||||
|
<div
|
||||||
|
class="image-toggle-text"
|
||||||
|
*ngIf="text"
|
||||||
|
(click)="toggle($event)" >{{text}}</div>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,29 +10,33 @@ export class ImageToggleComponent implements OnInit {
|
|||||||
@Input()
|
@Input()
|
||||||
images : string = "";
|
images : string = "";
|
||||||
|
|
||||||
value: number = 0;
|
index: number = 0;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
valueChanged : EventEmitter<number> = new EventEmitter<number>();
|
valueChanged : EventEmitter<number> = new EventEmitter<number>();
|
||||||
|
|
||||||
|
text = undefined;
|
||||||
|
|
||||||
_states : Array<any>;
|
_states : Array<any>;
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this._states = JSON.parse(this.images);
|
this._states = JSON.parse(this.images);
|
||||||
|
this.text = this._states[this.index].text;
|
||||||
}
|
}
|
||||||
|
|
||||||
imageUrl() : string {
|
imageUrl() : string {
|
||||||
return this._states[this.value].imageUrl;
|
return this._states[this.index].imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
title() : string {
|
title() : string {
|
||||||
return this._states[this.value].title;
|
return this._states[this.index].title;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(event){
|
toggle(event){
|
||||||
this.value = (this.value+1) % this._states.length;
|
this.index = (this.index+1) % this._states.length;
|
||||||
this.valueChanged.emit(this.value);
|
this.text = this._states[this.index].text;
|
||||||
|
this.valueChanged.emit(this._states[this.index].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ mat-form-field:last-child {
|
|||||||
mat-form-field.pdb-form-number {
|
mat-form-field.pdb-form-number {
|
||||||
width: 3.5em;
|
width: 3.5em;
|
||||||
}
|
}
|
||||||
|
mat-form-field.pdb-form-number-long {
|
||||||
|
width: 7em;
|
||||||
|
}
|
||||||
.pdb-form-icon-small {
|
.pdb-form-icon-small {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
|
|||||||
Reference in New Issue
Block a user