You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by te...@apache.org on 2020/05/14 14:26:44 UTC

[incubator-streampipes] 01/02: - create image labeling app - improve image labeling tool usability - label can be drawn on top of an existing label

This is an automated email from the ASF dual-hosted git repository.

tex pushed a commit to branch STREAMPIPES-79
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit eaf736d0966847fd59caa9fe822dbc33285644f9
Author: tex <te...@fzi.de>
AuthorDate: Thu May 14 16:23:45 2020 +0200

    - create image labeling app
    - improve image labeling tool usability
    - label can be drawn on top of an existing label
---
 .../app-image-labeling.component.css}              |   8 +-
 .../app-image-labeling.component.html              |  35 ++++++
 .../app-image-labeling.component.ts                |  54 ++++++++
 .../app-image-labeling.module.ts}                  |  32 ++++-
 .../app/app-overview/app-overview.component.html   |   2 +
 ui/src/app/app-overview/app-overview.component.ts  |  21 ++--
 ui/src/app/app-overview/app-overview.module.ts     |  26 ++--
 .../datalake/datalake-rest.service.ts              |   6 +-
 ui/src/app/core-ui/core-ui.module.ts               |   2 +
 .../image-annotations.component.html               |  12 +-
 .../components/image-bar/image-bar.component.css   |   1 +
 .../image-container/image-container.component.css  |   3 +-
 .../image-container/image-container.component.ts   |  34 ++++--
 .../image-categorize.component.html                |   2 +-
 .../image-labeling/image-labeling.component.html   |  24 ++--
 .../image-labeling/image-labeling.component.ts     | 136 +++++++++++----------
 .../image/image-viewer/image-viewer.component.html |   2 +-
 .../image/services/BrushLabeling.service.ts        |  50 ++++----
 .../core-ui/image/services/LabelingMode.service.ts |  79 ++++++++++++
 .../image/services/PolygonLabeling.service.ts      |  85 +++++++------
 .../image/services/ReactLabeling.service.ts        |  65 ++++++----
 21 files changed, 473 insertions(+), 206 deletions(-)

diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css b/ui/src/app/app-image-labeling/app-image-labeling.component.css
similarity index 89%
copy from ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
copy to ui/src/app/app-image-labeling/app-image-labeling.component.css
index a4868af..e9af737 100644
--- a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
+++ b/ui/src/app/app-image-labeling/app-image-labeling.component.css
@@ -16,6 +16,10 @@
  *
  */
 
