import { Component, OnInit, ViewChild } from '@angular/core'; import { PlotService, PlotType, PlotRequest, PlotResponse, TagField, FilterDefaults } from '../plot.service'; import { Observable } from 'rxjs/Observable'; import { FormControl, Validators } from '@angular/forms'; 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 * 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'); availablePlotTypes = {}; selectedPlotType = new FormControl(''); plotTypes: Array; selectedCombinePlotType = new FormControl(''); combinePlotTypes: Array; tagFields: Array = new Array(); groupBy = new Array(); @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; enableGallery = false; splitBy = null; constructor(private plotService: PlotService) { } ngOnInit() { const that = this; this.plotTypes = this.plotService.getPlotTypes(); this.selectedPlotType.setValue(this.plotTypes[0]); this.plotTypes.forEach(pt => this.availablePlotTypes[pt.name] = pt); this.combinePlotTypes = this.getCombinablePlotTypes(this.selectedPlotType.value); that.plotService.getFilterDefaults().subscribe(function(filterDefaults) { filterDefaults.fields.forEach(function(name) { that.tagFields.push(new TagField(name)); }); that.groupBy = that.tagFields.filter(val => filterDefaults.groupBy.includes(val.name)); that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name); }); this.yAxisScale = "LOG10"; this.selectedPlotType.valueChanges.subscribe(function(selectedMainPlotType){ that.combinePlotTypes = that.getCombinablePlotTypes(selectedMainPlotType); if (!that.combinePlotTypes.includes(that.selectedCombinePlotType.value)){ that.selectedCombinePlotType.setValue(''); } }); } getCombinablePlotTypes(selectedMainPlotType) : Array{ //const mainPlotType = this.availablePlotTypes[selectedMainPlotType]; const mainPlotType = selectedMainPlotType; const compatiblePlotTypes = this.plotTypes.filter(pt => pt.compatible(mainPlotType)); return compatiblePlotTypes; } dateRangeAsString() : string { return (document.getElementById("search-date-range")).value; } gallery(){ const that = this; this.plotService.splitQuery(this.query.query, this.splitBy.name).subscribe(function(valuesForSplitBy){ console.log("valuesForSplitBy: " + JSON.stringify(valuesForSplitBy)); that.plotView.errorMessage = ''; }, error => { that.plotView.imageUrl = ''; that.plotView.errorMessage = error.error.message; }); } plot(){ const that = this; that.plotView.errorMessage = ''; that.plotView.imageUrl = ''; const aggregates = []; aggregates.push(this.selectedPlotType.value.id); if (this.selectedCombinePlotType.value){ aggregates.push(this.selectedCombinePlotType.value.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; this.plotService.sendPlotRequest(request).subscribe(function(plotResponse){ console.log("response: " + JSON.stringify(plotResponse)); that.plotView.imageUrl = "http://"+window.location.hostname+':8080/'+plotResponse.imageUrl; that.plotView.errorMessage = ''; }, error => { that.plotView.imageUrl = ''; that.plotView.errorMessage = error.error.message; }); } /** * 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; (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; }