You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/04/07 19:36:22 UTC
[incubator-streampipes] branch dev updated: [STREAMPIPES-528] Improve support for images in data explorer
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/incubator-streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new d26d88ecd [STREAMPIPES-528] Improve support for images in data explorer
d26d88ecd is described below
commit d26d88ecd79c92cecf0ed8772c958850fe722904
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Thu Apr 7 21:36:13 2022 +0200
[STREAMPIPES-528] Improve support for images in data explorer
---
ui/src/app/core-ui/core-ui.module.ts | 212 ++++++++--------
.../image-bar-preview.component.html} | 2 +
.../image-bar-preview.component.scss} | 12 +-
.../image-bar-preview.component.ts} | 38 +--
.../components/image-bar/image-bar.component.css | 7 -
.../components/image-bar/image-bar.component.html | 58 +++--
.../image-container/image-container.component.html | 2 +-
.../image-container/image-container.component.ts | 278 ++-------------------
.../image-labeling/image-labeling.component.ts | 4 +-
.../image/image-viewer/image-viewer.component.html | 2 +-
.../image/image-viewer/image-viewer.component.ts | 11 +-
...-explorer-visualisation-settings.component.html | 5 +
.../config/image-widget-config.component.html | 10 +
.../image/config/image-widget-config.component.ts | 13 +-
.../widgets/image/image-widget.component.html | 21 +-
.../widgets/image/image-widget.component.ts | 78 +++---
16 files changed, 284 insertions(+), 469 deletions(-)
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index 94f3a00ba..aed2bfa03 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -84,114 +84,114 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { StaticRuntimeResolvableTreeInputComponent } from './static-properties/static-runtime-resolvable-tree-input/static-tree-input.component';
import { MatTreeModule } from '@angular/material/tree';
import { PlatformServicesModule } from '@streampipes/platform-services';
-import { BarchartWidgetComponent } from '../pipeline-details/components/monitoring/widget/barchart/barchart-widget.component';
-import { StatusWidgetComponent } from '../pipeline-details/components/monitoring/widget/status/status-widget.component';
+import { ImageBarPreviewComponent } from './image/components/image-bar/image-bar-preview/image-bar-preview.component';
@NgModule({
- imports: [
- CommonModule,
- ColorPickerModule,
- FlexLayoutModule,
- CodemirrorModule,
- CustomMaterialModule,
- ReactiveFormsModule,
- FormsModule,
- CdkTableModule,
- MatAutocompleteModule,
- MatSnackBarModule,
- MatProgressSpinnerModule,
- MatDatepickerModule,
- MatNativeDateModule,
- NgxChartsModule,
- PlotlyViaWindowModule,
- MatSliderModule,
- MatSlideToggleModule,
- MatChipsModule,
- MatTreeModule,
- PlatformServicesModule,
- PortalModule,
- OverlayModule,
- QuillModule.forRoot(),
- MatTreeModule
- ],
- declarations: [
- ConfigureLabelsComponent,
- ConfirmDialogComponent,
- DisplayRecommendedPipe,
- ImageComponent,
- ImageContainerComponent,
- ImageLabelingComponent,
- SelectLabelComponent,
- ImageBarComponent,
- ImageAnnotationsComponent,
- ImageViewerComponent,
- ObjectPermissionDialogComponent,
- StandardDialogComponent,
- PanelDialogComponent,
- SplitSectionComponent,
- StaticAnyInput,
- StaticPropertyComponent,
- StaticFreeInputComponent,
- StaticSecretInputComponent,
- StaticFileInputComponent,
- StaticMappingNaryComponent,
- StaticMappingUnaryComponent,
- StaticGroupComponent,
- StaticAlternativesComponent,
- StaticCollectionComponent,
- StaticColorPickerComponent,
- StaticCodeInputComponent,
- StaticOneOfInputComponent,
- StaticRuntimeResolvableAnyInputComponent,
- StaticRuntimeResolvableOneOfInputComponent,
- StaticRuntimeResolvableTreeInputComponent,
- StaticSlideToggleComponent,
- LabelListItemComponent,
- ErrorHintComponent,
- AddToCollectionComponent,
- PipelineStartedStatusComponent,
- ],
- providers: [
- MatDatepickerModule,
- ColorService,
- DisplayRecommendedPipe,
- ReactLabelingService,
- PolygonLabelingService,
- BrushLabelingService,
- CocoFormatService,
- LabelingModeService,
- DialogService,
- RuntimeResolvableService,
- ],
- exports: [
- ConfigureLabelsComponent,
- ImageComponent,
- ImageLabelingComponent,
- SelectLabelComponent,
- StandardDialogComponent,
- PanelDialogComponent,
- ConfirmDialogComponent,
- StaticAnyInput,
- StaticPropertyComponent,
- StaticFreeInputComponent,
- StaticSecretInputComponent,
- StaticFileInputComponent,
- StaticMappingNaryComponent,
- StaticMappingUnaryComponent,
- StaticGroupComponent,
- StaticAlternativesComponent,
- StaticCollectionComponent,
- StaticColorPickerComponent,
- StaticCodeInputComponent,
- StaticOneOfInputComponent,
- StaticRuntimeResolvableAnyInputComponent,
- StaticRuntimeResolvableOneOfInputComponent,
- StaticSlideToggleComponent,
- ImageViewerComponent,
- ErrorHintComponent,
- PipelineStartedStatusComponent,
- SplitSectionComponent,
- ]
+ imports: [
+ CommonModule,
+ ColorPickerModule,
+ FlexLayoutModule,
+ CodemirrorModule,
+ CustomMaterialModule,
+ ReactiveFormsModule,
+ FormsModule,
+ CdkTableModule,
+ MatAutocompleteModule,
+ MatSnackBarModule,
+ MatProgressSpinnerModule,
+ MatDatepickerModule,
+ MatNativeDateModule,
+ NgxChartsModule,
+ PlotlyViaWindowModule,
+ MatSliderModule,
+ MatSlideToggleModule,
+ MatChipsModule,
+ MatTreeModule,
+ PlatformServicesModule,
+ PortalModule,
+ OverlayModule,
+ QuillModule.forRoot(),
+ MatTreeModule
+ ],
+ declarations: [
+ ConfigureLabelsComponent,
+ ConfirmDialogComponent,
+ DisplayRecommendedPipe,
+ ImageBarPreviewComponent,
+ ImageComponent,
+ ImageContainerComponent,
+ ImageLabelingComponent,
+ SelectLabelComponent,
+ ImageBarComponent,
+ ImageAnnotationsComponent,
+ ImageViewerComponent,
+ ObjectPermissionDialogComponent,
+ StandardDialogComponent,
+ PanelDialogComponent,
+ SplitSectionComponent,
+ StaticAnyInput,
+ StaticPropertyComponent,
+ StaticFreeInputComponent,
+ StaticSecretInputComponent,
+ StaticFileInputComponent,
+ StaticMappingNaryComponent,
+ StaticMappingUnaryComponent,
+ StaticGroupComponent,
+ StaticAlternativesComponent,
+ StaticCollectionComponent,
+ StaticColorPickerComponent,
+ StaticCodeInputComponent,
+ StaticOneOfInputComponent,
+ StaticRuntimeResolvableAnyInputComponent,
+ StaticRuntimeResolvableOneOfInputComponent,
+ StaticRuntimeResolvableTreeInputComponent,
+ StaticSlideToggleComponent,
+ LabelListItemComponent,
+ ErrorHintComponent,
+ AddToCollectionComponent,
+ PipelineStartedStatusComponent,
+ ],
+ providers: [
+ MatDatepickerModule,
+ ColorService,
+ DisplayRecommendedPipe,
+ ReactLabelingService,
+ PolygonLabelingService,
+ BrushLabelingService,
+ CocoFormatService,
+ LabelingModeService,
+ DialogService,
+ RuntimeResolvableService,
+ ],
+ exports: [
+ ConfigureLabelsComponent,
+ ImageComponent,
+ ImageLabelingComponent,
+ SelectLabelComponent,
+ StandardDialogComponent,
+ PanelDialogComponent,
+ ConfirmDialogComponent,
+ StaticAnyInput,
+ StaticPropertyComponent,
+ StaticFreeInputComponent,
+ StaticSecretInputComponent,
+ StaticFileInputComponent,
+ StaticMappingNaryComponent,
+ StaticMappingUnaryComponent,
+ StaticGroupComponent,
+ StaticAlternativesComponent,
+ StaticCollectionComponent,
+ StaticColorPickerComponent,
+ StaticCodeInputComponent,
+ StaticOneOfInputComponent,
+ StaticRuntimeResolvableAnyInputComponent,
+ StaticRuntimeResolvableOneOfInputComponent,
+ StaticSlideToggleComponent,
+ ImageViewerComponent,
+ ErrorHintComponent,
+ PipelineStartedStatusComponent,
+ SplitSectionComponent,
+ ]
})
export class CoreUiModule {
}
diff --git a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.html
similarity index 85%
copy from ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html
copy to ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.html
index fb99b649e..0854d62a9 100644
--- a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.html
@@ -15,3 +15,5 @@
~ limitations under the License.
~
-->
+
+<img [ngClass]="focus ? 'imagePreview imageFocus' : 'imagePreview'" [style.height.px]="imagePreviewHeight" *ngIf="showImage" [src]="imagePath">
diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.scss
similarity index 88%
copy from ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
copy to ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.scss
index 54647dc83..aba112fec 100644
--- a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.scss
@@ -16,15 +16,13 @@
*
*/
-.imageBar {
- height: 70px;
- /*width: 640px;*/
-}
-
.imagePreview {
- /*height: 65px*/
+ height: 65px;
+ margin-left: 10px;
+ margin-right: 10px;
}
.imageFocus {
- border: 5px solid #39b54a
+ border: 3px solid #39b54a
}
+
diff --git a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.ts
similarity index 55%
copy from ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
copy to ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.ts
index 21bebcac6..b49e6d18d 100644
--- a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar-preview/image-bar-preview.component.ts
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -15,33 +15,35 @@
* limitations under the License.
*/
-import { Component, Input } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
+import { SafeUrl } from '@angular/platform-browser';
+import { Observable } from 'rxjs';
@Component({
- selector: 'sp-image-viewer',
- templateUrl: './image-viewer.component.html',
- styleUrls: ['./image-viewer.component.css']
+ selector: 'sp-image-bar-preview',
+ templateUrl: './image-bar-preview.component.html',
+ styleUrls: ['./image-bar-preview.component.scss']
})
-export class ImageViewerComponent {
+export class ImageBarPreviewComponent implements OnInit {
@Input()
- public imagesRoutes;
+ imagePreviewHeight: number;
@Input()
- public canvasHeight = 500;
+ focus = false;
- @Input()
- public canvasWidth = 800;
+ imagePath: SafeUrl;
+ showImage = false;
@Input()
- public imagePreviewHeight = 65;
-
-
- public imagesIndex = 0;
-
- constructor() {}
+ set imageSrc(src: Observable<SafeUrl>) {
+ src.subscribe(url => {
+ this.imagePath = url;
+ this.showImage = true;
+ });
+ }
- handleImageIndexChange(index) {
- this.imagesIndex = index;
+ ngOnInit(): void {
}
+
}
diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
index 54647dc83..7c49dc0e7 100644
--- a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
@@ -21,10 +21,3 @@
/*width: 640px;*/
}
-.imagePreview {
- /*height: 65px*/
-}
-
-.imageFocus {
- border: 5px solid #39b54a
-}
diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
index 911e62a68..271f70a59 100644
--- a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
@@ -22,25 +22,45 @@
<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">-->
-<!-- <img class="imagePreview" [style.height.px]="imagePreviewHeight" *ngIf="selectedIndex >= 2" src="{{this.restService.getImageUrl(_imageRoutes[selectedIndex - 2])}}" (click)="changeImage(selectedIndex - 2)">-->
-<!-- <img class="imagePreview" [style.height.px]="imagePreviewHeight" *ngIf="selectedIndex >= 1" src="{{this.restService.getImageUrl(_imageRoutes[selectedIndex - 1])}}" (click)="changeImage(selectedIndex - 1)">-->
-<!-- </div>-->
-
-<!-- <div fxFlex="20">-->
-<!-- <div fxLayout="row" fxLayoutAlign="center">-->
-<!-- <img class="imagePreview imageFocus" [style.height.px]="imagePreviewHeight" src="{{this.restService.getImageUrl(_imageRoutes[selectedIndex])}}" (click)="changeImage(selectedIndex)">-->
-<!-- </div>-->
-<!-- </div>-->
-
-<!-- <div fxFlex="40">-->
-<!-- <div fxLayout="row" fxLayoutAlign="start center">-->
-<!-- <img class="imagePreview" [style.height.px]="imagePreviewHeight" *ngIf="selectedIndex < maxImages - 1" src="{{this.restService.getImageUrl(_imageRoutes[selectedIndex + 1])}}" (click)="changeImage(selectedIndex + 1)">-->
-<!-- <img class="imagePreview" [style.height.px]="imagePreviewHeight" *ngIf="selectedIndex < maxImages - 2" src="{{this.restService.getImageUrl(_imageRoutes[selectedIndex + 2])}}" (click)="changeImage(selectedIndex + 2)">-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </div>-->
+ <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>
<button mat-icon-button (click)="previousImage()"> <mat-icon>keyboard_arrow_right</mat-icon></button>
diff --git a/ui/src/app/core-ui/image/components/image-container/image-container.component.html b/ui/src/app/core-ui/image/components/image-container/image-container.component.html
index 0d9541524..5c8a1284f 100644
--- a/ui/src/app/core-ui/image/components/image-container/image-container.component.html
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.html
@@ -17,5 +17,5 @@
-->
<div class="canvas-container">
<mat-spinner *ngIf="isDrawingVar" [diameter]="40" style="position: fixed"></mat-spinner>
- <div id="canvas-container" (dblclick)="dblclick($event)"></div>
+ <img [src]="imagePath" #mainImg *ngIf="showImage" [width]="canvasWidth" (load)="onImageLoaded()"/>
</div>
diff --git a/ui/src/app/core-ui/image/components/image-container/image-container.component.ts b/ui/src/app/core-ui/image/components/image-container/image-container.component.ts
index 6bbb8d50f..68f2c094b 100644
--- a/ui/src/app/core-ui/image/components/image-container/image-container.component.ts
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.ts
@@ -15,290 +15,52 @@
* limitations under the License.
*/
-import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core';
-import Konva from 'konva';
-import { ICoordinates } from '../../model/coordinates';
+import { Component, ElementRef, Input, OnInit, 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.css']
})
-export class ImageContainerComponent implements OnInit, AfterViewInit {
+export class ImageContainerComponent implements OnInit {
+
+ imagePath: SafeUrl;
+ showImage = false;
@Input()
- set imageSrc(src) {
- this.loadImage(src);
+ set imageSrc(src: Observable<Blob>) {
+ src.subscribe(url => {
+ this.imagePath = url;
+ this.showImage = true;
+ });
}
+ @ViewChild('mainImg') imageRef: ElementRef;
+
@Input()
public canvasHeight = 500;
@Input()
public canvasWidth = 800;
- @Output()
- childRedraw: EventEmitter<[Konva.Layer, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates]>();
- @Output()
- mouseDownLeft: EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- mouseMove: EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- mouseMoveLeft: EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- mouseUpLeft: EventEmitter<[Konva.Layer, Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- shortCut: EventEmitter<string> = new EventEmitter<string>();
- @Output()
- dbclick: EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- mouseDownRight: EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]> = new EventEmitter<[Konva.Layer, ICoordinates, ICoordinates]>();
- @Output()
- isDrawing: EventEmitter<boolean> = new EventEmitter<boolean>();
-
-
- private image;
-
- private mainCanvasStage: Konva.Stage;
- private imageLayer: Konva.Layer;
- private annotationLayer: Konva.Layer;
- private drawLayer: Konva.Layer;
-
private scale: number;
- private imageShift: ICoordinates;
- private lastImageTranslation: ICoordinates;
- private lastImagePointerPosition: ICoordinates;
-
- private isLeftMouseDown: boolean;
- private isMiddleMouseDown: boolean;
- private isRightMouseDown: boolean;
-
- private isHoverComponent: boolean;
public isDrawingVar: boolean;
- constructor() { }
-
- ngOnInit(): void {
- this.scale = 1;
- this.imageShift = {x: 0, y: 0};
- this.isLeftMouseDown = false;
- this.isMiddleMouseDown = false;
- this.isRightMouseDown = false;
- this.isHoverComponent = false;
- this.isDrawingVar = false;
- }
-
- ngAfterViewInit(): void {
- this.reset();
+ constructor() {
}
- reset() {
+ ngOnInit(): void {
this.scale = 1;
- this.imageShift = {x: 0, y: 0};
- // TODO fit to parent
- this.mainCanvasStage = new Konva.Stage({
- container: 'canvas-container',
- width: this.canvasWidth,
- height: this.canvasHeight
- });
- this.registerEventHandler();
- window.addEventListener('resize', this.fitStageIntoParentContainer);
-
- }
-
- fitStageIntoParentContainer() {
- this.mainCanvasStage.width(500);
- this.mainCanvasStage.height(500 * this.scale);
- this.mainCanvasStage.scale({ x: this.scale, y: this.scale });
- this.mainCanvasStage.draw();
- }
-
- loadImage(src) {
- this.isDrawing.emit(true);
- this.isDrawingVar = true;
- this.reset();
- this.image = new window.Image();
-
- this.image.onload = () => {
- this.scale = Math.min(1, this.mainCanvasStage.width() / this.image.width, this.mainCanvasStage.height() / this.image.height);
- this.initLayers();
- this.redrawAll();
- };
- // this.image.src = this.restService.getImageUrl(src);
- }
-
- getShift() {
- if (this.imageLayer !== undefined) {
- const position = this.imageLayer.getChildren().toArray()[0].getPosition();
- return {x: position.x, y: position.y};
- }
- }
- /* mouse handler */
-
- imageMouseDown(e) {
- const button = e.evt.which;
- if (button === 1) {
- // left click
- this.isLeftMouseDown = true;
- this.mouseDownLeft.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
- this.drawLayer.batchDraw();
- } else if (button === 2) {
- // middle click
- this.isMiddleMouseDown = true;
- this.mainCanvasStage.container().style.cursor = 'move';
- this.lastImagePointerPosition = this.getImagePointerPosition();
- this.lastImageTranslation = this.imageShift;
- } else if (button === 3) {
- // right click
- this.isRightMouseDown = true;
- this.mouseDownRight.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
- }
- }
-
- imageMouseMove(e) {
- if (this.isLeftMouseDown) {
- this.drawLayer.destroyChildren();
- this.mouseMoveLeft.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
- this.drawLayer.batchDraw();
- } else if (this.isMiddleMouseDown) {
- const imagePointerPosition = this.getImagePointerPosition();
- this.imageShift.x = this.lastImageTranslation.x + (imagePointerPosition.x - this.lastImagePointerPosition.x);
- this.imageShift.y = this.lastImageTranslation.y + (imagePointerPosition.y - this.lastImagePointerPosition.y);
- this.lastImagePointerPosition = this.getImagePointerPosition();
- this.lastImageTranslation = this.imageShift;
- this.shiftViewContent();
- } else {
- if (this.drawLayer !== undefined) { this.drawLayer.destroyChildren(); }
- this.mouseMove.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
- if (this.drawLayer !== undefined) { this.drawLayer.destroyChildren(); }
- }
}
- imageMouseUp(e) {
- if (this.isLeftMouseDown) {
- this.isLeftMouseDown = false;
- this.drawLayer.destroyChildren();
- this.mouseUpLeft.emit([this.annotationLayer, this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
- this.drawLayer.batchDraw();
- this.annotationLayer.batchDraw();
- }
- if (this.isMiddleMouseDown) {
- this.isMiddleMouseDown = false;
- this.mainCanvasStage.container().style.cursor = 'default';
- }
+ onImageLoaded() {
+ const naturalImgWidth = (this.imageRef.nativeElement as HTMLImageElement).naturalWidth;
+ const naturalImageHeight = (this.imageRef.nativeElement as HTMLImageElement).naturalHeight;
+ this.scale = Math.min(1, this.canvasWidth / naturalImgWidth, this.canvasHeight / naturalImageHeight);
}
- dblclick (e) {
- this.drawLayer.destroyChildren();
- this.drawLayer.batchDraw();
- this.dbclick.emit([this.annotationLayer, this.getShift(), this.getImagePointerPosition()]);
- this.annotationLayer.batchDraw();
- }
-
- /* Draw */
-
- redrawAll() {
- this.isDrawing.emit(true);
- this.isDrawingVar = true;
-
- if (this.drawLayer !== undefined) {
- this.drawLayer.destroyChildren();
- }
- if (this.annotationLayer !== undefined) {
- this.annotationLayer.destroyChildren();
- }
- this.childRedraw.emit([this.annotationLayer, this.getShift()]);
- this.shiftViewContent();
- this.isDrawing.emit(false);
- this.isDrawingVar = false;
- }
-
- shiftViewContent() {
- const newWidth = this.mainCanvasStage.width() * this.scale;
- const newHeight = this.mainCanvasStage.height() * this.scale;
-
- this.mainCanvasStage.position({
- x: -((newWidth - this.mainCanvasStage.width()) / 2) + this.imageShift.x,
- y: -((newHeight - this.mainCanvasStage.height()) / 2) + this.imageShift.y
- });
- this.mainCanvasStage.scale({ x: this.scale, y: this.scale });
-
- this.mainCanvasStage.batchDraw();
- }
-
- initLayers() {
- this.imageLayer = new Konva.Layer();
- const konvaImage = new Konva.Image({
- image: this.image,
- x: this.mainCanvasStage.width() / 2 - this.image.width / 2,
- y: this.mainCanvasStage.height() / 2 - this.image.height / 2,
- });
- this.imageLayer.add(konvaImage);
- this.imageLayer.clearBeforeDraw();
-
- this.annotationLayer = new Konva.Layer();
- this.drawLayer = new Konva.Layer();
-
- this.mainCanvasStage.add(this.imageLayer);
- this.mainCanvasStage.add(this.annotationLayer);
- this.mainCanvasStage.add(this.drawLayer);
- }
-
- @HostListener('document:keydown', ['$event'])
- handleShortCuts(e) {
- const key = e.key;
- this.shortCut.emit(key.toLowerCase());
- if (this.isHoverComponent) {
- switch (key.toLowerCase()) {
- case 'w': this.imageShift.y -= 5; this.redrawAll();
- break;
- case 'a': this.imageShift.x -= 5; this.redrawAll();
- break;
- case 's': this.imageShift.y += 5; this.redrawAll();
- break;
- case 'd': this.imageShift.x += 5; this.redrawAll();
- break;
- }
- }
- }
-
- getPointerPosition(): ICoordinates {
- return this.mainCanvasStage.getPointerPosition();
- }
-
- getImagePointerPosition(): ICoordinates {
- const x = Math.floor((this.getPointerPosition().x / this.scale) -
- ((this.mainCanvasStage.width() / this.scale - this.image.width) / 2) - (this.imageShift.x / this.scale));
- const y = Math.floor((this.getPointerPosition().y / this.scale) -
- ((this.mainCanvasStage.height() / this.scale - this.image.height) / 2) - (this.imageShift.y / this.scale));
- return {x, y};
- }
-
- getImagePositionFromPosition(posistion: ICoordinates): ICoordinates {
- const x = Math.floor((posistion.x / this.scale) -
- ((this.mainCanvasStage.width() / this.scale - this.image.width) / 2) - (this.imageShift.x / this.scale));
- const y = Math.floor((posistion.y / this.scale) -
- ((this.mainCanvasStage.height() / this.scale - this.image.height) / 2) - (this.imageShift.y / this.scale));
- return {x, y};
- }
-
- registerEventHandler() {
- this.mainCanvasStage.on('wheel', e => this.scroll(e));
- this.mainCanvasStage.on('contextmenu', e => e.evt.preventDefault());
- this.mainCanvasStage.on('mousedown', e => this.imageMouseDown(e));
- this.mainCanvasStage.on('mousemove', e => this.imageMouseMove(e));
- this.mainCanvasStage.on('mouseup', e => this.imageMouseUp(e));
- this.mainCanvasStage.on('mouseover', e => this.isHoverComponent = true);
- this.mainCanvasStage.on('mouseout', e => this.isHoverComponent = false);
- this.mainCanvasStage.on('dblclick', e => this.dblclick(e));
- this.mainCanvasStage.on('dbclick', e => this.dblclick(e));
- }
-
- scroll(e) {
- e.evt.preventDefault();
- this.scale += e.evt.wheelDeltaY * (1 / 6000);
- this.redrawAll();
- }
}
diff --git a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
index c0da32014..3b6ca8867 100644
--- a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
@@ -228,7 +228,7 @@ export class ImageLabelingComponent implements OnInit {
const categoryId = this.cocoFormatService.getLabelId(coco, change[0].category_id, change[1].name, change[1].name);
change[0].category_id = categoryId;
change[0].category_name = change[1].categoryId;
- this.imageView.redrawAll();
+ //this.imageView.redrawAll();
}
}
@@ -237,7 +237,7 @@ export class ImageLabelingComponent implements OnInit {
if (annotation !== undefined) {
const coco = this.cocoFile;
this.cocoFormatService.removeAnnotation(coco, annotation.id);
- this.imageView.redrawAll();
+ //this.imageView.redrawAll();
}
}
}
diff --git a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
index 399b165b9..e9605a78b 100644
--- a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
+++ b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
@@ -16,7 +16,7 @@
~
-->
-<div>
+<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 " >
diff --git a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
index 21bebcac6..1b462de0e 100644
--- a/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
+++ b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
@@ -15,17 +15,19 @@
* limitations under the License.
*/
-import { Component, Input } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
+import { SafeUrl } from '@angular/platform-browser';
+import { Observable } from 'rxjs';
@Component({
selector: 'sp-image-viewer',
templateUrl: './image-viewer.component.html',
styleUrls: ['./image-viewer.component.css']
})
-export class ImageViewerComponent {
+export class ImageViewerComponent implements OnInit {
@Input()
- public imagesRoutes;
+ public imagesRoutes: Observable<SafeUrl>[];
@Input()
public canvasHeight = 500;
@@ -44,4 +46,7 @@ export class ImageViewerComponent {
handleImageIndexChange(index) {
this.imagesIndex = index;
}
+
+ ngOnInit(): void {
+ }
}
diff --git a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
index b526c1368..f9209ab25 100644
--- a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
@@ -68,5 +68,10 @@
[currentlyConfiguredWidget]="currentlyConfiguredWidget">
</sp-data-explorer-distribution-chart-widget-config>
</div>
+ <div *ngIf="currentlyConfiguredWidget.widgetType === 'image'" class="h-100 p-0">
+ <sp-data-explorer-image-widget-config
+ [currentlyConfiguredWidget]="currentlyConfiguredWidget">
+ </sp-data-explorer-image-widget-config>
+ </div>
</div>
</div>
diff --git a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html
index fb99b649e..1576c2b55 100644
--- a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html
+++ b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.html
@@ -15,3 +15,13 @@
~ limitations under the License.
~
-->
+
+<div fxFlex="100" fxLayout="column">
+
+ <h5>Image Field</h5>
+ <sp-select-property [availableProperties]="imageFields"
+ [selectedProperty]="currentlyConfiguredWidget.visualizationConfig.selectedField"
+ (changeSelectedProperty)="setSelectedImageProperty($event)">
+ </sp-select-property>
+
+</div>
diff --git a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts
index 3a5062cb5..19f55efaa 100644
--- a/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/image/config/image-widget-config.component.ts
@@ -20,6 +20,7 @@ import { Component, OnInit } from '@angular/core';
import { BaseWidgetConfig } from '../../base/base-widget-config';
import { ImageWidgetModel, ImageWidgetVisConfig } from '../model/image-widget.model';
import { WidgetType } from '../../../../registry/data-explorer-widgets';
+import { DataExplorerField } from "../../../../../../../dist/streampipes/platform-services";
@Component({
selector: 'sp-data-explorer-image-widget-config',
@@ -28,6 +29,9 @@ import { WidgetType } from '../../../../registry/data-explorer-widgets';
})
export class ImageWidgetConfigComponent extends BaseWidgetConfig<ImageWidgetModel, ImageWidgetVisConfig> implements OnInit {
+ imageSemanticType = 'https://image.com';
+ imageFields: DataExplorerField[];
+
ngOnInit(): void {
}
@@ -36,10 +40,17 @@ export class ImageWidgetConfigComponent extends BaseWidgetConfig<ImageWidgetMode
}
protected initWidgetConfig(): ImageWidgetVisConfig {
+ this.imageFields = this.fieldProvider.allFields
+ .filter(field => field.fieldCharacteristics.semanticTypes.find(st => st === this.imageSemanticType));
return {
forType: this.getWidgetType(),
- selectedField: this.fieldProvider.allFields[0]
+ selectedField: this.imageFields[0]
};
}
+ setSelectedImageProperty(field: DataExplorerField) {
+ this.currentlyConfiguredWidget.visualizationConfig.selectedField = field;
+ this.triggerDataRefresh();
+ }
+
}
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 f168e4d86..15772772b 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
@@ -17,23 +17,20 @@
-->
-<div class="widget-content">
- <div class="widget-inner-options ml-0 mr-0 mt-0">
- <div fxFlex="100" fxLayout="row">
- <div fxFlex="100" fxLayout="row" fxLayoutAlign="start center" class="ml-0 mr-0">
- <sp-select-properties [availableProperties]="availableColumns" [selectedProperties]="selectedColumn"></sp-select-properties>
- </div>
- </div>
- </div>
+<div fxFlex="100" fxLayoutAlign="center center" fxLayout="column" class="main-panel">
+
+ <sp-load-data-spinner *ngIf="showIsLoadingData" class="h-100"></sp-load-data-spinner>
+
+ <sp-no-data-in-date-range *ngIf="showNoDataInDateRange" [viewDateRange]="timeSettings"></sp-no-data-in-date-range>
+
<div class="widget-inner-content">
- <sp-load-data-spinner *ngIf="showIsLoadingData"></sp-load-data-spinner>
- <sp-no-data-in-date-range *ngIf="imagesRoutes.length === 0" [viewDateRange]="viewDateRange"></sp-no-data-in-date-range>
- <sp-image-viewer *ngIf="imagesRoutes.length > 0"
- [imagesRoutes]="imagesRoutes"
+ <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>
</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 eda1600dc..6b3f0ec44 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
@@ -23,11 +23,17 @@ import {
DataExplorerField,
DatalakeQueryParameterBuilder,
DatalakeQueryParameters,
+ DatalakeRestService,
+ DataViewQueryGeneratorService,
EventPropertyUnion,
- EventSchema,
SpQueryResult
} from '@streampipes/platform-services';
import { ImageWidgetModel } from './model/image-widget.model';
+import { WidgetConfigurationService } from '../../../services/widget-configuration.service';
+import { ResizeService } from '../../../services/resize.service';
+import { DataExplorerFieldProviderService } from '../../../services/data-explorer-field-provider-service';
+import { TimeSelectionService } from '../../../services/time-selection.service';
+import { SecurePipe } from '../../../../services/secure.pipe';
@Component({
selector: 'sp-data-explorer-image-widget',
@@ -36,7 +42,10 @@ import { ImageWidgetModel } from './model/image-widget.model';
})
export class ImageWidgetComponent extends BaseDataExplorerWidgetDirective<ImageWidgetModel> implements OnInit, OnDestroy {
- @ViewChild(MatSort, { static: true }) sort: MatSort;
+ @ViewChild(MatSort, {static: true}) sort: MatSort;
+
+ imageBaseUrl: string;
+ imagePaths = [];
availableColumns: EventPropertyUnion[];
selectedColumn: EventPropertyUnion;
@@ -45,46 +54,33 @@ export class ImageWidgetComponent extends BaseDataExplorerWidgetDirective<ImageW
canvasWidth;
imagePreviewHeight;
- public imagesRoutes = [];
-
- ngOnInit(): void {
- this.canvasHeight = this.gridsterItemComponent.height - 240;
- this.canvasWidth = this.gridsterItemComponent.width - 20;
- this.imagePreviewHeight = this.gridsterItemComponent.width / 14;
-
- this.availableColumns = this.getImageProperties(this.dataExplorerWidget.dataConfig.sourceConfigs[0].measure.eventSchema);
- this.selectedColumn = this.availableColumns[0];
- this.updateData();
+ constructor(dataLakeRestService: DatalakeRestService,
+ widgetConfigurationService: WidgetConfigurationService,
+ resizeService: ResizeService,
+ dataViewQueryGeneratorService: DataViewQueryGeneratorService,
+ fieldService: DataExplorerFieldProviderService,
+ timeSelectionService: TimeSelectionService,
+ private securePipe: SecurePipe) {
+ super(
+ dataLakeRestService,
+ widgetConfigurationService,
+ resizeService,
+ dataViewQueryGeneratorService,
+ fieldService,
+ timeSelectionService
+ );
}
- getImageProperties(eventSchema: EventSchema): EventPropertyUnion[] {
- return eventSchema.eventProperties.filter(ep => ep.domainProperties.some(dp => dp === 'https://image.com'));
+ ngOnInit(): void {
+ super.ngOnInit();
+ this.onResize(this.gridsterItemComponent.width, this.gridsterItemComponent.height - 40);
+ this.imageBaseUrl = this.dataLakeRestService.dataLakeUrl + '/images/';
}
ngOnDestroy(): void {
}
- refreshData() {
- this.setShownComponents(false, false, true);
-
- this.dataLakeRestService.getData(
- this.dataExplorerWidget.dataConfig.sourceConfigs[0].measureName, this.buildQuery())
- .subscribe(
- (res: SpQueryResult) => {
- // this.availableImageData = res;
- this.showIsLoadingData = false;
- this.imagesRoutes = [];
- if (res.allDataSeries[0].rows !== null) {
- const imageField = res.headers.findIndex(name => name === this.selectedColumn.runtimeName);
- res.allDataSeries[0].rows.forEach(row => {
- this.imagesRoutes.push(row[imageField]);
- });
- }
- }
- );
- }
-
refreshView() {
}
@@ -93,12 +89,26 @@ export class ImageWidgetComponent extends BaseDataExplorerWidgetDirective<ImageW
}
onResize(width: number, height: number) {
+ this.canvasHeight = height - 50;
+ this.canvasWidth = width - 20;
+ this.imagePreviewHeight = width / 14;
}
beforeDataFetched() {
+ this.setShownComponents(false, false, true, false);
}
onDataReceived(spQueryResult: SpQueryResult[]) {
+ const selectedField = this.dataExplorerWidget.visualizationConfig.selectedField;
+ if (spQueryResult.length > 0) {
+ const qr = spQueryResult[selectedField.sourceIndex];
+ const columnIndex = qr.headers.indexOf(selectedField.runtimeName);
+ this.imagePaths = qr.allDataSeries[0].rows
+ .map(row => row[columnIndex])
+ .map(imageId => this.imageBaseUrl + imageId)
+ .map(imageRoute => this.securePipe.transform(imageRoute));
+ }
+ this.setShownComponents(false, true, false, false);
}
handleUpdatedFields(addedFields: DataExplorerField[], removedFields: DataExplorerField[]) {