diff --git a/pdb-js/src/app/plot-view/plot-view.component.ts b/pdb-js/src/app/plot-view/plot-view.component.ts index f61e059..edb633c 100644 --- a/pdb-js/src/app/plot-view/plot-view.component.ts +++ b/pdb-js/src/app/plot-view/plot-view.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit, Output, EventEmitter } from '@angular/core'; -import { DataType, AxesTypes, PlotResponseStats } from '../plot.service'; +import { DataType, AxesTypes, PlotResponseStats, PlotConfig, PlotService, PlotResponse, PlotRequest } from '../plot.service'; +import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar'; +import * as moment from 'moment'; @Component({ selector: 'pdb-plot-view', @@ -8,6 +10,7 @@ import { DataType, AxesTypes, PlotResponseStats } from '../plot.service'; }) export class PlotViewComponent implements OnInit { + readonly DATE_PATTERN = "YYYY-MM-DD HH:mm:ss"; // for moment-JS readonly gnuplotLMargin = 110; // The left margin configured for gnuplot readonly gnuplotRMargin = 110; // The right margin configured for gnuplot @@ -19,12 +22,12 @@ export class PlotViewComponent implements OnInit { stats: PlotResponseStats | null = null; axes!: AxesTypes; - + @Output() - zoomRange : EventEmitter = new EventEmitter(); - + loadingEvent : EventEmitter = new EventEmitter(); + @Output() - zoomWithDateAnchor : EventEmitter = new EventEmitter(); + dateRangeUpdateEvent : EventEmitter = new EventEmitter(); in_drag_mode = false; drag_start_x = 0; @@ -41,10 +44,22 @@ export class PlotViewComponent implements OnInit { showStats = false; - constructor() { } + config? : PlotConfig; + + submitterId = crypto.randomUUID(); + + constructor(private service : PlotService, private snackBar: MatSnackBar) { } ngOnInit() { } + + + showError(message:string) { + this.snackBar.open(message, "", { + duration: 5000, + verticalPosition: 'top' + }); + } hideZoomInSlider() { this.zoomInSliderStyleDisplay = "none"; @@ -147,7 +162,7 @@ export class PlotViewComponent implements OnInit { const startPercentOfDateRange = startPxWithinPlotArea / widthPlotArea; const endPercentOfDateRange = endPxWithinPlotArea / widthPlotArea; - this.zoomRange.emit(new SelectionRange(startPercentOfDateRange, endPercentOfDateRange)); + this.zoomRange(new SelectionRange(startPercentOfDateRange, endPercentOfDateRange)); } } } @@ -161,6 +176,25 @@ export class PlotViewComponent implements OnInit { this.hideZoomInSlider(); } } + + 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.dateRangeUpdateEvent.emit(newDateRange); + //this.plot(); + } + + zoomRange(range: SelectionRange) { + this.shiftDate(this.config?.dateRange!, range.startPercentOfDateRange, range.endPercentOfDateRange-1); + } + + zoomWithDateAnchor(dateAnchor: DateAnchor){ + this.shiftDateByAnchor(this.config?.dateRange!, dateAnchor.cursorPercentOfDateRange, dateAnchor.zoomFactor); + } zoomByScroll(event: WheelEvent) { if (this.isInImage(event) && event.deltaY != 0 && this.axes.hasXAxis(DataType.Time)) { @@ -175,7 +209,7 @@ export class PlotViewComponent implements OnInit { const zoomFactor = event.deltaY < 0 ? 0.5 : 2; - this.zoomWithDateAnchor.emit(new DateAnchor(cursorPercentOfDateRange, zoomFactor)); + this.zoomWithDateAnchor(new DateAnchor(cursorPercentOfDateRange, zoomFactor)); } } @@ -186,6 +220,100 @@ export class PlotViewComponent implements OnInit { hideDetails() { this.showStats = false; } + + + + plot(config : PlotConfig, axes: AxesTypes){ + this.config = config; + this.axes = axes; + + const request = this.createPlotRequest(); + + this.loadingEvent.emit(new LoadingEvent(true)); + const x = this.service.sendPlotRequest(request).subscribe({ + next: (plotResponse: PlotResponse) => { + this.imageUrl = "http://"+window.location.hostname+':'+window.location.port+'/'+plotResponse.imageUrl; + this.stats = plotResponse.stats; + document.dispatchEvent(new Event("invadersPause", {})); + this.loadingEvent.emit(new LoadingEvent(false)); + }, + error: (error:any) => { + this.imageUrl = ''; + this.stats = null; + this.showError(error.error.message); + document.dispatchEvent(new Event("invadersPause", {})); + this.loadingEvent.emit(new LoadingEvent(false)); + } + }); + } + + createPlotRequest(): PlotRequest { + const results = document.getElementById("results"); + + + + const request = new PlotRequest( + results != null ? results.offsetHeight-1: 1024, + results != null ? results.offsetWidth-1 : 1024, + 300, // thumbnailMaxWidth + 200, // thumbnailMaxHeight + false, // keyOutside + false, // generateThumbnail + this.submitterId, + this.config!); + 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 { + 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)) + }; + } } export class SelectionRange { @@ -206,4 +334,14 @@ export class DateAnchor { this.cursorPercentOfDateRange = cursorPercentOfDateRange; this.zoomFactor = zoomFactor; } +} + +export class LoadingEvent { + constructor(public loading: boolean){} +} + +export class DateRange { + startDate: any; + endDate: any; + duration: any; } \ No newline at end of file diff --git a/pdb-js/src/app/visualization-page/visualization-page.component.html b/pdb-js/src/app/visualization-page/visualization-page.component.html index 7f220f3..1e99ce4 100644 --- a/pdb-js/src/app/visualization-page/visualization-page.component.html +++ b/pdb-js/src/app/visualization-page/visualization-page.component.html @@ -96,8 +96,8 @@
+ (loadingEvent)="loading($event)" + (dateRangeUpdateEvent)="updateDateRange($event)"> 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 72c3439..cfadfdd 100644 --- a/pdb-js/src/app/visualization-page/visualization-page.component.ts +++ b/pdb-js/src/app/visualization-page/visualization-page.component.ts @@ -5,7 +5,7 @@ import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack import { LimitByComponent } from '../limit-by/limit-by.component'; import { YAxisDefinitionComponent } from '../y-axis-definition/y-axis-definition.component'; import { QueryAutocompleteComponent } from '../query-autocomplete/query-autocomplete.component'; -import { PlotViewComponent, SelectionRange, DateAnchor } from '../plot-view/plot-view.component'; +import { PlotViewComponent, SelectionRange, DateAnchor, LoadingEvent } from '../plot-view/plot-view.component'; import { GalleryViewComponent } from '../gallery-view/gallery-view.component'; import * as moment from 'moment'; @@ -89,6 +89,14 @@ export class VisualizationPageComponent implements OnInit { that.splitBy = that.tagFields.find(val => filterDefaults.splitBy == val.name); }); } + loading(event: LoadingEvent) { + this.plotJobActive = event.loading; + } + + updateDateRange(newDateRange: string) { + (document.getElementById("search-date-range")).value = newDateRange; + this.plot(); + } changePlotType(selectedPlotTypes: Array) { const compatiblePlotTypes = this.plotTypes.filter(pt => pt.compatible(selectedPlotTypes)); @@ -151,34 +159,9 @@ export class VisualizationPageComponent implements OnInit { } plot(){ - const that = this; - - that.plotView.imageUrl = ''; - that.plotView.stats = null; - this.plotJobActive = true; - 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({ - next: (plotResponse: PlotResponse) => { - this.plotView.imageUrl = "http://"+window.location.hostname+':'+window.location.port+'/'+plotResponse.imageUrl; - this.plotView.stats = plotResponse.stats; - this.plotJobActive = false; - document.dispatchEvent(new Event("invadersPause", {})); - }, - error: (error:any) => { - console.log(JSON.stringify(error)); - this.plotView.imageUrl = ''; - this.plotView.stats = null; - this.plotJobActive = false; - this.showError(error.error.message); - document.dispatchEvent(new Event("invadersPause", {})); - } - }); + const config = this.createPlotConfig(); + const axes = this.getAxes(); + this.plotView.plot(config, axes); } createPlotConfig(): PlotConfig { @@ -220,89 +203,4 @@ export class VisualizationPageComponent implements OnInit { config); 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 { - 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; -} - -/* -export class AxesUsed { - x1: DataType; - y1: DataType; - x2: DataType; - y2: DataType; -} -*/