-.imageBar {
-    height: 70px;
+.page-container-padding {
+    width:100%;
+}
+
+.page-container-padding-inner {
+    padding: 10px;
 }
\ No newline at end of file
diff --git a/ui/src/app/app-image-labeling/app-image-labeling.component.html b/ui/src/app/app-image-labeling/app-image-labeling.component.html
new file mode 100644
index 0000000..818003e
--- /dev/null
+++ b/ui/src/app/app-image-labeling/app-image-labeling.component.html
@@ -0,0 +1,35 @@
+<!--
+  ~ 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.
+  -->
+
+<div fxLayout="column" fxFlex="100" class="page-container-connect">
+    <div fxLayout="row" style="padding:0px;background-color:#f6f6f6;">
+        <div fxLayout="fill" style="line-height:24px;border-bottom:1px solid #ccc">
+            <mat-form-field style="margin-top: 5px; margin-left: 5px;">
+                <mat-label>Select data lake measurement</mat-label>
+                <mat-select [(value)]="selectedMeasure">
+                    <mat-option *ngFor="let measure of dataLakeMeasures" [value]="measure">
+                        {{measure.measureName}}
+                    </mat-option>
+                </mat-select>
+            </mat-form-field>
+        </div>
+    </div>
+
+    <div class="fixed-height page-container-padding-inner" fxLayout="column" fxFlex="100">
+        <sp-image-labeling [measureName]="selectedMeasure?.measureName" [eventSchema]="selectedMeasure?.eventSchema"></sp-image-labeling>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/app-image-labeling/app-image-labeling.component.ts b/ui/src/app/app-image-labeling/app-image-labeling.component.ts
new file mode 100644
index 0000000..f6c923c
--- /dev/null
+++ b/ui/src/app/app-image-labeling/app-image-labeling.component.ts
@@ -0,0 +1,54 @@
+/*
+ * 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, EventEmitter, OnInit, Output } from '@angular/core';
+import { DatalakeRestService } from "../core-services/datalake/datalake-rest.service";
+import { TsonLdSerializerService } from "../platform-services/tsonld-serializer.service";
+import { DataLakeMeasure } from "../core-model/datalake/DataLakeMeasure";
+
+@Component({
+    selector: 'app-image-labeling',
+    templateUrl: './app-image-labeling.component.html',
+    styleUrls: ['./app-image-labeling.component.css']
+})
+export class AppImageLabelingComponent implements  OnInit {
+
+
+  dataLakeMeasures: DataLakeMeasure[] = [];
+  selectedMeasure: DataLakeMeasure;
+
+  @Output() appOpened = new EventEmitter<boolean>();
+
+  constructor(private restService: DatalakeRestService,
+              private tsonLdSerializerService: TsonLdSerializerService) {
+
+  }
+
+  ngOnInit() {
+      this.appOpened.emit(true);
+        this.restService.getAllInfos().map(data => {
+          return this.tsonLdSerializerService.fromJsonLdContainer(data, 'sp:DataLakeMeasure');
+        }).subscribe(
+          res => {
+              this.dataLakeMeasures = res;
+              this.selectedMeasure = res[0];
+          }
+        );
+  }
+
+
+}
diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css b/ui/src/app/app-image-labeling/app-image-labeling.module.ts
similarity index 51%
copy from ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
copy to ui/src/app/app-image-labeling/app-image-labeling.module.ts
index a4868af..9895c72 100644
--- a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
+++ b/ui/src/app/app-image-labeling/app-image-labeling.module.ts
@@ -6,16 +6,38 @@
  * (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,
  * 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.
- *
  */
 
-.imageBar {
-    height: 70px;
-}
\ No newline at end of file
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { CoreUiModule } from '../core-ui/core-ui.module';
+import { CustomMaterialModule } from '../CustomMaterial/custom-material.module';
+import { AppImageLabelingComponent } from './app-image-labeling.component';
+
+@NgModule({
+    imports: [
+        CommonModule,
+        CustomMaterialModule,
+        CoreUiModule,
+    ],
+    declarations: [
+        AppImageLabelingComponent
+    ],
+    providers: [
+    ],
+    entryComponents: [
+        AppImageLabelingComponent,
+    ],
+    exports: [
+        AppImageLabelingComponent
+    ]
+})
+export class AppImageLabelingModule {
+}
diff --git a/ui/src/app/app-overview/app-overview.component.html b/ui/src/app/app-overview/app-overview.component.html
index f358675..9824a55 100644
--- a/ui/src/app/app-overview/app-overview.component.html
+++ b/ui/src/app/app-overview/app-overview.component.html
@@ -49,4 +49,6 @@
     </div>
     <app-asset-monitoring (appOpened)="appOpened($event)"
                           *ngIf="currentlySelectedApp === apps[0].appId"></app-asset-monitoring>
+    <app-image-labeling (appOpened)="appOpened($event)"
+                          *ngIf="currentlySelectedApp === apps[1].appId"></app-image-labeling>
 </div>
diff --git a/ui/src/app/app-overview/app-overview.component.ts b/ui/src/app/app-overview/app-overview.component.ts
index 465d38b..5c7fe70 100644
--- a/ui/src/app/app-overview/app-overview.component.ts
+++ b/ui/src/app/app-overview/app-overview.component.ts
@@ -16,23 +16,28 @@
  *
  */
 
-import {Component} from '@angular/core';
+import { Component, OnInit } from "@angular/core";
 
 @Component({
     templateUrl: './app-overview.component.html',
     styleUrls: ['./app-overview.component.css']
 })
-export class AppOverviewComponent {
+export class AppOverviewComponent implements OnInit {
 
-    selectedIndex: number = 0;
+    selectedIndex = 0;
     appOpen = false;
-    currentlySelectedApp: string = "";
+    currentlySelectedApp = '';
 
     apps: any[] = [
         {
-            appName: "Asset Dashboards",
-            appDescription: "Monitor measurements of your assets by placing visualizations on an image of your asset.",
-            appId: "asset-monitoring",
+            appName: 'Asset Dashboards',
+            appDescription: 'Monitor measurements of your assets by placing visualizations on an image of your asset.',
+            appId: 'asset-monitoring',
+        },
+        {
+            appName: 'Image Labeling',
+            appDescription: 'Label in data lake stored images.',
+            appId: 'image-labeling',
         },
     ];
 
@@ -54,7 +59,7 @@ export class AppOverviewComponent {
 
     appClosed() {
         this.appOpen = false;
-        this.currentlySelectedApp = "";
+        this.currentlySelectedApp = '';
     }
 
     selectApp(appId: string) {
diff --git a/ui/src/app/app-overview/app-overview.module.ts b/ui/src/app/app-overview/app-overview.module.ts
index 10f9ead..03dc7f7 100644
--- a/ui/src/app/app-overview/app-overview.module.ts
+++ b/ui/src/app/app-overview/app-overview.module.ts
@@ -16,18 +16,19 @@
  *
  */
 
-import {NgModule} from '@angular/core';
-import {FlexLayoutModule} from '@angular/flex-layout';
-import {CommonModule} from '@angular/common';
-import {CustomMaterialModule} from '../CustomMaterial/custom-material.module';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { CustomMaterialModule } from '../CustomMaterial/custom-material.module';
 
-import {MatFormFieldModule} from "@angular/material/form-field";
-import {MatGridListModule} from "@angular/material/grid-list";
-import {MatInputModule} from "@angular/material/input";
-import {FormsModule} from "@angular/forms";
-import {AppOverviewComponent} from "./app-overview.component";
-import {AppAssetMonitoringModule} from "../app-asset-monitoring/app-asset-monitoring.module";
-import {AppTransportMonitoringModule} from "../app-transport-monitoring/app-transport-monitoring.module";
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { MatInputModule } from '@angular/material/input';
+import { AppAssetMonitoringModule } from '../app-asset-monitoring/app-asset-monitoring.module';
+import { AppImageLabelingModule } from '../app-image-labeling/app-image-labeling.module';
+import { AppTransportMonitoringModule } from '../app-transport-monitoring/app-transport-monitoring.module';
+import { AppOverviewComponent } from './app-overview.component';
 
 @NgModule({
     imports: [
@@ -39,7 +40,8 @@ import {AppTransportMonitoringModule} from "../app-transport-monitoring/app-tran
         MatFormFieldModule,
         FormsModule,
         AppAssetMonitoringModule,
-        AppTransportMonitoringModule
+        AppTransportMonitoringModule,
+        AppImageLabelingModule,
     ],
     declarations: [
         AppOverviewComponent,
diff --git a/ui/src/app/core-services/datalake/datalake-rest.service.ts b/ui/src/app/core-services/datalake/datalake-rest.service.ts
index 465cc0b..91e1184 100644
--- a/ui/src/app/core-services/datalake/datalake-rest.service.ts
+++ b/ui/src/app/core-services/datalake/datalake-rest.service.ts
@@ -18,12 +18,12 @@
 
 import { HttpClient, HttpRequest } from '@angular/common/http';
 import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import { DataLakeMeasure } from '../../core-model/datalake/DataLakeMeasure';
 import { DataResult } from '../../core-model/datalake/DataResult';
 import { GroupedDataResult } from '../../core-model/datalake/GroupedDataResult';
-import { DataLakeMeasure } from '../../core-model/datalake/DataLakeMeasure';
 import { PageResult } from '../../core-model/datalake/PageResult';
 import { AuthStatusService } from '../../services/auth-status.service';
-import { Observable } from "rxjs/Observable";
 
 @Injectable()
 export class DatalakeRestService {
@@ -146,4 +146,4 @@ export class DatalakeRestService {
     saveCocoFileForImage(imageRoute, data) {
       return this.http.post(this.dataLakeUrlV3 + '/data/image/' + imageRoute + '/coco', data);
     }
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index a1483ab..da4936e 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -45,6 +45,7 @@ import { ColorService } from './image/services/color.service';
 import { PolygonLabelingService } from './image/services/PolygonLabeling.service';
 import { ReactLabelingService } from './image/services/ReactLabeling.service';
 import { CocoFormatService } from "./image/services/CocoFormat.service";
+import { LabelingModeService } from "./image/services/LabelingMode.service";
 // PlotlyViaCDNModule.plotlyjs = PlotlyJS;
 
 @NgModule({
@@ -80,6 +81,7 @@ import { CocoFormatService } from "./image/services/CocoFormat.service";
         PolygonLabelingService,
         BrushLabelingService,
         CocoFormatService,
+        LabelingModeService,
     ],
     entryComponents: [
     ],
diff --git a/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.html b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.html
index feedf72..abfaf1d 100644
--- a/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.html
+++ b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.html
@@ -20,19 +20,25 @@
     <h2>Annotations</h2>
     <mat-list>
         <mat-list-item *ngFor="let annotation of annotations" (mouseover)="enterAnnotation(annotation)" (mouseout)="leaveAnnotation(annotation)"
-                       style="height: 30px; padding-top: 5px; padding-buttom: 5px; border-radius: 50px; margin-bottom: 5px"
+                       style="height: 40px; padding-top: 5px; padding-buttom: 5px; border-radius: 50px; margin-bottom: 5px"
                        [style.background-color]="annotation.isHovered || annotation.isSelected ? 'lightgrey' : 'white'">
-            <mat-icon matListIcon [style.color]="colorService.getColor(annotation.category_name)" style="margin-top: -8px;">color_lens</mat-icon>
             <mat-form-field>
                 <mat-select [value]="annotation.category_name">
+
+                    <mat-select-trigger>
+                        <mat-icon [style.color]="colorService.getColor(annotation.category_name)">color_lens</mat-icon>
+                        {{annotation.category_name}}
+                    </mat-select-trigger>
+
                     <mat-optgroup *ngFor="let category of categories" [label]="category">
                         <mat-option *ngFor="let label of _labels[category]" [value]="label" (click)="changeLabel(annotation, label, category)">
+                            <mat-icon [style.color]="colorService.getColor(label)">color_lens</mat-icon>
                             {{label}}
                         </mat-option>
                     </mat-optgroup>
                 </mat-select>
             </mat-form-field>
-            <button mat-icon-button (click)="delete(annotation)" style="margin-top: -10px; margin-left: 10px"> <mat-icon>delete_forever</mat-icon></button>
+            <button mat-icon-button (click)="delete(annotation)" style="margin-top: -10px; margin-left: -5px"> <mat-icon>delete_forever</mat-icon></button>
         </mat-list-item>
     </mat-list>
 </div>
\ No newline at end of file
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 a4868af..b0f2e09 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
@@ -18,4 +18,5 @@
 
 .imageBar {
     height: 70px;
+    width: 1000px;
 }
\ No newline at end of file
diff --git a/ui/src/app/core-ui/image/components/image-container/image-container.component.css b/ui/src/app/core-ui/image/components/image-container/image-container.component.css
index 612fce8..dfaa975 100644
--- a/ui/src/app/core-ui/image/components/image-container/image-container.component.css
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.css
@@ -20,6 +20,5 @@
     background-color: #fafafa;
     border-color: lightgrey;
     border-style: solid;
-    height: 500px;
-    width: 800px;
+
 }
\ No newline at end of file
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 7667a8f..b1c47c0 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
@@ -17,7 +17,6 @@
 
 import { AfterViewInit, Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core';
 import Konva from 'konva';
-import { Context } from 'konva/types/Context';
 import { ICoordinates } from '../../model/coordinates';
 
 @Component({
@@ -46,6 +45,8 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
   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]>();
 
 
   private image;
@@ -62,6 +63,7 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
   private lastImagePointerPosition: ICoordinates;
 
   private isLeftMouseDown: boolean;
+  private isMiddleMouseDown: boolean;
   private isRightMouseDown: boolean;
 
   private isHoverComponent: boolean;
@@ -72,6 +74,7 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
     this.scale = 1;
     this.imageShift = {x: 0, y: 0};
     this.isLeftMouseDown = false;
+    this.isMiddleMouseDown = false;
     this.isRightMouseDown = false;
     this.isHoverComponent = false;
   }
@@ -106,8 +109,10 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
   }
 
   getShift() {
-    const position = this.imageLayer.getChildren().toArray()[0].getPosition();
-    return {x: position.x, y: position.y};
+    if (this.imageLayer !== undefined) {
+      const position = this.imageLayer.getChildren().toArray()[0].getPosition();
+      return {x: position.x, y: position.y};
+    }
   }
   /* mouse handler */
 
@@ -120,13 +125,14 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
       this.drawLayer.batchDraw();
     } else if (button === 2) {
       // middle click
-
-    } else if (button === 3) {
-      // right click
-      this.isRightMouseDown = true;
+      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()]);
     }
   }
 
@@ -135,7 +141,7 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
       this.drawLayer.destroyChildren();
       this.mouseMoveLeft.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
       this.drawLayer.batchDraw();
-    } else if (this.isRightMouseDown) {
+    } 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);
@@ -157,8 +163,8 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
       this.drawLayer.batchDraw();
       this.annotationLayer.batchDraw();
     }
-    if (this.isRightMouseDown) {
-      this.isRightMouseDown = false;
+    if (this.isMiddleMouseDown) {
+      this.isMiddleMouseDown = false;
       this.mainCanvasStage.container().style.cursor = 'default';
     }
   }
@@ -173,8 +179,12 @@ export class ImageContainerComponent implements OnInit, AfterViewInit {
   /* Draw */
 
   redrawAll() {
-    this.drawLayer.destroyChildren();
-    this.annotationLayer.destroyChildren();
+    if (this.drawLayer !== undefined) {
+      this.drawLayer.destroyChildren();
+    }
+    if (this.annotationLayer !== undefined) {
+      this.annotationLayer.destroyChildren();
+    }
     this.childRedraw.emit([this.annotationLayer, this.getShift()]);
     this.shiftViewContent();
   }
diff --git a/ui/src/app/core-ui/image/image-categorize/image-categorize.component.html b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.html
index a75852d..a5d6a0c 100644
--- a/ui/src/app/core-ui/image/image-categorize/image-categorize.component.html
+++ b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.html
@@ -46,7 +46,7 @@
             </div>
         </div>
         <br />
-        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum + 1}}</div></div>
+        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum }}</div></div>
         <sp-image-bar style="width: 100%"
                       [imagesSrcs]="imagesSrcs"
                       [selectedIndex]="imagesIndex"
