Files
perfdb/pdb-js/src/app/visualization-page/visualization-page.component.ts

239 lines
8.5 KiB
TypeScript

import { Component, OnInit, ViewChild } from '@angular/core';
import { PlotService, PlotType, PlotRequest, PlotResponse, TagField, FilterDefaults, DataType, AxesTypes } from '../plot.service';
import { Observable } from 'rxjs/Observable';
import { FormControl, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar';
import { LimitByComponent } from '../limit-by/limit-by.component';
import { YAxisRangeComponent } from '../y-axis-range/y-axis-range.component';
import { QueryAutocompleteComponent } from '../query-autocomplete/query-autocomplete.component';
import { PlotViewComponent, SelectionRange, DateAnchor } from '../plot-view/plot-view.component';
import { GalleryViewComponent } from '../gallery-view/gallery-view.component';
import * as moment from 'moment';
@Component({
selector: 'pdb-visualization-page',
templateUrl: './visualization-page.component.html',
styleUrls: ['./visualization-page.component.scss']
})
export class VisualizationPageComponent implements OnInit {
readonly DATE_PATTERN = "YYYY-MM-DD HH:mm:ss"; // for moment-JS
dateRange = new FormControl('2019-10-05 00:00:00 - 2019-10-11 23:59:59');
selectedPlotType = [];
plotTypes: Array<any>;
tagFields: Array<TagField> = new Array<TagField>();
groupBy = new Array<TagField>();
@ViewChild(LimitByComponent, {static: false})
private limitbycomponent : LimitByComponent;
yAxisScale: string;
@ViewChild(YAxisRangeComponent, {static: false})
private yAxisRangeComponent : YAxisRangeComponent;
@ViewChild(QueryAutocompleteComponent, {static: false})
query: QueryAutocompleteComponent;
@ViewChild(PlotViewComponent, {static: false})
plotView: PlotViewComponent;
@ViewChild(GalleryViewComponent, {static: false})
galleryView: GalleryViewComponent;
enableGallery = false;
splitBy = null;
constructor(private plotService: PlotService, private snackBar: MatSnackBar) {
}
showError(message) {
this.snackBar.open(message, "", {
duration: 5000,
verticalPosition: 'top'
});
}
ngOnInit() {
const that = this;
this.plotTypes = this.plotService.getPlotTypes();
this.selectedPlotType.push(this.plotTypes[0]);
that.plotService.getFilterDefaults().subscribe(function(filterDefaults) {
filterDefaults.fields.forEach(function(name) {
that.tagFields.push(new TagField(name));
},
error => {
that.showError(error.error.message);
});
that.groupBy = that.tagFields.filter(val => filterDefaults.groupBy.includes(val.name));
that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name);
});
this.yAxisScale = "LOG10";
}
changePlotType(selectedPlotTypes: Array<PlotType>) {
const compatiblePlotTypes = this.plotTypes.filter(pt => pt.compatible(selectedPlotTypes));
this.plotTypes.forEach(pt => pt.active=false);
compatiblePlotTypes.forEach(pt => pt.active=true);
}
dateRangeAsString() : string {
return (<HTMLInputElement>document.getElementById("search-date-range")).value;
}
gallery(){
const that = this;
this.plotView.imageUrl = '';
that.galleryView.show=true;
const request = this.createPlotRequest();
this.galleryView.renderGallery(request, this.splitBy.name);
}
getAxes() : AxesTypes {
var x = new Set<DataType>();
var y = new Set<DataType>();
for(var i = 0; i < this.selectedPlotType.length; i++){
var plotType = this.selectedPlotType[i];
x.add(plotType.xAxis);
y.add(plotType.yAxis);
}
return new AxesTypes(x,y);
}
plot(){
const that = this;
that.plotView.imageUrl = '';
this.plotView.axes = this.getAxes();
console.log(JSON.stringify(this.getAxes()));
that.galleryView.show=false;
document.dispatchEvent(new Event("invadersStart", {}));
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;
document.dispatchEvent(new Event("invadersPause", {}));
},
error => {
that.plotView.imageUrl = '';
that.showError(error.error.message);
document.dispatchEvent(new Event("invadersPause", {}));
});
}
createPlotRequest(): PlotRequest {
const aggregates = [];
this.selectedPlotType.forEach(a => aggregates.push(a.id));
const request = new PlotRequest();
request.query = this.query.query;
request.height = document.getElementById("results").offsetHeight-1;
request.width = document.getElementById("results").offsetWidth-1;
request.groupBy = this.groupBy.map(o => o.name);
request.limitBy = this.limitbycomponent.limitBy;
request.limit = this.limitbycomponent.limit;
request.dateRange = this.dateRangeAsString();
request.axisScale = this.yAxisScale;
request.aggregates = aggregates;
request.keyOutside = false;
request.generateThumbnail = this.enableGallery;
request.yRangeMin = this.yAxisRangeComponent.minYValue;
request.yRangeMax = this.yAxisRangeComponent.maxYValue;
request.yRangeUnit = this.yAxisRangeComponent.yAxisUnit;
return request;
}
/**
* Zoom in/out by zoomFaktor, so that the anchorInPercentOfDateRange keeps the same position.
*
* shiftDateByAnchor(dateRangeAsString, 0.20, 0.5) zooms in by 50%, so that the date that was at 20% before the zoom is still at 20% after the zoom
* shiftDateByAnchor(dateRangeAsString, 0.33, 2) zooms out by 50%, so that the date that was at 33% before the zoom is still at 33% after the zoom
*/
shiftDateByAnchor(dateRange:string, anchorInPercentOfDateRange:number, zoomFactor:number)
{
const dateRangeParsed = this.parseDateRange(dateRange);
const dateRangeInSeconds = dateRangeParsed.duration.asSeconds();
const anchorTimestampInSeconds = dateRangeParsed.startDate.clone().add(Math.floor(dateRangeInSeconds*anchorInPercentOfDateRange), "seconds");
const newDateRangeInSeconds = dateRangeInSeconds * zoomFactor;
const newStartDate = anchorTimestampInSeconds.clone().subtract(newDateRangeInSeconds*anchorInPercentOfDateRange, "seconds");
const newEndDate = newStartDate.clone().add({seconds: newDateRangeInSeconds});;
this.setDateRange(newStartDate, newEndDate);
}
/**
* Zoom in/out or shift date by adding factorStartDate*dateRangeInSeconds seconds to the start date
* and factorEndDate*dateRangeInSeconds seconds to the end date.
*
* shiftDate(dateRangeAsString, 0.25, -0.25) will zoom in, making the range half its size
* shiftDate(dateRangeAsString, -0.5, 0.5) will zoom out, making the range double its size
* shiftDate(dateRangeAsString, -0.5, -0.5) will move the range by half its size to older values
* shiftDate(dateRangeAsString, 1, 1) will move the range by its size to newer values
*/
shiftDate(dateRange: string, factorStartDate: number, factorEndDate: number)
{
const dateRangeParsed = this.parseDateRange(dateRange);
const dateRangeInSeconds = dateRangeParsed.duration.asSeconds();
const newStartDate = dateRangeParsed.startDate.add({seconds: dateRangeInSeconds*factorStartDate});
const newEndDate = dateRangeParsed.endDate.add({seconds: dateRangeInSeconds*factorEndDate});
this.setDateRange(newStartDate, newEndDate);
}
parseDateRange(dateRangeAsString : string) : DateRange {
if (dateRangeAsString) {
const startDate = moment(dateRangeAsString.slice(0, 19));
const endDate = moment(dateRangeAsString.slice(22, 41));
return {
startDate: startDate,
endDate: endDate,
duration: moment.duration(endDate.diff(startDate))
};
}
}
setDateRange(startDate: any, endDate: any) {
const formattedStartDate = startDate.format(this.DATE_PATTERN);
const formattedEndDate = endDate.format(this.DATE_PATTERN);
const newDateRange = formattedStartDate+" - "+formattedEndDate;
(<HTMLInputElement>document.getElementById("search-date-range")).value = newDateRange;
this.plot();
}
zoomRange(range: SelectionRange) {
this.shiftDate(this.dateRangeAsString(), range.startPercentOfDateRange, range.endPercentOfDateRange-1);
}
zoomWithDateAnchor(dateAnchor: DateAnchor){
this.shiftDateByAnchor(this.dateRangeAsString(), dateAnchor.cursorPercentOfDateRange, dateAnchor.zoomFactor);
}
}
export class DateRange {
startDate: any;
endDate: any;
duration: any;
}