This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new c410d113ff fix: Image rendering in data explorer (#2918)
c410d113ff is described below
commit c410d113ff40506888a7edaddbb444ef9b1718b9
Author: Dominik Riemer <[email protected]>
AuthorDate: Fri Jun 7 09:15:54 2024 +0200
fix: Image rendering in data explorer (#2918)
* fix: Image rendering in data explorer
* Fix checkstyle
---
.../streampipes/ps/DataLakeImageResource.java | 9 +-
.../image-bar-preview.component.html | 2 +-
.../image-bar-preview.component.scss | 1 +
.../image/image-bar/image-bar.component.html | 114 ++++++++++-----------
.../image/image-bar/image-bar.component.scss | 4 -
.../image-container.component.html} | 18 ++--
.../image-container.component.scss} | 7 +-
.../image-container/image-container.component.ts | 81 +++++++++++++++
.../image/image-viewer/image-viewer.component.html | 30 +++---
.../widgets/image/image-widget.component.html | 31 +++---
.../widgets/image/image-widget.component.ts | 21 +---
ui/src/app/data-explorer/data-explorer.module.ts | 2 +
12 files changed, 190 insertions(+), 130 deletions(-)
diff --git
a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeImageResource.java
b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeImageResource.java
index 6e71ec1a36..dca9b530d5 100644
---
a/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeImageResource.java
+++
b/streampipes-platform-services/src/main/java/org/apache/streampipes/ps/DataLakeImageResource.java
@@ -21,21 +21,22 @@ package org.apache.streampipes.ps;
import
org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
import org.apache.streampipes.storage.management.StorageDispatcher;
+import org.apache.commons.io.IOUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-
-import java.io.InputStream;
+import java.io.IOException;
@RestController
@RequestMapping("/api/v4/datalake/images")
public class DataLakeImageResource extends AbstractAuthGuardedRestResource {
@GetMapping(path = "{imageId}", produces = "image/jpeg")
- public ResponseEntity<InputStream> getImage(@PathVariable("imageId") String
imageId) {
- return
ok(StorageDispatcher.INSTANCE.getNoSqlStore().getImageStorage().getImageBytes(imageId));
+ public ResponseEntity<byte[]> getImage(@PathVariable("imageId") String
imageId) throws IOException {
+ var image =
StorageDispatcher.INSTANCE.getNoSqlStore().getImageStorage().getImageBytes(imageId);
+ return ok(IOUtils.toByteArray(image));
}
}
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
index 6bb8c48acc..f2c949996e 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
+++
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
@@ -18,7 +18,7 @@
<img
[ngClass]="focus ? 'imagePreview imageFocus' : 'imagePreview'"
- [style.height.px]="imagePreviewHeight"
+ [style.height.px]="imagePreviewHeight - 40"
*ngIf="showImage"
[src]="imagePath"
/>
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.scss
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.scss
index 499314a337..adc14cfa96 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.scss
+++
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.scss
@@ -20,6 +20,7 @@
height: 65px;
margin-left: 10px;
margin-right: 10px;
+ cursor: pointer;
}
.imageFocus {
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.html
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.html
index 6606552180..e1ba9ec18f 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.html
+++
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.html
@@ -16,67 +16,59 @@
~
-->
-<div fxLayout="row" fxLayoutAlign="center center">
- <div>{{ selectedIndex + 1 }} / {{ maxImages }}</div>
-</div>
-
-<div fxLayout="row" fxLayoutAlign="space-around center">
- <button mat-icon-button (click)="goToStart()">
- <mat-icon>skip_previous</mat-icon>
- </button>
- <button mat-icon-button (click)="nextImage()">
- <mat-icon>keyboard_arrow_left</mat-icon>
- </button>
-
- <div fxLayout="row" fxLayoutAlign="center center" class="imageBar">
- <div fxFlex="40" fxLayoutAlign="end center">
- <sp-image-bar-preview
- [imagePreviewHeight]="imagePreviewHeight"
- [imageSrc]="_imageRoutes[selectedIndex - 2]"
- *ngIf="selectedIndex >= 2"
- (click)="changeImage(selectedIndex - 2)"
- ></sp-image-bar-preview>
- <sp-image-bar-preview
- [imagePreviewHeight]="imagePreviewHeight"
- [imageSrc]="_imageRoutes[selectedIndex - 1]"
- *ngIf="selectedIndex >= 1"
- (click)="changeImage(selectedIndex - 1)"
- ></sp-image-bar-preview>
- </div>
-
- <div fxFlex="20">
- <div fxLayout="row" fxLayoutAlign="center">
- <sp-image-bar-preview
- [imagePreviewHeight]="imagePreviewHeight"
- [imageSrc]="_imageRoutes[selectedIndex]"
- [focus]="true"
- (click)="changeImage(selectedIndex)"
- ></sp-image-bar-preview>
- </div>
- </div>
-
- <div fxFlex="40">
- <div fxLayout="row" fxLayoutAlign="start center">
- <sp-image-bar-preview
- [imagePreviewHeight]="imagePreviewHeight"
- [imageSrc]="_imageRoutes[selectedIndex + 1]"
- *ngIf="selectedIndex < maxImages - 1"
- (click)="changeImage(selectedIndex + 1)"
- ></sp-image-bar-preview>
- <sp-image-bar-preview
- [imagePreviewHeight]="imagePreviewHeight"
- [imageSrc]="_imageRoutes[selectedIndex + 2]"
- *ngIf="selectedIndex < maxImages - 2"
- (click)="changeImage(selectedIndex + 2)"
- ></sp-image-bar-preview>
- </div>
- </div>
+<div fxFlex="100" fxLayout="column">
+ <div fxLayout="row" fxLayoutAlign="center center" class="mb-10">
+ <div>{{ selectedIndex + 1 }} / {{ maxImages }}</div>
</div>
- <button mat-icon-button (click)="previousImage()">
- <mat-icon>keyboard_arrow_right</mat-icon>
- </button>
- <button mat-icon-button (click)="goToEnd()">
- <mat-icon>skip_next</mat-icon>
- </button>
+ <div
+ fxFlex
+ fxLayout="row"
+ fxLayoutAlign="center center"
+ class="imageBar"
+ fxLayoutGap="10px"
+ >
+ <button mat-icon-button (click)="goToStart()">
+ <mat-icon>skip_previous</mat-icon>
+ </button>
+ <button mat-icon-button (click)="nextImage()">
+ <mat-icon>keyboard_arrow_left</mat-icon>
+ </button>
+ <sp-image-bar-preview
+ [imagePreviewHeight]="imagePreviewHeight"
+ [imageSrc]="_imageRoutes[selectedIndex - 2]"
+ *ngIf="selectedIndex >= 2"
+ (click)="changeImage(selectedIndex - 2)"
+ ></sp-image-bar-preview>
+ <sp-image-bar-preview
+ [imagePreviewHeight]="imagePreviewHeight"
+ [imageSrc]="_imageRoutes[selectedIndex - 1]"
+ *ngIf="selectedIndex >= 1"
+ (click)="changeImage(selectedIndex - 1)"
+ ></sp-image-bar-preview>
+ <sp-image-bar-preview
+ [imagePreviewHeight]="imagePreviewHeight"
+ [imageSrc]="_imageRoutes[selectedIndex]"
+ [focus]="true"
+ (click)="changeImage(selectedIndex)"
+ ></sp-image-bar-preview>
+ <sp-image-bar-preview
+ [imagePreviewHeight]="imagePreviewHeight"
+ [imageSrc]="_imageRoutes[selectedIndex + 1]"
+ *ngIf="selectedIndex < maxImages - 1"
+ (click)="changeImage(selectedIndex + 1)"
+ ></sp-image-bar-preview>
+ <sp-image-bar-preview
+ [imagePreviewHeight]="imagePreviewHeight"
+ [imageSrc]="_imageRoutes[selectedIndex + 2]"
+ *ngIf="selectedIndex < maxImages - 2"
+ (click)="changeImage(selectedIndex + 2)"
+ ></sp-image-bar-preview>
+ <button mat-icon-button (click)="previousImage()">
+ <mat-icon>keyboard_arrow_right</mat-icon>
+ </button>
+ <button mat-icon-button (click)="goToEnd()">
+ <mat-icon>skip_next</mat-icon>
+ </button>
+ </div>
</div>
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
index 0c64d80038..13cbc4aacb 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
+++
b/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
@@ -15,7 +15,3 @@
* limitations under the License.
*
*/
-
-.imageBar {
- height: 70px;
-}
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.html
similarity index 73%
copy from
ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
copy to
ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.html
index 6bb8c48acc..5536e7c2bb 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar-preview/image-bar-preview.component.html
+++
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.html
@@ -15,10 +15,14 @@
~ limitations under the License.
~
-->
-
-<img
- [ngClass]="focus ? 'imagePreview imageFocus' : 'imagePreview'"
- [style.height.px]="imagePreviewHeight"
- *ngIf="showImage"
- [src]="imagePath"
-/>
+<div class="main-image" fxLayoutAlign="center center" fxFlex="100">
+ <img
+ class="main-image"
+ [src]="imagePath"
+ [style.width.px]="imageWidth"
+ [style.height.px]="imageHeight"
+ #mainImg
+ *ngIf="showImage"
+ (load)="onImageLoaded()"
+ />
+</div>
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.scss
similarity index 88%
copy from
ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
copy to
ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.scss
index 0c64d80038..754495c653 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-bar/image-bar.component.scss
+++
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.scss
@@ -16,6 +16,9 @@
*
*/
-.imageBar {
- height: 70px;
+.main-image {
+ margin-left: auto;
+ margin-right: auto;
+ max-height: 100%;
+ max-width: 100%;
}
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.ts
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.ts
new file mode 100644
index 0000000000..ac5123b1c6
--- /dev/null
+++
b/ui/src/app/data-explorer/components/widgets/image/image-container/image-container.component.ts
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { SafeUrl } from '@angular/platform-browser';
+import { Observable } from 'rxjs';
+
+@Component({
+ selector: 'sp-image-container',
+ templateUrl: './image-container.component.html',
+ styleUrls: ['./image-container.component.scss'],
+})
+export class SpImageContainerComponent {
+ imagePath: SafeUrl;
+ showImage = false;
+
+ @ViewChild('mainImg') imageRef: ElementRef;
+
+ @Input()
+ public canvasHeight = 500;
+
+ @Input()
+ public canvasWidth = 800;
+
+ imageWidth = 0;
+ imageHeight = 0;
+
+ constructor() {}
+
+ onImageLoaded() {
+ const naturalImageWidth = (
+ this.imageRef.nativeElement as HTMLImageElement
+ ).naturalWidth;
+ const naturalImageHeight = (
+ this.imageRef.nativeElement as HTMLImageElement
+ ).naturalHeight;
+ this.calculateImageDimensions(naturalImageWidth, naturalImageHeight);
+ }
+
+ calculateImageDimensions(imageWidth: number, imageHeight: number): void {
+ const canvasAspectRatio = this.canvasWidth / this.canvasHeight;
+ const imageAspectRatio = imageWidth / imageHeight;
+
+ let finalWidth: number;
+ let finalHeight: number;
+
+ if (imageAspectRatio > canvasAspectRatio) {
+ finalWidth = this.canvasWidth;
+ finalHeight = this.canvasWidth / imageAspectRatio;
+ } else {
+ finalHeight = this.canvasHeight;
+ finalWidth = this.canvasHeight * imageAspectRatio;
+ }
+
+ this.imageWidth = finalWidth;
+ this.imageHeight = finalHeight;
+ }
+
+ @Input()
+ set imageSrc(src: Observable<Blob>) {
+ src.subscribe(url => {
+ this.imagePath = url;
+ this.showImage = true;
+ });
+ }
+}
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-viewer/image-viewer.component.html
b/ui/src/app/data-explorer/components/widgets/image/image-viewer/image-viewer.component.html
index c6bfa13867..59d4bd48ad 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-viewer/image-viewer.component.html
+++
b/ui/src/app/data-explorer/components/widgets/image/image-viewer/image-viewer.component.html
@@ -17,22 +17,22 @@
-->
<div style="width: 100%; height: 100%">
- <div fxLayout="column" fxLayoutAlign="space-between ">
- <div fxLayout="row" fxLayoutAlign="space-around start">
- <div fxLayout="column" fxLayoutAlign="space-between ">
- <sp-image-container
- *ngIf="imagesRoutes.length > 0"
- [imageSrc]="imagesRoutes[imagesIndex]"
- [canvasWidth]="canvasWidth"
- [canvasHeight]="canvasHeight"
- >
- </sp-image-container>
- </div>
- </div>
- <br />
-
+ <div [ngStyle]="{ width: canvasWidth, height: canvasHeight + 'px' }">
+ <sp-image-container
+ fxFlex="100"
+ *ngIf="imagesRoutes.length > 0"
+ [imageSrc]="imagesRoutes[imagesIndex]"
+ [canvasWidth]="canvasWidth"
+ [canvasHeight]="canvasHeight"
+ >
+ </sp-image-container>
+ </div>
+ <div
+ [ngStyle]="{ width: '100%', height: imagePreviewHeight + 'px' }"
+ fxLayout="row"
+ >
<sp-image-bar
- style="width: 100%"
+ fxFlex="100"
[imagesRoutes]="imagesRoutes"
[selectedIndex]="imagesIndex"
[enableShortCuts]="true"
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html
b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html
index 519fd70ebd..b492ab54e0 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html
+++
b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.html
@@ -16,28 +16,21 @@
~
-->
-<div
- fxFlex="100"
- fxLayoutAlign="center center"
- fxLayout="column"
- class="main-panel"
->
+<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column">
<sp-no-data-in-date-range
*ngIf="showNoDataInDateRange"
[viewDateRange]="timeSettings"
></sp-no-data-in-date-range>
- <div class="widget-inner-content">
- <sp-image-viewer
- *ngIf="imagePaths.length > 0"
- [imagesRoutes]="imagePaths"
- [canvasHeight]="canvasHeight"
- [canvasWidth]="canvasWidth"
- [imagePreviewHeight]="imagePreviewHeight"
- [ngStyle]="{
- width: canvasWidth + 'px',
- height: canvasHeight + 'px'
- }"
- ></sp-image-viewer>
- </div>
+ <sp-image-viewer
+ *ngIf="imagePaths.length > 0"
+ [imagesRoutes]="imagePaths"
+ [canvasHeight]="canvasHeight"
+ [canvasWidth]="canvasWidth"
+ [imagePreviewHeight]="imagePreviewHeight"
+ [ngStyle]="{
+ width: '100%',
+ height: '100%'
+ }"
+ ></sp-image-viewer>
</div>
diff --git
a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.ts
b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.ts
index 4d8d7dc83c..c14cb303de 100644
---
a/ui/src/app/data-explorer/components/widgets/image/image-widget.component.ts
+++
b/ui/src/app/data-explorer/components/widgets/image/image-widget.component.ts
@@ -21,9 +21,6 @@ import { MatSort } from '@angular/material/sort';
import { BaseDataExplorerWidgetDirective } from
'../base/base-data-explorer-widget.directive';
import {
DataExplorerField,
- DatalakeQueryParameterBuilder,
- DatalakeQueryParameters,
- EventPropertyUnion,
SpQueryResult,
} from '@streampipes/platform-services';
import { ImageWidgetModel } from './model/image-widget.model';
@@ -43,9 +40,6 @@ export class ImageWidgetComponent
imageBaseUrl: string;
imagePaths = [];
- availableColumns: EventPropertyUnion[];
- selectedColumn: EventPropertyUnion;
-
canvasHeight;
canvasWidth;
imagePreviewHeight;
@@ -58,24 +52,17 @@ export class ImageWidgetComponent
super.ngOnInit();
this.onResize(
this.gridsterItemComponent.width,
- this.gridsterItemComponent.height - 40,
+ this.gridsterItemComponent.height - 53,
);
this.imageBaseUrl = this.dataLakeRestService.dataLakeUrl + '/images/';
}
refreshView() {}
- buildQuery(): DatalakeQueryParameters {
- return DatalakeQueryParameterBuilder.create(
- this.timeSettings.startTime,
- this.timeSettings.endTime,
- ).build();
- }
-
onResize(width: number, height: number) {
- this.canvasHeight = height - 50;
- this.canvasWidth = width - 20;
- this.imagePreviewHeight = width / 14;
+ this.canvasHeight = height * 0.8;
+ this.canvasWidth = width;
+ this.imagePreviewHeight = height * 0.2;
}
beforeDataFetched() {
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts
b/ui/src/app/data-explorer/data-explorer.module.ts
index aa0b3823b9..6d31754b25 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -112,6 +112,7 @@ import { MatDividerModule } from
'@angular/material/divider';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
+import { SpImageContainerComponent } from
'./components/widgets/image/image-container/image-container.component';
@NgModule({
imports: [
@@ -225,6 +226,7 @@ import { MatButtonToggleModule } from
'@angular/material/button-toggle';
SpValueHeatmapWidgetConfigComponent,
SpHistogramChartWidgetConfigComponent,
SpPieChartWidgetConfigComponent,
+ SpImageContainerComponent,
SpInvalidConfigurationComponent,
SpConfigurationBoxComponent,
SpVisualizationConfigOuterComponent,