diff --git a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
index 0669e12..a6390f8 100644
--- a/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
@@ -21,19 +21,24 @@
     <div fxLayout="column" fxLayoutAlign="space-between " >
         <div  fxLayout="row" fxLayoutAlign="space-around start">
 
-            <sp-image-labels
+            <sp-image-labels style="width: 270px"
                     [labels]="labels"
                     [enableShortCuts]="isHoverComponent"
                     (labelChange)="handleLabelChange($event)">
             </sp-image-labels>
 
             <div fxLayout="column" fxLayoutAlign="space-between " >
-                <div>
-                    <button mat-button (click)="setReactMode()" [style.background-color]="isReactMode() ? 'lightgrey' : 'white'"> <mat-icon>crop_3_2</mat-icon></button>
-                    <button mat-button (click)="setPolygonMode()" [style.background-color]="isPolygonMode() ? 'lightgrey' : 'white'"> <mat-icon>details</mat-icon></button>
-                    <button mat-button (click)="setBrushMode()" [style.background-color]="isBrushMode() ? 'lightgrey' : 'white'"> <mat-icon>blur_circular</mat-icon></button>
+                <div style="display: flex; position: relative">
+                    <button mat-button matTooltip="Edit Annotations"
+                            (click)="labelingMode.setNoneMode()" [style.background-color]="labelingMode.isNoneMode() ? 'lightgrey' : 'white'"> <mat-icon>create</mat-icon></button>
+                    <button mat-button matTooltip="Create React Annotation"
+                            (click)="labelingMode.setReactMode()" [style.background-color]="labelingMode.isReactMode() ? 'lightgrey' : 'white'"> <mat-icon>crop_3_2</mat-icon></button>
+                    <button mat-button matTooltip="Create Polygon Annotation"
+                            (click)="labelingMode.setPolygonMode()" [style.background-color]="labelingMode.isPolygonMode() ? 'lightgrey' : 'white'"> <mat-icon>details</mat-icon></button>
+                    <button mat-button matTooltip="Create Brush Annotation"
+                            (click)="labelingMode.setBrushMode()" [style.background-color]="labelingMode.isBrushMode() ? 'lightgrey' : 'white'"> <mat-icon>blur_circular</mat-icon></button>
                     <mat-slider [min]="1"  [max]="50" [step]="1" [thumbLabel]="true" [(ngModel)]="brushSize"></mat-slider>
