show fullscreen image
This commit is contained in:
@@ -38,6 +38,7 @@ import { AddTextDialogComponent } from './dashboard-page/dashboard/add-text-dial
|
|||||||
import { TextWidgetComponent } from './dashboard-page/dashboard/text-widget/text-widget.component';
|
import { TextWidgetComponent } from './dashboard-page/dashboard/text-widget/text-widget.component';
|
||||||
import { AddPlotDialogComponent } from './dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component';
|
import { AddPlotDialogComponent } from './dashboard-page/dashboard/add-plot-dialog/add-plot-dialog.component';
|
||||||
import { PlotWidgetComponent } from './dashboard-page/dashboard/plot-widget/plot-widget.component';
|
import { PlotWidgetComponent } from './dashboard-page/dashboard/plot-widget/plot-widget.component';
|
||||||
|
import { FullScreenPlotDialogComponent } from './dashboard-page/dashboard/full-screen-plot-dialog/full-screen-plot-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -61,7 +62,8 @@ import { PlotWidgetComponent } from './dashboard-page/dashboard/plot-widget/plot
|
|||||||
AddTextDialogComponent,
|
AddTextDialogComponent,
|
||||||
TextWidgetComponent,
|
TextWidgetComponent,
|
||||||
AddPlotDialogComponent,
|
AddPlotDialogComponent,
|
||||||
PlotWidgetComponent
|
PlotWidgetComponent,
|
||||||
|
FullScreenPlotDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar';
|
import { MatLegacySnackBar as MatSnackBar } from '@angular/material/legacy-snack-bar';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Dashboard, DashboardService, PlotSize, PlotWidget, PlotWidgetRenderData, TextWidget } from 'src/app/dashboard.service';
|
import { Dashboard, DashboardService, PlotSize, PlotWidget, PlotWidgetRenderData, TextWidget } from 'src/app/dashboard.service';
|
||||||
import { PlotConfig, PlotRequest, PlotResponse, PlotService } from 'src/app/plot.service';
|
import { PlotConfig, PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service';
|
||||||
import { AddPlotDialogComponent } from './add-plot-dialog/add-plot-dialog.component';
|
import { AddPlotDialogComponent } from './add-plot-dialog/add-plot-dialog.component';
|
||||||
import { AddTextDialogComponent } from './add-text-dialog/add-text-dialog.component';
|
import { AddTextDialogComponent } from './add-text-dialog/add-text-dialog.component';
|
||||||
|
|
||||||
@@ -67,11 +67,15 @@ export class DashboardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
createPlotRequest(plotWidget: PlotWidget): PlotRequest {
|
createPlotRequest(plotWidget: PlotWidget): PlotRequest {
|
||||||
|
|
||||||
const height = this.height(plotWidget.size);
|
const height = this.height(plotWidget.size);
|
||||||
const width = this.width(plotWidget.size);
|
const width = this.width(plotWidget.size);
|
||||||
|
|
||||||
|
const fullWidth = window.innerWidth-30;
|
||||||
|
const fullHeight = window.innerHeight-30;
|
||||||
|
|
||||||
const request = new PlotRequest(
|
const request = new PlotRequest(
|
||||||
height,
|
height,
|
||||||
width,
|
width,
|
||||||
@@ -80,7 +84,12 @@ export class DashboardComponent implements OnInit {
|
|||||||
false, // keyOutside
|
false, // keyOutside
|
||||||
false, // generateThumbnail
|
false, // generateThumbnail
|
||||||
(<any>window).submitterId+crypto.randomUUID(),
|
(<any>window).submitterId+crypto.randomUUID(),
|
||||||
plotWidget.config);
|
plotWidget.config,
|
||||||
|
{
|
||||||
|
'main': new RenderOptions(height,width, false, true),
|
||||||
|
'fullScreen': new RenderOptions(fullHeight,fullWidth, false, true)
|
||||||
|
}
|
||||||
|
);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<style>
|
||||||
|
button {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<img [src]="data.imageUrl" (click)="close()" />
|
||||||
|
<button mat-icon-button mat-dialog-close cdkFocusInitial><img src="assets/img/close.svg" class="icon-small" /></button>
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-full-screen-plot-dialog',
|
||||||
|
templateUrl: './full-screen-plot-dialog.component.html'
|
||||||
|
})
|
||||||
|
export class FullScreenPlotDialogComponent {
|
||||||
|
|
||||||
|
|
||||||
|
constructor(public dialogRef: MatDialogRef<void>, @Inject(MAT_DIALOG_DATA) public data: {imageUrl: string}){}
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="dashboard-card" [ngClass]="{'size-medium' : data.widget.size=='MEDIUM'}">
|
<div class="dashboard-card" [ngClass]="{'size-medium' : data.widget.size=='MEDIUM'}">
|
||||||
<mat-spinner *ngIf="!data.plotResponse?.imageUrl && !isError"></mat-spinner>
|
<mat-spinner *ngIf="!hasRender('main') && !isError"></mat-spinner>
|
||||||
<img *ngIf="data.plotResponse?.imageUrl" src="{{data.plotResponse?.imageUrl}}" />
|
<img *ngIf="hasRender('main')" [src]="getImageUrl('main')" (click)="showFullScreenImage()" />
|
||||||
<div *ngIf="isError">
|
<div *ngIf="isError">
|
||||||
There was an error! This is a good time to panic!
|
There was an error! This is a good time to panic!
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { PlotWidget, PlotWidgetRenderData } from 'src/app/dashboard.service';
|
import { PlotWidget, PlotWidgetRenderData } from 'src/app/dashboard.service';
|
||||||
import { PlotViewComponent } from 'src/app/plot-view/plot-view.component';
|
import { PlotViewComponent } from 'src/app/plot-view/plot-view.component';
|
||||||
import { PlotRequest, PlotResponse, PlotService } from 'src/app/plot.service';
|
import { PlotRequest, PlotResponse, PlotService, RenderOptions } from 'src/app/plot.service';
|
||||||
|
import { FullScreenPlotDialogComponent } from '../full-screen-plot-dialog/full-screen-plot-dialog.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-plot-widget',
|
selector: 'app-plot-widget',
|
||||||
@@ -17,37 +19,28 @@ export class PlotWidgetComponent implements AfterViewInit {
|
|||||||
|
|
||||||
@ViewChild("plotView") plotView!: PlotViewComponent;
|
@ViewChild("plotView") plotView!: PlotViewComponent;
|
||||||
|
|
||||||
constructor(private plotService : PlotService){}
|
constructor(private dialog: MatDialog, ){}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
/*
|
|
||||||
const plotRequest = this.createPlotRequest();
|
|
||||||
this.plotService.sendPlotRequest(plotRequest).subscribe({
|
|
||||||
next: (response: PlotResponse) => {
|
|
||||||
this.thumbnailUrl = response.imageUrl;
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.isError = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createPlotRequest(): PlotRequest {
|
hasRender(name: string): boolean{
|
||||||
|
return this.data.plotResponse!.rendered[name] !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getImageUrl(name: string ): string {
|
||||||
|
return this.data.plotResponse!.rendered[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
showFullScreenImage(){
|
||||||
|
|
||||||
const height = window.innerHeight - 20;
|
this.dialog.open(FullScreenPlotDialogComponent,{
|
||||||
const width = window. innerWidth - 20;
|
width: 'calc(100% - 15px)',
|
||||||
|
height: 'calc(100% - 15px)',
|
||||||
const request = new PlotRequest(
|
'data': {'imageUrl': this.getImageUrl('fullScreen')}
|
||||||
500,
|
}).afterClosed().subscribe(() => {
|
||||||
600,
|
|
||||||
600, // thumbnailMaxWidth
|
});
|
||||||
500, // thumbnailMaxHeight
|
}
|
||||||
false, // keyOutside
|
|
||||||
false, // generateThumbnail
|
|
||||||
(<any>window).submitterId,
|
|
||||||
this.data.widget.config!);
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -281,7 +281,8 @@ export class PlotViewComponent implements OnInit {
|
|||||||
false, // keyOutside
|
false, // keyOutside
|
||||||
false, // generateThumbnail
|
false, // generateThumbnail
|
||||||
(<any>window).submitterId,
|
(<any>window).submitterId,
|
||||||
this.config!);
|
this.config!,
|
||||||
|
{});
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,14 @@ export class AutocompleteResult{
|
|||||||
constructor(public proposals: Array<Suggestion>){}
|
constructor(public proposals: Array<Suggestion>){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RenderOptionsMap = {
|
||||||
|
[key: string]: RenderOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RenderedImages = {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
export class PlotRequest {
|
export class PlotRequest {
|
||||||
constructor(
|
constructor(
|
||||||
public height : number,
|
public height : number,
|
||||||
@@ -214,7 +222,8 @@ export class PlotRequest {
|
|||||||
public keyOutside : boolean = false,
|
public keyOutside : boolean = false,
|
||||||
public generateThumbnail : boolean,
|
public generateThumbnail : boolean,
|
||||||
public submitterId: string,
|
public submitterId: string,
|
||||||
public config: PlotConfig
|
public config: PlotConfig,
|
||||||
|
public renders: RenderOptionsMap
|
||||||
){}
|
){}
|
||||||
|
|
||||||
|
|
||||||
@@ -237,6 +246,14 @@ export class PlotConfig {
|
|||||||
public renderBarChartTickLabels: boolean = false,) {}
|
public renderBarChartTickLabels: boolean = false,) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RenderOptions {
|
||||||
|
constructor(
|
||||||
|
public height: number,
|
||||||
|
public width: number,
|
||||||
|
public keyOutside: boolean,
|
||||||
|
public renderLabels: boolean) {}
|
||||||
|
}
|
||||||
|
|
||||||
export class YAxisDefinition {
|
export class YAxisDefinition {
|
||||||
constructor(
|
constructor(
|
||||||
public axisScale : string,
|
public axisScale : string,
|
||||||
@@ -249,7 +266,8 @@ export class PlotResponse {
|
|||||||
constructor(
|
constructor(
|
||||||
public imageUrl : string,
|
public imageUrl : string,
|
||||||
public stats : PlotResponseStats,
|
public stats : PlotResponseStats,
|
||||||
public thumbnailUrl : string){}
|
public thumbnailUrl : string,
|
||||||
|
public rendered: RenderedImages){}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PlotResponseStats {
|
export class PlotResponseStats {
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ export class VisualizationPageComponent implements OnInit {
|
|||||||
false, // keyOutside
|
false, // keyOutside
|
||||||
this.enableGallery, // generateThumbnail
|
this.enableGallery, // generateThumbnail
|
||||||
(<any>window).submitterId,
|
(<any>window).submitterId,
|
||||||
config);
|
config,
|
||||||
|
{});
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,25 @@ package org.lucares.recommind.logs;
|
|||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PlotResult {
|
public class PlotResult {
|
||||||
private final Path imagePath;
|
private final Path imagePath;
|
||||||
private final List<DataSeries> dataSeries;
|
private final List<DataSeries> dataSeries;
|
||||||
private final Path thumbnail;
|
private final Path thumbnail;
|
||||||
|
private final Map<String, Path> renderedImages;
|
||||||
|
|
||||||
public PlotResult(final Path imagePath, final List<DataSeries> dataSeries, final Path thumbnail) {
|
public PlotResult(final Path imagePath, final List<DataSeries> dataSeries, final Path thumbnail,
|
||||||
|
final Map<String, Path> renderedImages) {
|
||||||
super();
|
super();
|
||||||
this.imagePath = imagePath;
|
this.imagePath = imagePath;
|
||||||
this.dataSeries = dataSeries;
|
this.dataSeries = dataSeries;
|
||||||
this.thumbnail = thumbnail;
|
this.thumbnail = thumbnail;
|
||||||
|
this.renderedImages = renderedImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Path> getRenderedImages() {
|
||||||
|
return renderedImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getImageName() {
|
public Path getImageName() {
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ import java.time.OffsetDateTime;
|
|||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -26,6 +29,7 @@ import org.lucares.pdb.api.Tags;
|
|||||||
import org.lucares.pdb.plot.api.AggregatorCollection;
|
import org.lucares.pdb.plot.api.AggregatorCollection;
|
||||||
import org.lucares.pdb.plot.api.Limit;
|
import org.lucares.pdb.plot.api.Limit;
|
||||||
import org.lucares.pdb.plot.api.PlotSettings;
|
import org.lucares.pdb.plot.api.PlotSettings;
|
||||||
|
import org.lucares.pdb.plot.api.RenderOptions;
|
||||||
import org.lucares.performance.db.PerformanceDb;
|
import org.lucares.performance.db.PerformanceDb;
|
||||||
import org.lucares.utils.file.FileUtils;
|
import org.lucares.utils.file.FileUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -145,7 +149,26 @@ public class Plotter {
|
|||||||
thumbnail = null;
|
thumbnail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PlotResult(outputFile, dataSeries, thumbnail);
|
final Map<String, Path> renderedImages = new HashMap<>();
|
||||||
|
for (final Entry<String, RenderOptions> renders : plotSettings.getRenders().entrySet()) {
|
||||||
|
final Path file = Files.createTempFile(outputDir, "", ".png");
|
||||||
|
renderedImages.put(renders.getKey(), file);
|
||||||
|
final RenderOptions renderOptions = renders.getValue();
|
||||||
|
|
||||||
|
final Gnuplot gnuplot = new Gnuplot(tmpBaseDir);
|
||||||
|
final GnuplotSettings gnuplotSettings = new GnuplotSettings(file);
|
||||||
|
gnuplotSettings.setHeight(renderOptions.getHeight());
|
||||||
|
gnuplotSettings.setWidth(renderOptions.getWidth());
|
||||||
|
gnuplotSettings.setDateTimeRange(plotSettings.dateRange());
|
||||||
|
gnuplotSettings.setY1(plotSettings.getY1());
|
||||||
|
gnuplotSettings.setY2(plotSettings.getY2());
|
||||||
|
gnuplotSettings.setAggregates(plotSettings.getAggregates());
|
||||||
|
gnuplotSettings.setKeyOutside(renderOptions.isKeyOutside());
|
||||||
|
gnuplotSettings.renderLabels(renderOptions.isRenderLabels());
|
||||||
|
gnuplot.plot(gnuplotSettings, dataSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PlotResult(outputFile, dataSeries, thumbnail, renderedImages);
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new AbortException();
|
throw new AbortException();
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
package org.lucares.pdbui;
|
package org.lucares.pdbui;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
@@ -120,8 +124,16 @@ public class PdbController implements HardcodedValues, PropertyKeys {
|
|||||||
? WEB_IMAGE_OUTPUT_PATH + "/" + result.getThumbnailName()
|
? WEB_IMAGE_OUTPUT_PATH + "/" + result.getThumbnailName()
|
||||||
: "img/no-thumbnail.png";
|
: "img/no-thumbnail.png";
|
||||||
|
|
||||||
|
final Map<String, String> rendered = new HashMap<>();
|
||||||
|
for (final Entry<String, Path> renderedImageEntry : result.getRenderedImages().entrySet()) {
|
||||||
|
final String url = WEB_IMAGE_OUTPUT_PATH + "/"
|
||||||
|
+ renderedImageEntry.getValue().getFileName();
|
||||||
|
|
||||||
|
rendered.put(renderedImageEntry.getKey(), url);
|
||||||
|
}
|
||||||
|
|
||||||
final PlotResponseStats stats = PlotResponseStats.fromDataSeries(result.getDataSeries());
|
final PlotResponseStats stats = PlotResponseStats.fromDataSeries(result.getDataSeries());
|
||||||
final PlotResponse plotResponse = new PlotResponse(stats, imageUrl, thumbnailUrl);
|
final PlotResponse plotResponse = new PlotResponse(stats, imageUrl, thumbnailUrl, rendered);
|
||||||
|
|
||||||
return ResponseEntity.ok().body(plotResponse);
|
return ResponseEntity.ok().body(plotResponse);
|
||||||
} catch (final NoDataPointsException e) {
|
} catch (final NoDataPointsException e) {
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
package org.lucares.pdbui.domain;
|
package org.lucares.pdbui.domain;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PlotResponse {
|
public class PlotResponse {
|
||||||
private String imageUrl = "";
|
private String imageUrl = "";
|
||||||
private PlotResponseStats stats;
|
private PlotResponseStats stats;
|
||||||
private String thumbnailUrl;
|
private String thumbnailUrl;
|
||||||
|
private final Map<String, String> rendered;
|
||||||
|
|
||||||
public PlotResponse(final PlotResponseStats stats, final String imageUrl, final String thumbnailUrl) {
|
public PlotResponse(final PlotResponseStats stats, final String imageUrl, final String thumbnailUrl,
|
||||||
|
final Map<String, String> rendered) {
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
this.thumbnailUrl = thumbnailUrl;
|
this.thumbnailUrl = thumbnailUrl;
|
||||||
|
this.rendered = rendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getRendered() {
|
||||||
|
return rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getImageUrl() {
|
public String getImageUrl() {
|
||||||
|
|||||||
Reference in New Issue
Block a user