diff --git a/pdb-js/src/app/app.module.ts b/pdb-js/src/app/app.module.ts
index 42fa956..579a93c 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 } from './gallery-view/gallery-view.component';
+import { GalleryViewComponent, GalleryItemView } from './gallery-view/gallery-view.component';
@NgModule({
declarations: [
@@ -35,6 +35,8 @@ import { GalleryViewComponent } from './gallery-view/gallery-view.component';
QueryAutocompleteComponent,
LimitByComponent,
PlotViewComponent,
+ GalleryViewComponent,
+ GalleryItemView
],
imports: [
BrowserModule,
diff --git a/pdb-js/src/app/gallery-view/gallery-item-view.component.html b/pdb-js/src/app/gallery-view/gallery-item-view.component.html
new file mode 100644
index 0000000..ed38f22
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-item-view.component.html
@@ -0,0 +1,13 @@
+
+
+

+
+
{{data.splitByValue}}
+
Values:
+ {{data.stats.plottedValues}}/
+ {{data.stats.values}}
+
+
Max value: {{ formatMs(data.stats.maxValue) }}
+
Average: {{ formatMs(data.stats.average) }}
+
+
\ No newline at end of file
diff --git a/pdb-js/src/app/gallery-view/gallery-item-view.component.scss b/pdb-js/src/app/gallery-view/gallery-item-view.component.scss
new file mode 100644
index 0000000..fb4163f
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-item-view.component.scss
@@ -0,0 +1,14 @@
+.gallery-item {
+ display: flex;
+ flex-flow: column;
+ background: white;
+ box-shadow: 5px 5px 10px 0px #aaa;
+}
+
+.gallery-item a {
+ align-self: center;
+}
+
+.gallery-item .fieldValue{
+ word-break: break-all;
+}
\ No newline at end of file
diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.html b/pdb-js/src/app/gallery-view/gallery-view.component.html
new file mode 100644
index 0000000..094ce5f
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-view.component.html
@@ -0,0 +1,5 @@
+
diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.scss b/pdb-js/src/app/gallery-view/gallery-view.component.scss
new file mode 100644
index 0000000..c25801b
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-view.component.scss
@@ -0,0 +1,7 @@
+.card-grid-300 {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 300px));
+ grid-gap: 10px;
+ padding: 10px;
+}
+
diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.spec.ts b/pdb-js/src/app/gallery-view/gallery-view.component.spec.ts
new file mode 100644
index 0000000..cbb1400
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-view.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { GalleryViewComponent } from './gallery-view.component';
+
+describe('GalleryViewComponent', () => {
+ let component: GalleryViewComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ GalleryViewComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(GalleryViewComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/pdb-js/src/app/gallery-view/gallery-view.component.ts b/pdb-js/src/app/gallery-view/gallery-view.component.ts
new file mode 100644
index 0000000..16d9e9f
--- /dev/null
+++ b/pdb-js/src/app/gallery-view/gallery-view.component.ts
@@ -0,0 +1,123 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { PlotService, PlotRequest, PlotResponse, PlotResponseStats } from '../plot.service';
+
+@Component({
+ selector: 'pdb-gallery-view',
+ templateUrl: './gallery-view.component.html',
+ styleUrls: ['./gallery-view.component.scss']
+})
+export class GalleryViewComponent implements OnInit {
+
+
+ galleryItems: Array = new Array();
+
+ splitByValuesQueue = new Array();
+
+ constructor(private plotService: PlotService, private snackBar: MatSnackBar) {
+ }
+
+ showError(message) {
+ this.snackBar.open(message, "", {
+ duration: 5000,
+ verticalPosition: 'top'
+ });
+ }
+
+ ngOnInit() {
+ }
+
+ renderGallery(request: PlotRequest, splitByField: string) {
+ const that=this;
+
+ this.galleryItems.length = 0;
+ this.splitByValuesQueue.length = 0;
+
+ request.generateThumbnail = true;
+
+ this.plotService.splitQuery(request.query, splitByField).subscribe(function(valuesForSplitBy){
+ console.log("valuesForSplitBy: " + JSON.stringify(valuesForSplitBy));
+ that.splitByValuesQueue = valuesForSplitBy;
+ that.renderGalleryRecursively(request, splitByField);
+ },
+ error => {
+ that.showError(error.error.message);
+ });
+ }
+
+ renderGalleryRecursively(masterRequest: PlotRequest, splitByField: string){
+ const that = this;
+
+ if (this.splitByValuesQueue.length == 0){
+ return;
+ }
+
+ const splitByValue = this.splitByValuesQueue.pop();
+
+ let request = masterRequest.copy();
+ request.query = "("+request.query+") and " + splitByField+"="+ splitByValue;
+
+ this.plotService.sendPlotRequest(request).subscribe(function(plotResponse : PlotResponse){
+ console.log("response: " + JSON.stringify(plotResponse));
+
+ plotResponse.thumbnailUrl = "http://"+window.location.hostname+':8080/'+plotResponse.thumbnailUrl;
+ plotResponse.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl;
+ let galleryItem = new GalleryItem(splitByValue, plotResponse);
+ that.galleryItems.push(galleryItem);
+ that.renderGalleryRecursively(masterRequest, splitByField);
+ },
+ error => {
+ that.showError(error.error.message);
+ });
+ }
+
+}
+
+@Component({
+ selector: 'pdb-gallery-item-view',
+ templateUrl: './gallery-item-view.component.html',
+ styleUrls: ['./gallery-item-view.component.scss']
+})
+export class GalleryItemView {
+ @Input()
+ data: GalleryItem;
+
+
+ formatMs(valueInMs):string {
+ const ms = Math.floor(valueInMs % 1000);
+ const s = Math.floor((valueInMs / 1000) % 60);
+ const m = Math.floor((valueInMs / (60*1000)) % 60);
+ const h = Math.floor(valueInMs / (3600*1000));
+
+ var result = "";
+ if (h != 0) {
+ result += h+"h ";
+ }
+ if (h!= 0 || m != 0) {
+ result += m+"m ";
+ }
+ if (h!= 0 || m != 0 || s != 0) {
+ result += s+"s ";
+ result += ms+"ms";
+ } else {
+ result += ms+"ms";
+ }
+
+ return result;
+ }
+}
+
+
+export class GalleryItem {
+ thumbnailUrl: string;
+ imageUrl: string;
+ stats: PlotResponseStats;
+ splitByValue : string;
+
+ constructor(splitByValue: string, plotResponse: PlotResponse){
+ this.thumbnailUrl = plotResponse.thumbnailUrl;
+ this.imageUrl = plotResponse.imageUrl;
+ this.splitByValue = splitByValue;
+ this.stats = plotResponse.stats;
+ }
+}
\ No newline at end of file
diff --git a/pdb-js/src/app/plot.service.ts b/pdb-js/src/app/plot.service.ts
index 6c32bbb..e3c12a3 100644
--- a/pdb-js/src/app/plot.service.ts
+++ b/pdb-js/src/app/plot.service.ts
@@ -156,6 +156,10 @@ export class PlotRequest {
yRangeUnit : string;
keyOutside : boolean = false;
generateThumbnail : boolean;
+
+ copy(): PlotRequest {
+ return JSON.parse(JSON.stringify(this));
+ }
}
export class PlotResponse {
diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.scss b/pdb-js/src/app/visualization-page/visualization-page.component.scss
index ef7ff56..f94aeee 100644
--- a/pdb-js/src/app/visualization-page/visualization-page.component.scss
+++ b/pdb-js/src/app/visualization-page/visualization-page.component.scss
@@ -11,6 +11,7 @@
display: grid;
height: 100%;
margin: 0;
+ overflow: hidden;
grid:
"query-box query-box date-box" auto
"filters results results" 1fr
@@ -22,6 +23,7 @@
#visualization {
display: grid;
margin: 0;
+ overflow: hidden;
grid:
"query-box" auto
"date-box" auto
@@ -57,8 +59,8 @@
#results {
grid-area: results;
overflow: hidden;
- margin-right: 0.5em;
position:relative; /* ??? */
+ overflow-y: scroll;
}
#plot-button-bar {
diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.ts b/pdb-js/src/app/visualization-page/visualization-page.component.ts
index 09cfcc7..f7fcbc8 100644
--- a/pdb-js/src/app/visualization-page/visualization-page.component.ts
+++ b/pdb-js/src/app/visualization-page/visualization-page.component.ts
@@ -46,6 +46,9 @@ export class VisualizationPageComponent implements OnInit {
@ViewChild(PlotViewComponent, {static: false})
plotView: PlotViewComponent;
+
+ @ViewChild(GalleryViewComponent, {static: false})
+ galleryView: GalleryViewComponent;
enableGallery = false;
splitBy = null;
@@ -108,13 +111,9 @@ export class VisualizationPageComponent implements OnInit {
gallery(){
const that = this;
- this.plotService.splitQuery(this.query.query, this.splitBy.name).subscribe(function(valuesForSplitBy){
- console.log("valuesForSplitBy: " + JSON.stringify(valuesForSplitBy));
- },
- error => {
- that.plotView.imageUrl = '';
- that.showError(error.error.message);
- });
+ this.plotView.imageUrl = '';
+ const request = this.createPlotRequest();
+ this.galleryView.renderGallery(request, this.splitBy.name);
}
plot(){
@@ -122,7 +121,19 @@ export class VisualizationPageComponent implements OnInit {
that.plotView.imageUrl = '';
+ const request = this.createPlotRequest();
+ this.plotService.sendPlotRequest(request).subscribe(function(plotResponse){
+ console.log("response: " + JSON.stringify(plotResponse));
+ that.plotView.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl;
+ },
+ error => {
+ that.plotView.imageUrl = '';
+ that.showError(error.error.message);
+ });
+ }
+
+ createPlotRequest(): PlotRequest {
const aggregates = [];
aggregates.push(this.selectedPlotType.value.id);
if (this.selectedCombinePlotType.value){
@@ -144,16 +155,7 @@ export class VisualizationPageComponent implements OnInit {
request.yRangeMin = this.yAxisRangeComponent.minYValue;
request.yRangeMax = this.yAxisRangeComponent.maxYValue;
request.yRangeUnit = this.yAxisRangeComponent.yAxisUnit;
-
-
- this.plotService.sendPlotRequest(request).subscribe(function(plotResponse){
- console.log("response: " + JSON.stringify(plotResponse));
- that.plotView.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl;
- },
- error => {
- that.plotView.imageUrl = '';
- that.showError(error.error.message);
- });
+ return request;
}
/**
diff --git a/pdb-js/src/styles.scss b/pdb-js/src/styles.scss
index 20e3743..2ce1286 100644
--- a/pdb-js/src/styles.scss
+++ b/pdb-js/src/styles.scss
@@ -75,6 +75,10 @@ a.external-link:after {
display: inline-block;
}
+.clickable {
+ cursor: pointer;
+}
+
body .mat-select-panel, body .mat-autocomplete-panel {
max-height: 300px;
}