-                    <button mat-button (click)="save()"> <mat-icon>save</mat-icon></button>
+                    <button mat-button (click)="save()" style="position: absolute; right: 0px;"> <mat-icon>save</mat-icon></button>
                 </div>
 
                 <sp-image-container
@@ -44,11 +49,12 @@
                         (mouseMoveLeft)="handleMouseMoveLeft($event[0], $event[1], $event[2])"
                         (mouseUpLeft)="handleMouseUpLeft($event[0], $event[1], $event[2], $event[3])"
                         (shortCut)="handleImageViewShortCuts($event)"
-                        (dbclick)="handleImageViewDBClick($event[0], $event[1], $event[2])">
+                        (dbclick)="handleImageViewDBClick($event[0], $event[1], $event[2])"
+                        (mouseDownRight)="handleMouseDownRight($event[0], $event[1], $event[2])">
                 </sp-image-container>
             </div>
 
-            <sp-image-annotations
+            <sp-image-annotations style="width: 270px"
                     [annotations]="this.cocoFiles[this.imagesIndex]?.annotations"
                     [labels]="labels"
                     (changeAnnotationLabel)="handleChangeAnnotationLabel($event)"
@@ -56,7 +62,7 @@
             </sp-image-annotations>
         </div>
         <br />
-        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum + 1}}</div></div>
+        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum}}</div></div>
         <sp-image-bar style="width: 100%"
                 [imagesSrcs]="imagesSrcs"
                 [selectedIndex]="imagesIndex"
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 2cd0b24..c2c68f7 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
@@ -17,27 +17,28 @@
  */
 
 
-import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
+import { AfterViewInit, Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
 import { MatSnackBar } from '@angular/material/snack-bar';
 import Konva from 'konva';
 import { Annotation } from '../../../core-model/coco/Annotation';
 import { CocoFormat } from '../../../core-model/coco/Coco.format';
 import { DatalakeRestService } from '../../../core-services/datalake/datalake-rest.service';
+import { TsonLdSerializerService } from '../../../platform-services/tsonld-serializer.service';
 import { ImageContainerComponent } from '../components/image-container/image-container.component';
 import { ICoordinates } from '../model/coordinates';
 import { LabelingMode } from '../model/labeling-mode';
 import { BrushLabelingService } from '../services/BrushLabeling.service';
 import { CocoFormatService } from '../services/CocoFormat.service';
+import { LabelingModeService } from '../services/LabelingMode.service';
 import { PolygonLabelingService } from '../services/PolygonLabeling.service';
 import { ReactLabelingService } from '../services/ReactLabeling.service';
-import { TsonLdSerializerService } from '../../../platform-services/tsonld-serializer.service';
 
 @Component({
   selector: 'sp-image-labeling',
   templateUrl: './image-labeling.component.html',
   styleUrls: ['./image-labeling.component.css']
 })
-export class ImageLabelingComponent implements OnInit, AfterViewInit {
+export class ImageLabelingComponent implements OnInit, AfterViewInit, OnChanges {
 
   // label
   public labels;
@@ -54,8 +55,8 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
 
   @ViewChild(ImageContainerComponent) imageView: ImageContainerComponent;
 
-  measureName = 'image'; // TODO: Remove hard coded Index, should be injected
-  eventSchema = undefined; // TODO: event schema should be also injected
+  @Input() measureName = 'image'; // TODO: Remove default value for production
+  @Input() eventSchema = undefined; // TODO: event schema should be always injected by production
   imageField = undefined;
   pageIndex = undefined;
   pageSum = undefined;
@@ -65,38 +66,57 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
   private setImagesIndexToLast = false;
 
 
-  public labelingMode: LabelingMode = LabelingMode.ReactLabeling;
 
   constructor(private restService: DatalakeRestService, private reactLabelingService: ReactLabelingService,
               private polygonLabelingService: PolygonLabelingService, private brushLabelingService: BrushLabelingService,
               private snackBar: MatSnackBar, private cocoFormatService: CocoFormatService,
-              private tsonLdSerializerService: TsonLdSerializerService) { }
+              private tsonLdSerializerService: TsonLdSerializerService,
+              public labelingMode: LabelingModeService) { }
 
   ngOnInit(): void {
     this.isHoverComponent = false;
     this.brushSize = 5;
+    this.imagesIndex = 0;
+
 
-    // TODO Get Labels
     this.labels = this.restService.getLabels();
 
-    this.restService.getAllInfos().map(data => {
-      return this.tsonLdSerializerService.fromJsonLdContainer(data, 'sp:DataLakeMeasure');
-    }).subscribe(
-      res => {
-        this.eventSchema = res.find(elem => elem.measureName === this.measureName).eventSchema;
-        const properties = this.eventSchema.eventProperties;
-        for (const prop of properties) {
-          // if (prop.domainProperties.find(type => type === 'https://image.com')) {
+    // TODO remove for production, if default dev values are not necessary
+    if (this.eventSchema === undefined) {
+      this.restService.getAllInfos().map(data => {
+        return this.tsonLdSerializerService.fromJsonLdContainer(data, 'sp:DataLakeMeasure');
+      }).subscribe(
+        res => {
+          this.eventSchema = res.find(elem => elem.measureName === this.measureName).eventSchema;
+          const properties = this.eventSchema.eventProperties;
+          for (const prop of properties) {
+            // if (prop.domainProperties.find(type => type === 'https://image.com')) {
             if (prop.domainProperty === 'https://image.com') {
-            this.imageField = prop;
-            break;
+              this.imageField = prop;
+              break;
+            }
           }
+          this.loadData();
+        }
+      );
+    }
+  }
+
+  ngOnChanges() {
+    if (this.eventSchema !== null) {
+      const properties = this.eventSchema.eventProperties;
+      for (const prop of properties) {
+        if (prop.domainProperty === 'https://image.com') {
+          this.imageField = prop;
+          break;
         }
-        this.loadData();
       }
-    );
+      this.pageIndex = undefined;
+      this.pageSum = undefined;
+      this.imagesIndex = 0;
 
-    this.imagesIndex = 0;
+      this.loadData();
+    }
   }
 
   ngAfterViewInit(): void {
@@ -159,7 +179,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
   /* sp-image-view handler */
   handleMouseDownLeft(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
     if (this.labelingEnabled()) {
-      switch (this.labelingMode) {
+      switch (this.labelingMode.getMode()) {
         case LabelingMode.ReactLabeling: this.reactLabelingService.startLabeling(position);
           break;
         case LabelingMode.PolygonLabeling: this.polygonLabelingService.startLabeling(position);
@@ -170,7 +190,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
   }
 
   handleMouseMove(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
-    switch (this.labelingMode) {
+    switch (this.labelingMode.getMode()) {
       case LabelingMode.PolygonLabeling: {
         this.polygonLabelingService.executeLabeling(position);
         this.polygonLabelingService.tempDraw(layer, shift, this.selectedLabel.label);
@@ -180,7 +200,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
 
   handleMouseMoveLeft(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
     if (this.labelingEnabled()) {
-      switch (this.labelingMode) {
+      switch (this.labelingMode.getMode()) {
         case LabelingMode.ReactLabeling: {
           this.reactLabelingService.executeLabeling(position);
           this.reactLabelingService.tempDraw(layer, shift, this.selectedLabel.label);
@@ -191,12 +211,12 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
           this.brushLabelingService.tempDraw(layer, shift, this.selectedLabel.label);
         }
       }
-    }
+   }
   }
 
   handleMouseUpLeft(annotationLayer: Konva.Layer, drawLayer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
     if (this.labelingEnabled()) {
-      switch (this.labelingMode) {
+      switch (this.labelingMode.getMode()) {
         case LabelingMode.ReactLabeling: {
           const result = this.reactLabelingService.endLabeling(position);
           const coco = this.cocoFiles[this.imagesIndex];
@@ -220,10 +240,14 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
     }
   }
 
+  handleMouseDownRight(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
+    this.labelingMode.toggleNoneMode();
+  }
+
 
   handleImageViewDBClick(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
     if (this.labelingEnabled()) {
-      switch (this.labelingMode) {
+      switch (this.labelingMode.getMode()) {
         case LabelingMode.PolygonLabeling:
           const points = this.polygonLabelingService.endLabeling(position);
           const coco = this.cocoFiles[this.imagesIndex];
@@ -236,15 +260,17 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
 
   handleChildRedraw(layer: Konva.Layer, shift: ICoordinates) {
     const coco = this.cocoFiles[this.imagesIndex];
-    for (const annotation of coco.annotations) {
-      annotation.isHovered = false;
-      annotation.isSelected = false;
-      if (this.cocoFormatService.isBoxAnnonation(annotation)) {
-        this.reactLabelingService.draw(layer, shift, annotation, this.imageView);
-      } else if (this.cocoFormatService.isPolygonAnnonation(annotation) && !this.cocoFormatService.isBrushAnnonation(annotation)) {
-        this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
-      } else if (this.cocoFormatService.isBrushAnnonation(annotation)) {
-        this.brushLabelingService.draw(layer, shift, annotation, this.imageView);
+    if (coco  !== undefined) {
+      for (const annotation of coco.annotations) {
+        annotation.isHovered = false;
+        annotation.isSelected = false;
+        if (this.cocoFormatService.isBoxAnnonation(annotation)) {
+          this.reactLabelingService.draw(layer, shift, annotation, this.imageView);
+        } else if (this.cocoFormatService.isPolygonAnnonation(annotation) && !this.cocoFormatService.isBrushAnnonation(annotation)) {
+          this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
+        } else if (this.cocoFormatService.isBrushAnnonation(annotation)) {
+          this.brushLabelingService.draw(layer, shift, annotation, this.imageView);
+        }
       }
     }
   }
@@ -306,7 +332,7 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
 
   private labelingEnabled() {
     const coco = this.cocoFiles[this.imagesIndex];
-    const annotation = coco.annotations.find(anno => anno.isHovered);
+    const annotation = coco.annotations.find(anno => anno.isHovered && anno.isSelected);
     if (annotation !== undefined) {
       return false;
     } else {
@@ -317,11 +343,13 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
   save() {
     // TODO
     const coco = this.cocoFiles[this.imagesIndex];
-    const imageSrcSplitted = this.imagesSrcs[this.imagesIndex].split('/');
-    const imageRoute = imageSrcSplitted[imageSrcSplitted.length - 2];
-    this.restService.saveCocoFileForImage(imageRoute, JSON.stringify(coco)).subscribe(
-      res =>    this.openSnackBar('Saved')
-    );
+    if (coco !== undefined) {
+      const imageSrcSplitted = this.imagesSrcs[this.imagesIndex].split('/');
+      const imageRoute = imageSrcSplitted[imageSrcSplitted.length - 2];
+      this.restService.saveCocoFileForImage(imageRoute, JSON.stringify(coco)).subscribe(
+        res =>    this.openSnackBar('Saved')
+      );
+    }
   }
 
   private openSnackBar(message: string) {
@@ -332,28 +360,4 @@ export class ImageLabelingComponent implements OnInit, AfterViewInit {
     });
   }
 
-  /* UI */
-  isReactMode() {
-    return this.labelingMode === LabelingMode.ReactLabeling;
-  }
-
-  setReactMode() {
-    this.labelingMode = LabelingMode.ReactLabeling;
-  }
-
-  isPolygonMode() {
-    return this.labelingMode === LabelingMode.PolygonLabeling;
-  }
-
-  setPolygonMode() {
-    this.labelingMode = LabelingMode.PolygonLabeling;
-  }
-
-  isBrushMode() {
-    return this.labelingMode === LabelingMode.BrushLabeling;
-  }
-
-  setBrushMode() {
-    this.labelingMode = LabelingMode.BrushLabeling;
-  }
 }
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 d373a2b..60ca4a6 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
@@ -26,7 +26,7 @@
             </div>
         </div>
         <br />
-        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum + 1}}</div></div>
+        <div fxLayout="row" fxLayoutAlign="center center"><div>{{pageIndex + 1}} / {{pageSum }}</div></div>
         <sp-image-bar style="width: 100%"
                       [imagesSrcs]="imagesSrcs"
                       [selectedIndex]="imagesIndex"
diff --git a/ui/src/app/core-ui/image/services/BrushLabeling.service.ts b/ui/src/app/core-ui/image/services/BrushLabeling.service.ts
index d97b0dc..07ffd3b 100644
--- a/ui/src/app/core-ui/image/services/BrushLabeling.service.ts
+++ b/ui/src/app/core-ui/image/services/BrushLabeling.service.ts
@@ -20,6 +20,7 @@ import Konva from 'konva';
 import { Annotation } from '../../../core-model/coco/Annotation';
 import { ICoordinates } from '../model/coordinates';
 import { ColorService } from './color.service';
+import { LabelingModeService } from './LabelingMode.service';
 
 @Injectable()
 export class BrushLabelingService {
@@ -29,7 +30,8 @@ export class BrushLabelingService {
 
   private isLabeling: boolean;
 
-  constructor(private colorService: ColorService) {
+  constructor(private colorService: ColorService,
+              private labelingMode: LabelingModeService) {
 
   }
 
@@ -100,43 +102,49 @@ export class BrushLabelingService {
       transformer.attachTo(line);
     }
 
-    this.addMouseHandler(line, annotation, layer, transformer);
-    this.addClickHandler(line, annotation, layer, transformer);
+    this.addMouseHandler(line, annotation, layer, transformer, this.labelingMode);
+    this.addClickHandler(line, annotation, layer, transformer, this.labelingMode);
 
     layer.add(line);
     layer.add(transformer);
   }
 
-  private addClickHandler(rect, annotation, layer, transformer) {
-    rect.on('click', function() {
-      annotation.isSelected = true;
-      transformer.attachTo(this);
-      layer.batchDraw();
-    });
+  private addClickHandler(brush, annotation, layer, transformer, labelingMode) {
+    brush.on('click', function() {
+      if (labelingMode.isNoneMode()) {
+        annotation.isSelected = !annotation.isSelected;
 
-    rect.on('dblclick', function() {
-      annotation.isSelected = false;
-      transformer.detach();
-      layer.batchDraw();
+        if (annotation.isSelected) {
+          transformer.attachTo(this);
+        } else {
+          transformer.detach();
+        }
+
+        layer.batchDraw();
+      }
     });
 
   }
 
-  private addMouseHandler(rect, annotation, layer, transformer) {
-    rect.on('mouseover', function() {
-      annotation.isHovered = true;
-      rect.opacity(0.8);
-      layer.batchDraw();
+  private addMouseHandler(brush, annotation, layer, transformer, labelingMode) {
+    brush.on('mouseover', function() {
+      if (labelingMode.isNoneMode()) {
+        annotation.isHovered = true;
+        brush.opacity(0.8);
+        layer.batchDraw();
+      }
     });
 
-    rect.on('mouseout', function() {
+    brush.on('mouseout', function() {
       annotation.isHovered = false;
-      rect.opacity(0.5);
+      brush.opacity(0.5);
       layer.batchDraw();
     });
 
     transformer.on('mouseover', function() {
-      annotation.isHovered = true;
+      if (labelingMode.isNoneMode()) {
+        annotation.isHovered = true;
+      }
     });
 
     transformer.on('mouseout', function() {
diff --git a/ui/src/app/core-ui/image/services/LabelingMode.service.ts b/ui/src/app/core-ui/image/services/LabelingMode.service.ts
new file mode 100644
index 0000000..fe5307e
--- /dev/null
+++ b/ui/src/app/core-ui/image/services/LabelingMode.service.ts
@@ -0,0 +1,79 @@
+/*
+ * 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 { Injectable } from '@angular/core';
+import { LabelingMode } from '../model/labeling-mode';
+
+@Injectable()
+export class LabelingModeService {
+
+  private labelingMode: LabelingMode;
+  private lastLabelingMode: LabelingMode;
+
+  constructor() {
+    this.labelingMode = LabelingMode.ReactLabeling;
+    this.lastLabelingMode = LabelingMode.ReactLabeling;
+  }
+
+  isReactMode() {
+    return this.labelingMode === LabelingMode.ReactLabeling;
+  }
+
+  setReactMode() {
+    this.labelingMode = LabelingMode.ReactLabeling;
+    this.lastLabelingMode = LabelingMode.ReactLabeling;
+  }
+
+  isPolygonMode() {
+    return this.labelingMode === LabelingMode.PolygonLabeling;
+  }
+
+  setPolygonMode() {
+    this.labelingMode = LabelingMode.PolygonLabeling;
+    this.lastLabelingMode = LabelingMode.PolygonLabeling;
+  }
+
+  isBrushMode() {
+    return this.labelingMode === LabelingMode.BrushLabeling;
+  }
+
+  setBrushMode() {
+    this.labelingMode = LabelingMode.BrushLabeling;
+    this.lastLabelingMode = LabelingMode.BrushLabeling;
+  }
+
+  isNoneMode() {
+    return this.labelingMode === LabelingMode.NoneLabeling;
+  }
+
+  setNoneMode() {
+    this.labelingMode = LabelingMode.NoneLabeling;
+  }
+
+  getMode() {
+    return this.labelingMode;
+  }
+
+  toggleNoneMode() {
+    if (this.labelingMode === LabelingMode.NoneLabeling) {
+      this.labelingMode = this.lastLabelingMode;
+    } else {
+      this.labelingMode = LabelingMode.NoneLabeling;
+    }
+  }
+
+}
diff --git a/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts b/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts
index 153e8fd..2c65fee 100644
--- a/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts
+++ b/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts
@@ -20,6 +20,7 @@ import Konva from 'konva';
 import { Annotation } from '../../../core-model/coco/Annotation';
 import { ICoordinates } from '../model/coordinates';
 import { ColorService } from './color.service';
+import { LabelingModeService } from './LabelingMode.service';
 
 @Injectable()
 export class PolygonLabelingService {
@@ -29,7 +30,8 @@ export class PolygonLabelingService {
 
   private isLabeling: boolean;
 
-  constructor(private colorService: ColorService) {
+  constructor(private colorService: ColorService,
+              private labelingMode: LabelingModeService) {
     this.isLabeling = false;
   }
 
@@ -182,36 +184,41 @@ export class PolygonLabelingService {
       PolygonLabelingService.buildAnchors(layer, annotation, imageView, poly);
     }
 
-    this.addDragHandler(poly, annotation, layer, imageView);
-    this.addMouseHandler(poly, annotation, layer, transformer);
-    this.addClickHandler(poly, annotation, layer, transformer, imageView);
+    this.addDragHandler(poly, annotation, layer, imageView, this.labelingMode);
+    this.addMouseHandler(poly, annotation, layer, transformer, this.labelingMode);
+    this.addClickHandler(poly, annotation, layer, transformer, imageView, this.labelingMode);
 
     layer.add(poly);
     layer.add(transformer);
   }
 
-  private addClickHandler(poly, annotation, layer, transformer, imageView) {
+  private addClickHandler(poly, annotation, layer, transformer, imageView, labelingMode) {
     poly.on('click', function() {
-      annotation.isSelected = true;
-      transformer.attachTo(this);
-      PolygonLabelingService.buildAnchors(layer, annotation, imageView, poly);
-      layer.batchDraw();
-    });
-
-    poly.on('dblclick', function() {
-      annotation.isSelected = false;
-      PolygonLabelingService.removeAnchors(layer, annotation.id);
-      transformer.detach();
-      layer.batchDraw();
+      if (labelingMode.isNoneMode()) {
+
+        annotation.isSelected = !annotation.isSelected;
+
+        if (annotation.isSelected) {
+          annotation.isSelected = true;
+          transformer.attachTo(this);
+          PolygonLabelingService.buildAnchors(layer, annotation, imageView, poly);
+        } else {
+          PolygonLabelingService.removeAnchors(layer, annotation.id);
+          transformer.detach();
+        }
+        layer.batchDraw();
+      }
     });
 
   }
 
-  private addMouseHandler(poly, annotation, layer, transformer) {
+  private addMouseHandler(poly, annotation, layer, transformer, labelingMode) {
     poly.on('mouseover', function() {
-      annotation.isHovered = true;
-      this.opacity(0.8);
-      layer.batchDraw();
+      if (labelingMode.isNoneMode()) {
+        annotation.isHovered = true;
+        poly.opacity(0.8);
+        layer.batchDraw();
+      }
     });
 
     poly.on('mouseout', function() {
@@ -222,28 +229,36 @@ export class PolygonLabelingService {
   }
 
 
-  private addDragHandler(poly, annotation, layer, imageView) {
+  private addDragHandler(poly, annotation, layer, imageView, labelingMode) {
     let offset: number[];
 
     poly.on('dragstart', function() {
-      const position = imageView.getImagePointerPosition();
-      offset = [];
-      for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
-        offset.push(annotation.segmentation[0][i] - position.x);
-        offset.push(annotation.segmentation[0][i + 1] - position.y);
+      if (!labelingMode.isNoneMode()) {
+        poly.stopDrag();
+      } else {
+        const position = imageView.getImagePointerPosition();
+        offset = [];
+        for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+          offset.push(annotation.segmentation[0][i] - position.x);
+          offset.push(annotation.segmentation[0][i + 1] - position.y);
+        }
       }
     });
 
     poly.on('dragmove', function() {
-      const position = imageView.getImagePointerPosition();
-      const tmp = [];
-      for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
-        tmp.push(position.x + offset[i]);
-        tmp.push(position.y + offset[i + 1]);
-      }
-      annotation.segmentation[0] = tmp;
-      if (annotation.isSelected) {
-        PolygonLabelingService.buildAnchors(layer, annotation, imageView, poly);
+      if (!labelingMode.isNoneMode()) {
+        poly.stopDrag();
+      } else {
+        const position = imageView.getImagePointerPosition();
+        const tmp = [];
+        for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+          tmp.push(position.x + offset[i]);
+          tmp.push(position.y + offset[i + 1]);
+        }
+        annotation.segmentation[0] = tmp;
+        if (annotation.isSelected) {
+          PolygonLabelingService.buildAnchors(layer, annotation, imageView, poly);
+        }
       }
     });
 
diff --git a/ui/src/app/core-ui/image/services/ReactLabeling.service.ts b/ui/src/app/core-ui/image/services/ReactLabeling.service.ts
index 1059dba..1c795b2 100644
--- a/ui/src/app/core-ui/image/services/ReactLabeling.service.ts
+++ b/ui/src/app/core-ui/image/services/ReactLabeling.service.ts
@@ -20,6 +20,7 @@ import Konva from 'konva';
 import { Annotation } from '../../../core-model/coco/Annotation';
 import { ICoordinates } from '../model/coordinates';
 import { ColorService } from './color.service';
+import { LabelingModeService } from './LabelingMode.service';
 
 @Injectable()
 export class ReactLabelingService {
@@ -29,8 +30,8 @@ export class ReactLabelingService {
 
   private isLabeling: boolean;
 
-  constructor(private colorService: ColorService) {
-
+  constructor(private colorService: ColorService,
+              private labelingMode: LabelingModeService) {
   }
 
 
@@ -94,35 +95,38 @@ export class ReactLabelingService {
       transformer.attachTo(rect);
     }
 
-    this.addDragHandler(rect, annotation, imageView);
+    this.addDragHandler(rect, annotation, imageView, this.labelingMode);
     this.addTransformHandler(rect, annotation, imageView);
-    this.addMouseHandler(rect, annotation, layer, transformer);
-    this.addClickHandler(rect, annotation, layer, transformer);
+    this.addMouseHandler(rect, annotation, layer, transformer, this.labelingMode);
+    this.addClickHandler(rect, annotation, layer, transformer, this.labelingMode);
 
     layer.add(rect);
     layer.add(transformer);
   }
 
-  private addClickHandler(rect, annotation, layer, transformer) {
+  private addClickHandler(rect, annotation, layer, transformer, labelingMode) {
     rect.on('click', function() {
-      annotation.isSelected = true;
-      transformer.attachTo(this);
-      layer.batchDraw();
-    });
+      if (labelingMode.isNoneMode()) {
+        annotation.isSelected = !annotation.isSelected;
 
-    rect.on('dblclick', function() {
-      annotation.isSelected = false;
-      transformer.detach();
-      layer.batchDraw();
-    });
+        if (annotation.isSelected) {
+          transformer.attachTo(this);
+        } else {
+          transformer.detach();
+        }
 
+        layer.batchDraw();
+      }
+    });
   }
 
-  private addMouseHandler(rect, annotation, layer, transformer) {
+  private addMouseHandler(rect, annotation, layer, transformer, labelingMode) {
     rect.on('mouseover', function() {
-      annotation.isHovered = true;
-      rect.opacity(0.8);
-      layer.batchDraw();
+      if (labelingMode.isNoneMode()) {
+        annotation.isHovered = true;
+        rect.opacity(0.8);
+        layer.batchDraw();
+      }
     });
 
     rect.on('mouseout', function() {
@@ -132,7 +136,9 @@ export class ReactLabelingService {
     });
 
     transformer.on('mouseover', function() {
-      annotation.isHovered = true;
+      if (labelingMode.isNoneMode()) {
+        annotation.isHovered = true;
+      }
     });
 
     transformer.on('mouseout', function() {
@@ -179,18 +185,25 @@ export class ReactLabelingService {
     });
   }
 
-  private addDragHandler(rect, annotation, imageView) {
+  private addDragHandler(rect, annotation, imageView, labelingMode) {
     let offset: ICoordinates;
 
     rect.on('dragstart', function() {
-      const position = imageView.getImagePointerPosition();
-      offset = {x: annotation.bbox[0] - position.x, y: annotation.bbox[1] - position.y};
+      if (!labelingMode.isNoneMode()) {
+        rect.stopDrag();
+      } else {
+        const position = imageView.getImagePointerPosition();
+        offset = {x: annotation.bbox[0] - position.x, y: annotation.bbox[1] - position.y};
+      }
     });
 
     rect.on('dragmove', function() {
-      const position = imageView.getImagePointerPosition();
-      annotation.bbox[0] = imageView.getImagePointerPosition().x + offset.x;
-      annotation.bbox[1] = imageView.getImagePointerPosition().y + offset.y;
+      if (!labelingMode.isNoneMode()) {
+        rect.stopDrag();
+      } else {
+        const position = imageView.getImagePointerPosition();
+        annotation.bbox[0] = imageView.getImagePointerPosition().x + offset.x;
+        annotation.bbox[1] = imageView.getImagePointerPosition().y + offset.y;     }
     });
 
   }