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/03/13 15:42:51 UTC

[incubator-streampipes] branch image-labeling updated: [STREAMPIPES-79] big refactor using konvasjs to drav; add brush labeling

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

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


The following commit(s) were added to refs/heads/image-labeling by this push:
     new b2e92c6  [STREAMPIPES-79] big refactor using konvasjs to drav; add brush labeling
b2e92c6 is described below

commit b2e92c667d77e7b7e724112463bb25141881ffd6
Author: tex <te...@fzi.de>
AuthorDate: Fri Mar 13 16:42:22 2020 +0100

    [STREAMPIPES-79]
    big refactor using konvasjs to drav; add brush labeling
---
 ui/package.json                                    |   1 -
 .../app/CustomMaterial/custom-material.module.ts   |  23 +-
 ui/src/app/core-model/coco/Annotation.ts           |  24 +-
 ui/src/app/core-model/coco/Coco.format.ts          |  92 +++--
 .../datalake/datalake-rest.service.ts              |  54 +--
 ui/src/app/core-ui/core-ui.module.ts               |  55 ++-
 .../image-annotations.component.css}               |  24 --
 .../image-annotations.component.html               |  38 ++
 .../image-annotations.component.ts                 |  63 +++
 .../components/image-bar/image-bar.component.css}  |   9 +-
 .../components/image-bar/image-bar.component.html} |  22 +-
 .../components/image-bar/image-bar.component.ts    |  82 ++++
 .../image-container/image-container.component.css} |  38 +-
 .../image-container.component.html}                |  20 +-
 .../image-container/image-container.component.ts   | 268 +++++++++++++
 .../image-labels/image-labels.component.css}       |  22 +-
 .../image-labels/image-labels.component.html       |  39 ++
 .../image-labels/image-labels.component.ts         |  55 +++
 .../image-categorize.component.css}                |  11 +-
 .../image-categorize.component.html                |  55 +++
 .../image-categorize/image-categorize.component.ts | 101 +++++
 .../image-labeling/image-labeling.component.css}   |  11 +-
 .../image-labeling/image-labeling.component.html   |  68 ++++
 .../image-labeling/image-labeling.component.ts     | 278 ++++++++++++++
 .../image-viewer/image-viewer.component.css}       |  11 +-
 .../image-viewer/image-viewer.component.html}      |  33 +-
 .../image-viewer/image-viewer.component.ts}        |  51 ++-
 .../image.component.css}                           |  11 +-
 .../image/image.component.html}                    |  24 +-
 .../annotationMode.ts => image/image.component.ts} |  29 +-
 .../model/coordinates.ts}                          |   9 +-
 .../model/labeling-mode.ts}                        |   6 +-
 .../image/services/BrushLabeling.service.ts        | 147 +++++++
 .../image/services/PolygonLabeling.service.ts      | 252 ++++++++++++
 .../image/services/ReactLabeling.service.ts        | 198 ++++++++++
 .../services/color.service.ts}                     |  21 +-
 .../util/imageTranslation.util.ts                  |  10 +-
 .../imageLabeler/annotation/imageAnnotation.ts     | 192 ----------
 .../annotation/polygonAnnotation.util.ts           | 155 --------
 .../annotation/reactAnnotation.util.ts             | 234 ------------
 .../imageLabeler/imageLabeler.component.html       | 125 ------
 .../core-ui/imageLabeler/imageLabeler.component.ts | 424 ---------------------
 .../app/data-explorer/data-explorer.component.html |   4 +-
 43 files changed, 1942 insertions(+), 1447 deletions(-)

diff --git a/ui/package.json b/ui/package.json
index 113310f..d25c2d3 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -87,7 +87,6 @@
     "ngmap": "1.18.0",
     "ngx-color-picker": "^9.0.0",
     "plotly.js": "^1.52.2",
-    "point-in-polygon": "1.0.1",
     "prismjs": "^1.19.0",
     "rxjs": "^6.5.4",
     "rxjs-compat": "^6.5.4",
diff --git a/ui/src/app/CustomMaterial/custom-material.module.ts b/ui/src/app/CustomMaterial/custom-material.module.ts
index cddada0..e6514ca 100644
--- a/ui/src/app/CustomMaterial/custom-material.module.ts
+++ b/ui/src/app/CustomMaterial/custom-material.module.ts
@@ -16,12 +16,15 @@
  *
  */
 
-import {NgModule} from '@angular/core';
+import { NgModule } from '@angular/core';
 
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
 import { MatButtonModule } from '@angular/material/button';
 import { MatButtonToggleModule } from '@angular/material/button-toggle';
 import { MatCardModule } from '@angular/material/card';
 import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatDialogModule } from '@angular/material/dialog';
 import { MatDividerModule } from '@angular/material/divider';
 import { MatExpansionModule } from '@angular/material/expansion';
 import { MatIconModule } from '@angular/material/icon';
@@ -30,19 +33,17 @@ import { MatListModule } from '@angular/material/list';
 import { MatMenuModule } from '@angular/material/menu';
 import { MatPaginatorModule } from '@angular/material/paginator';
 import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatRadioModule } from '@angular/material/radio';
 import { MatSelectModule } from '@angular/material/select';
 import { MatSidenavModule } from '@angular/material/sidenav';
 import { MatSlideToggleModule } from '@angular/material/slide-toggle';
+import { MatSliderModule } from '@angular/material/slider';
 import { MatSortModule } from '@angular/material/sort';
+import { MatStepperModule } from '@angular/material/stepper';
+import { MatTableModule } from '@angular/material/table';
 import { MatTabsModule } from '@angular/material/tabs';
 import { MatToolbarModule } from '@angular/material/toolbar';
-import {MatStepperModule} from '@angular/material/stepper';
-import {MatRadioModule} from '@angular/material/radio';
-import {MatTableModule} from '@angular/material/table';
-import {MatAutocompleteModule} from '@angular/material/autocomplete';
-import {MatDialogModule} from '@angular/material/dialog';
-import {MatTooltipModule} from '@angular/material/tooltip';
-import { MatChipsModule } from "@angular/material/chips";
+import { MatTooltipModule } from '@angular/material/tooltip';
 
 
 @NgModule({
@@ -73,7 +74,8 @@ import { MatChipsModule } from "@angular/material/chips";
         MatTooltipModule,
         MatProgressBarModule,
         MatButtonToggleModule,
-        MatChipsModule
+        MatChipsModule,
+        MatSliderModule
     ],
     exports: [
         MatButtonModule,
@@ -100,7 +102,8 @@ import { MatChipsModule } from "@angular/material/chips";
         MatTooltipModule,
         MatProgressBarModule,
         MatButtonToggleModule,
-        MatChipsModule
+        MatChipsModule,
+        MatSliderModule
     ]
 })
 export class CustomMaterialModule {
diff --git a/ui/src/app/core-model/coco/Annotation.ts b/ui/src/app/core-model/coco/Annotation.ts
index 1ebc566..ce76d22 100644
--- a/ui/src/app/core-model/coco/Annotation.ts
+++ b/ui/src/app/core-model/coco/Annotation.ts
@@ -2,28 +2,34 @@ export class Annotation {
   id: number;
   image_id: number;
   category_id: number;
-  segmentation: [any]; //RLE or [polygon] -> polygon [[x1,y1,x2,y2,... xn, yn]]
+  segmentation: [any]; // RLE or [polygon] -> polygon [[x1,y1,x2,y2,... xn, yn]]
   area: number;
-  bbox: [number,number,number,number]; //[x,y,width,height]
-  iscrowd: number; //(iscrowd=0 in which case polygons are used) or a collection of objects (iscrowd=1 in which case RLE is used)
+  bbox: [number, number, number, number]; // [x,y,width,height]
+  iscrowd: number; // (iscrowd=0 in which case polygons are used) or a collection of objects (iscrowd=1 in which case RLE is used)
+  brushSize: number [];
 
-  //For UI
-  isSelected: boolean = false;
-  isHovered: boolean = false;
 
+  // For UI
+  isSelected = false;
+  isHovered = false;
+  category_name: string;
 
   constructor() {
     this.segmentation = undefined;
     this.bbox = undefined;
+    this.brushSize = undefined;
   }
 
   isBox() {
     return this.bbox !== undefined;
   }
 
-
   isPolygon() {
-    return this.segmentation !== undefined;
+    return this.segmentation !== undefined && this.brushSize === undefined;
+  }
+
+  isBrush() {
+    return this.brushSize !== undefined;
   }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-model/coco/Coco.format.ts b/ui/src/app/core-model/coco/Coco.format.ts
index 43c4571..160c6b1 100644
--- a/ui/src/app/core-model/coco/Coco.format.ts
+++ b/ui/src/app/core-model/coco/Coco.format.ts
@@ -1,66 +1,82 @@
-import { Image } from "./Image";
-import { Annotation } from "./Annotation";
-import { Category } from "./Category";
+import { Annotation } from './Annotation';
+import { Category } from './Category';
+import { Image } from './Image';
 
 export class CocoFormat {
 
-
-  info : {
-    "year": number,
-    "version": String,
-    "description": String,
-    "contributor": String,
-    "url": String,
-    "date_created": Date,
+  info: {
+    'year': number,
+    'version': string,
+    'description': string,
+    'contributor': string,
+    'url': string,
+    'date_created': Date,
   };
   licenses: [];
   images: Image[] = [];
   annotations: Annotation[] = [];
   categories: Category[] = [];
 
-  constructor(file_name, width, height) {
-    let image = new Image();
-    image.file_name = file_name;
-    image.height = height;
-    image.width = width;
-    this.images.push(image)
+  constructor() { }
+
+  addImage(fileName) {
+      const image = new Image();
+      image.file_name = fileName;
+      image.id = this.images.length + 1;
+      this.images.push(image);
   }
 
   getLabelById(id) {
-    return this.categories.find(elem => elem.id == id).name;
+    return this.categories.find(elem => elem.id === id).name;
   }
 
-  getLabelId(name, supercategory): number {
-    let category = this.categories.find(elem => elem.name == name && elem.supercategory == supercategory);
+  getLabelId(supercategory, name): number {
+    let category = this.categories.find(elem => elem.name === name && elem.supercategory === supercategory);
     if (category === undefined) {
       category = new Category(this.categories.length + 1, name, supercategory);
-      this.categories.push(category)
+      this.categories.push(category);
     }
     return category.id;
   }
 
-  addReactAnnotation(x, y, width, height, categoryId) {
-    let annnotation = new Annotation();
-    annnotation.id = this.annotations.length + 1;
-    annnotation.iscrowd = 0;
-    annnotation.image_id = 1;
-    annnotation.bbox = [x, y, width, height];
-    annnotation.category_id = categoryId;
-    this.annotations.push(annnotation)
+  addReactAnnotationToFirstImage(cords, size, supercategory, category): Annotation {
+    const annotation = new Annotation();
+    annotation.id = this.annotations.length + 1;
+    annotation.iscrowd = 0;
+    annotation.image_id = 1;
+    annotation.bbox = [cords.x, cords.y, size.x, size.y];
+    annotation.category_id = this.getLabelId(supercategory, category);
+    annotation.category_name = category;
+    this.annotations.push(annotation);
+    return annotation;
+  }
+
+  addPolygonAnnotationFirstImage(points, supercategory, category): Annotation {
+    const annotation = new Annotation();
+    annotation.id = this.annotations.length + 1;
+    annotation.iscrowd = 0;
+    annotation.image_id = 1;
+    annotation.segmentation = [points];
+    annotation.category_id = this.getLabelId(supercategory, category);
+    annotation.category_name = category;    this.annotations.push(annotation);
+    return annotation;
   }
 
-  addPolygonAnnotation(points, categoryId) {
-    let annnotation = new Annotation();
-    annnotation.id = this.annotations.length + 1;
-    annnotation.iscrowd = 0;
-    annnotation.image_id = 1;
-    annnotation.segmentation = [points];
-    annnotation.category_id = categoryId;
-    this.annotations.push(annnotation)
+  addBrushAnnotationFirstImage(points, brushSize, supercategory, category): Annotation {
+    const annotation = new Annotation();
+    annotation.id = this.annotations.length + 1;
+    annotation.iscrowd = 0;
+    annotation.image_id = 1;
+    annotation.segmentation = [points];
+    annotation.brushSize = brushSize;
+    annotation.category_id = this.getLabelId(supercategory, category);
+    annotation.category_name = category;
+    this.annotations.push(annotation);
+    return annotation;
   }
 
   removeAnnotation(id) {
     this.annotations = this.annotations.filter(anno => anno.id !== id);
   }
 
-}
\ No newline at end of file
+}
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 a041d70..5550dbf 100644
--- a/ui/src/app/core-services/datalake/datalake-rest.service.ts
+++ b/ui/src/app/core-services/datalake/datalake-rest.service.ts
@@ -16,13 +16,13 @@
  *
  */
 
-import {HttpClient, HttpRequest} from '@angular/common/http';
-import {InfoResult} from '../../core-model/datalake/InfoResult';
-import {AuthStatusService} from '../../services/auth-status.service';
-import {Injectable} from '@angular/core';
-import {PageResult} from '../../core-model/datalake/PageResult';
-import {DataResult} from '../../core-model/datalake/DataResult';
-import {GroupedDataResult} from '../../core-model/datalake/GroupedDataResult';
+import { HttpClient, HttpRequest } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { DataResult } from '../../core-model/datalake/DataResult';
+import { GroupedDataResult } from '../../core-model/datalake/GroupedDataResult';
+import { InfoResult } from '../../core-model/datalake/InfoResult';
+import { PageResult } from '../../core-model/datalake/PageResult';
+import { AuthStatusService } from '../../services/auth-status.service';
 
 @Injectable()
 export class DatalakeRestService {
@@ -36,12 +36,12 @@ export class DatalakeRestService {
     }
 
     private get dataLakeUrlV3() {
-        return this.baseUrl + '/api/v3/users/' + this.authStatusService.email + '/datalake'
+        return this.baseUrl + '/api/v3/users/' + this.authStatusService.email + '/datalake';
     }
 
 
     getAllInfos() {
-        return this.http.get<InfoResult[]>(this.dataLakeUrlV3 + "/info");
+        return this.http.get<InfoResult[]>(this.dataLakeUrlV3 + '/info');
     }
 
     getDataPage(index, itemsPerPage, page) {
@@ -81,28 +81,28 @@ export class DatalakeRestService {
         @deprecate
      */
     getFile(index, format) {
-        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + "?format=" + format,  {
+        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + '?format=' + format,  {
             reportProgress: true,
             responseType: 'text'
         });
-        return this.http.request(request)
+        return this.http.request(request);
     }
 
     downloadRowData(index, format) {
-        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + "/download?format=" + format,  {
+        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + '/download?format=' + format,  {
             reportProgress: true,
             responseType: 'text'
         });
-        return this.http.request(request)
+        return this.http.request(request);
     }
 
     downloadRowDataTimeInterval(index, format, startDate, endDate) {
-        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + '/' + startDate + '/' + endDate + "/download" +
-            "?format=" + format, {
+        const request = new HttpRequest('GET', this.dataLakeUrlV3 + '/data/' + index + '/' + startDate + '/' + endDate + '/download' +
+            '?format=' + format, {
             reportProgress: true,
             responseType: 'text'
         });
-        return this.http.request(request)
+        return this.http.request(request);
     }
 
     getImageSrcs() {
@@ -122,17 +122,17 @@ export class DatalakeRestService {
 
     getLabels() {
         return {
-          "person": ["person"],
-          "vehicle": ["bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat"],
-          "outdoor": ["traffic light", "fire hydrant", "stop sign", "parking meter", "bench"],
-          "animal": ["bird", "cat", "dog"],
-          "accessory": ["backpack", "umbrella", "handbag", "suitcase"],
-          "sports": ["frisbee", "sports ball", "skis", "frisbee", "baseball bat"],
-          "kitchen": ["bottle", "cup", "fork", "knife", "spoon"],
-          "furniture": ["chair", "couch", "bed", "table"],
-          "electronic": ["tv", "laptop", "mouse", "keyboard"]
-        }
+          'person': ['person', 'Child'],
+          'vehicle': ['bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat'],
+          'outdoor': ['traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench'],
+          'animal': ['bird', 'cat', 'dog'],
+          'accessory': ['backpack', 'umbrella', 'handbag', 'suitcase'],
+          'sports': ['frisbee', 'sports ball', 'skis', 'frisbee', 'baseball bat'],
+          'kitchen': ['bottle', 'cup', 'fork', 'knife', 'spoon'],
+          'furniture': ['chair', 'couch', 'bed', 'table'],
+          'electronic': ['tv', 'laptop', 'mouse', 'keyboard']
+        };
     }
 
 
-}
\ 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 a6ad29b..dfdd7d9 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -16,26 +16,35 @@
  *
  */
 
-import {NgModule} from '@angular/core';
-import {FlexLayoutModule} from '@angular/flex-layout';
-import {CommonModule} from '@angular/common';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FlexLayoutModule } from '@angular/flex-layout';
 
-import {CustomMaterialModule} from '../CustomMaterial/custom-material.module';
-import {FormsModule, ReactiveFormsModule} from '@angular/forms';
-import {CdkTableModule} from '@angular/cdk/table';
+import { CdkTableModule } from '@angular/cdk/table';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { MatNativeDateModule } from '@angular/material/core';
 import { MatDatepickerModule } from '@angular/material/datepicker';
 import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 import { MatSnackBarModule } from '@angular/material/snack-bar';
-import {TableComponent} from './table/table.component';
-import {LineChartComponent} from './linechart/lineChart.component';
+import { CustomMaterialModule } from '../CustomMaterial/custom-material.module';
+import { LineChartComponent } from './linechart/lineChart.component';
+import { TableComponent } from './table/table.component';
 
-//import * as PlotlyJS from 'plotly.js/dist/plotly.js';
+// import * as PlotlyJS from 'plotly.js/dist/plotly.js';
 import { PlotlyViaWindowModule } from 'angular-plotly.js';
-import { ImageLabelerComponent } from "./imageLabeler/imageLabeler.component";
-import { ImageAnnotation } from "./imageLabeler/annotation/imageAnnotation";
-import { ImageClassification } from "./imageLabeler/classification/imageClassification";
-//PlotlyViaCDNModule.plotlyjs = PlotlyJS;
+import { ImageAnnotationsComponent } from './image/components/image-annotations/image-annotations.component';
+import { ImageBarComponent } from './image/components/image-bar/image-bar.component';
+import { ImageContainerComponent } from './image/components/image-container/image-container.component';
+import { ImageLabelsComponent } from './image/components/image-labels/image-labels.component';
+import { ImageCategorizeComponent } from './image/image-categorize/image-categorize.component';
+import { ImageLabelingComponent } from './image/image-labeling/image-labeling.component';
+import { ImageComponent } from './image/image.component';
+import { BrushLabelingService } from './image/services/BrushLabeling.service';
+import { ColorService } from './image/services/color.service';
+import { PolygonLabelingService } from './image/services/PolygonLabeling.service';
+import { ReactLabelingService } from './image/services/ReactLabeling.service';
+import { ImageViewerComponent } from './image/image-viewer/image-viewer.component';
+// PlotlyViaCDNModule.plotlyjs = PlotlyJS;
 
 @NgModule({
     imports: [
@@ -54,20 +63,30 @@ import { ImageClassification } from "./imageLabeler/classification/imageClassifi
     declarations: [
         TableComponent,
         LineChartComponent,
-        ImageLabelerComponent,
+        ImageComponent,
+        ImageContainerComponent,
+        ImageLabelingComponent,
+        ImageLabelsComponent,
+        ImageBarComponent,
+        ImageAnnotationsComponent,
+        ImageCategorizeComponent,
+        ImageViewerComponent,
     ],
     providers: [
         MatDatepickerModule,
-        ImageAnnotation,
-        ImageClassification
+        ColorService,
+        ReactLabelingService,
+        PolygonLabelingService,
+        BrushLabelingService,
     ],
     entryComponents: [
     ],
     exports: [
         TableComponent,
         LineChartComponent,
-        ImageLabelerComponent,
+        ImageComponent,
+        ImageLabelingComponent,
     ]
 })
 export class CoreUiModule {
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.css b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.css
similarity index 70%
copy from ui/src/app/core-ui/imageLabeler/imageLabeler.component.css
copy to ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.css
index d8f0592..8e48f10 100644
--- a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.css
+++ b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.css
@@ -15,30 +15,6 @@
  * limitations under the License.
  *
  */
-canvas {
-    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAIUlEQVQoU2NkYGCQYiACMEIVPiOgVmpUIb4QggcPwSAHAJ3ICQ/mI97EAAAAAElFTkSuQmCC);
-    background-color: #fafafa;
-    border-color: lightgrey;
-    border-style: solid;
-}
-
-.controlButtons {
-    top: 30px;
-}
-
-.imageBar {
-    height: 70px;
-    background-color: lightgrey;
-}
-
-img {
-    max-height: 100%;
-    margin: 5px;
-}
-
-labelCategorySelectContainer {
-
-}
 
 .mat-list-item {
     height: 5px;
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
new file mode 100644
index 0000000..feedf72
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.html
@@ -0,0 +1,38 @@
+<!--
+  ~ 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" fxLayoutAlign="space-between center">
+    <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.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-optgroup *ngFor="let category of categories" [label]="category">
+                        <mat-option *ngFor="let label of _labels[category]" [value]="label" (click)="changeLabel(annotation, label, category)">
+                            {{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>
+        </mat-list-item>
+    </mat-list>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.ts b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.ts
new file mode 100644
index 0000000..2fd7dca
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-annotations/image-annotations.component.ts
@@ -0,0 +1,63 @@
+/*
+ * 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, Input, OnInit, Output } from '@angular/core';
+import { Annotation } from '../../../../core-model/coco/Annotation';
+import { ColorService } from '../../services/color.service';
+
+@Component({
+  selector: 'sp-image-annotations',
+  templateUrl: './image-annotations.component.html',
+  styleUrls: ['./image-annotations.component.css']
+})
+export class ImageAnnotationsComponent implements OnInit {
+
+  @Input() annotations: Annotation[];
+  @Input()
+  set labels(labels) {
+    this._labels = labels;
+    this.categories = Object.keys(this._labels);
+  }
+  @Output() changeAnnotationLabel: EventEmitter<[Annotation, string, string]> = new EventEmitter<[Annotation, string, string]>();
+  @Output() deleteAnnotation: EventEmitter<Annotation> = new EventEmitter<Annotation>();
+
+  private _labels;
+  private categories;
+
+  constructor(public colorService: ColorService) { }
+
+  ngOnInit(): void {
+  }
+
+  changeLabel(annotation, label, category) {
+    this.changeAnnotationLabel.emit([annotation, category, label]);
+  }
+
+  delete(annotation) {
+    this.deleteAnnotation.emit(annotation);
+  }
+
+  enterAnnotation(annotation) {
+    annotation.isHovered = true;
+  }
+
+  leaveAnnotation(annotation) {
+    annotation.isHovered = false;
+  }
+
+}
diff --git a/ui/src/app/core-ui/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
similarity index 85%
copy from ui/src/app/core-ui/imageLabeler/interactionMode.ts
copy to ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
index 8ffb4bb..a4868af 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.css
@@ -6,17 +6,16 @@
  * (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.
+ *
  */
 
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
+.imageBar {
+    height: 70px;
 }
\ No newline at end of file
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
similarity index 54%
copy from ui/src/app/data-explorer/data-explorer.component.html
copy to ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
index 778be74..e8f31dd 100644
--- a/ui/src/app/data-explorer/data-explorer.component.html
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.html
@@ -16,21 +16,17 @@
   ~
   -->
 
-<div flex class="page-container page-container-padding" style="height: 1px">
-    <div flex="100" layout="column" style="padding:0px;background-color:#f6f6f6; display: inline-block; width: 100%;" >
-        <div flex layout-fill layout="row" layout-align="start center"
-             style="height:48px;padding-left:10px;font-size:14px;line-height:24px;border-bottom:1px solid #ccc">
-            <label style="font-size: 30px; padding-top: 10px;">Data Explorer</label>
-        </div>
-    </div>
-
-    <div class="container-fluid">
-
-        <sp-image-labeler></sp-image-labeler>
+<div fxLayout="row" fxLayoutAlign="space-around center" >
+    <button mat-icon-button (click)="previousPage()"> <mat-icon>skip_previous</mat-icon></button>
+    <button mat-icon-button (click)="previousImage()"> <mat-icon>keyboard_arrow_left</mat-icon></button>
 
+    <div fxLayout="row" fxLayoutAlign="center " class="imageBar">
+        <img *ngFor="let src of imagesSrcs; let i = index" src="{{src}}" (click)="changeImage(i)"
+             [style.border]="i == selectedIndex ? '5px solid #39b54a' : 'none'" style="height: 65px">
+    </div>
 
 
+    <button mat-icon-button (click)="nextImage()"> <mat-icon>keyboard_arrow_right</mat-icon></button>
+    <button mat-icon-button (click)="nextPage()"> <mat-icon>skip_next</mat-icon></button>
 
-        <!--    <sp-explorer></sp-explorer> -->
-    </div>
 </div>
diff --git a/ui/src/app/core-ui/image/components/image-bar/image-bar.component.ts b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.ts
new file mode 100644
index 0000000..cb880d9
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-bar/image-bar.component.ts
@@ -0,0 +1,82 @@
+/*
+ * 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, HostListener, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+  selector: 'sp-image-bar',
+  templateUrl: './image-bar.component.html',
+  styleUrls: ['./image-bar.component.css']
+})
+export class ImageBarComponent implements OnInit {
+
+  @Input() imagesSrcs: string [];
+  @Input() selectedIndex: number;
+  @Input() enableShortCuts: boolean;
+
+  @Output() indexChange: EventEmitter<number> = new EventEmitter<number>();
+  @Output() pageUp: EventEmitter<void> = new EventEmitter<void>();
+  @Output() pageDown: EventEmitter<void> = new EventEmitter<void>();
+
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+  changeImage(index) {
+    this.indexChange.emit(index);
+  }
+
+  previousPage() {
+    this.pageDown.emit();
+
+  }
+  previousImage() {
+    if (this.selectedIndex > 0) {
+      this.indexChange.emit(this.selectedIndex - 1);
+    } else {
+      this.pageDown.emit();
+    }
+  }
+  nextImage() {
+    if (this.selectedIndex < this.imagesSrcs.length - 1) {
+      this.indexChange.emit(this.selectedIndex + 1);
+    } else {
+      this.pageUp.emit();
+    }
+  }
+  nextPage() {
+   this.pageUp.emit();
+  }
+
+  @HostListener('document:keydown', ['$event'])
+  handleShortCuts(event: KeyboardEvent) {
+    if (this.enableShortCuts) {
+      const key = event.key;
+      switch (key.toLowerCase()) {
+        case 'q':
+          this.previousImage();
+          break;
+        case 'e':
+          this.nextImage();
+          break;
+      }
+    }
+  }
+
+}
diff --git a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.css b/ui/src/app/core-ui/image/components/image-container/image-container.component.css
similarity index 69%
rename from ui/src/app/core-ui/imageLabeler/imageLabeler.component.css
rename to ui/src/app/core-ui/image/components/image-container/image-container.component.css
index d8f0592..612fce8 100644
--- a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.css
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.css
@@ -15,43 +15,11 @@
  * limitations under the License.
  *
  */
-canvas {
+.canvas-container {
     background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAIUlEQVQoU2NkYGCQYiACMEIVPiOgVmpUIb4QggcPwSAHAJ3ICQ/mI97EAAAAAElFTkSuQmCC);
     background-color: #fafafa;
     border-color: lightgrey;
     border-style: solid;
-}
-
-.controlButtons {
-    top: 30px;
-}
-
-.imageBar {
-    height: 70px;
-    background-color: lightgrey;
-}
-
-img {
-    max-height: 100%;
-    margin: 5px;
-}
-
-labelCategorySelectContainer {
-
-}
-
-.mat-list-item {
-    height: 5px;
-}
-
-::ng-deep .mat-form-field-underline {
-    background-color: rgba(255, 255, 255, 0.8);
-}
-
-::ng-deep .mat-optgroup-label {
-    background-color: #FFFFFF !important;
-}
-
-::ng-deep .mat-option {
-    background-color: #FFFFFF !important;
+    height: 500px;
+    width: 800px;
 }
\ No newline at end of file
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/core-ui/image/components/image-container/image-container.component.html
similarity index 56%
copy from ui/src/app/data-explorer/data-explorer.component.html
copy to ui/src/app/core-ui/image/components/image-container/image-container.component.html
index 778be74..b204c11 100644
--- a/ui/src/app/data-explorer/data-explorer.component.html
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.html
@@ -15,22 +15,6 @@
   ~ limitations under the License.
   ~
   -->
-
-<div flex class="page-container page-container-padding" style="height: 1px">
-    <div flex="100" layout="column" style="padding:0px;background-color:#f6f6f6; display: inline-block; width: 100%;" >
-        <div flex layout-fill layout="row" layout-align="start center"
-             style="height:48px;padding-left:10px;font-size:14px;line-height:24px;border-bottom:1px solid #ccc">
-            <label style="font-size: 30px; padding-top: 10px;">Data Explorer</label>
-        </div>
-    </div>
-
-    <div class="container-fluid">
-
-        <sp-image-labeler></sp-image-labeler>
-
-
-
-
-        <!--    <sp-explorer></sp-explorer> -->
-    </div>
+<div class="canvas-container">
+    <div id="canvas-container"  (dblclick)="dblclick($event)"></div>
 </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
new file mode 100644
index 0000000..7667a8f
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-container/image-container.component.ts
@@ -0,0 +1,268 @@
+/*
+ * 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 { 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({
+  selector: 'sp-image-container',
+  templateUrl: './image-container.component.html',
+  styleUrls: ['./image-container.component.css']
+})
+export class ImageContainerComponent implements OnInit, AfterViewInit {
+
+  @Input()
+  set imageSrc(src) {
+    this.loadImage(src);
+  }
+
+  @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]>();
+
+
+  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 isRightMouseDown: boolean;
+
+  private isHoverComponent: boolean;
+
+  constructor() { }
+
+  ngOnInit(): void {
+    this.scale = 1;
+    this.imageShift = {x: 0, y: 0};
+    this.isLeftMouseDown = false;
+    this.isRightMouseDown = false;
+    this.isHoverComponent = false;
+  }
+
+  ngAfterViewInit(): void {
+    this.reset();
+  }
+
+  reset() {
+    this.scale = 1;
+    this.imageShift = {x: 0, y: 0};
+    // TODO fit to parent
+    this.mainCanvasStage = new Konva.Stage({
+      container: 'canvas-container',
+      width: 800,
+      height: 500
+    });
+    this.registerEventHandler();
+
+  }
+
+  loadImage(src) {
+    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 = src;
+  }
+
+  getShift() {
+    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
+
+    } else if (button === 3) {
+      // right click
+      this.isRightMouseDown = true;
+      this.mainCanvasStage.container().style.cursor = 'move';
+      this.lastImagePointerPosition = this.getImagePointerPosition();
+      this.lastImageTranslation = this.imageShift;
+    }
+  }
+
+  imageMouseMove(e) {
+    if (this.isLeftMouseDown) {
+      this.drawLayer.destroyChildren();
+      this.mouseMoveLeft.emit([this.drawLayer, this.getShift(), this.getImagePointerPosition()]);
+      this.drawLayer.batchDraw();
+    } else if (this.isRightMouseDown) {
+      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.isRightMouseDown) {
+      this.isRightMouseDown = false;
+      this.mainCanvasStage.container().style.cursor = 'default';
+    }
+  }
+
+  dblclick (e) {
+    this.drawLayer.destroyChildren();
+    this.drawLayer.batchDraw();
+    this.dbclick.emit([this.annotationLayer, this.getShift(), this.getImagePointerPosition()]);
+    this.annotationLayer.batchDraw();
+  }
+
+  /* Draw */
+
+  redrawAll() {
+    this.drawLayer.destroyChildren();
+    this.annotationLayer.destroyChildren();
+    this.childRedraw.emit([this.annotationLayer, this.getShift()]);
+    this.shiftViewContent();
+  }
+
+  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/imageLabeler/annotation/annotationMode.ts b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.css
similarity index 70%
copy from ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
copy to ui/src/app/core-ui/image/components/image-labels/image-labels.component.css
index 9162ba3..fc51d70 100644
--- a/ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
+++ b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.css
@@ -6,18 +6,28 @@
  * (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.
+ *
  */
 
-export enum AnnotationMode {
-  ReactLabeling,
-  ReactResize,
-  PolygonLabeling,
-  PolygonTransform,
+.mat-list-item {
+    height: 5px;
+}
+
+::ng-deep .mat-form-field-underline {
+    background-color: rgba(255, 255, 255, 0.8);
 }
+
+::ng-deep .mat-opt .group-label {
+    background-color: #FFFFFF !important;
+}
+
+::ng-deep .mat-option {
+    background-color: #FFFFFF !important;
+}
\ No newline at end of file
diff --git a/ui/src/app/core-ui/image/components/image-labels/image-labels.component.html b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.html
new file mode 100644
index 0000000..a041e44
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.html
@@ -0,0 +1,39 @@
+<!--
+  ~ 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" fxLayoutAlign="space-around center">
+
+    <h2>Labels</h2>
+    <div style="padding-left: 5px; padding-right: 5px; border-radius: 50px; font-size: 20px;">
+        <mat-form-field style="margin-top: -15px; margin-bottom: -10px">
+            <mat-select [(value)]="selectedCategory">
+                <mat-option *ngFor="let category of categories" [value]="category">
+                    {{category}}
+                </mat-option>
+            </mat-select>
+        </mat-form-field>
+    </div>
+    <mat-list>
+        <mat-list-item *ngFor="let label of _labels[selectedCategory]; index as i"
+                       [style.background-color]="_selectedLabel.label == label ? 'lightgrey' : 'white'"
+                       style="height: 30px; padding-top: 5px; padding-buttom: 5px; border-radius: 50px; margin-bottom: 5px"
+                       (click)="selectLabel({category: labelCategory, label: label})">
+            <mat-icon matListIcon [style.color]="colorService.getColor(label)" style="margin-top: -8px;">color_lens</mat-icon>
+            <h4 style="margin-top: -3px;"> {{label}} <label *ngIf="i < 10"> #{{i+1}}</label> </h4>
+        </mat-list-item>
+    </mat-list>
+</div>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/image/components/image-labels/image-labels.component.ts b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.ts
new file mode 100644
index 0000000..ea8948a
--- /dev/null
+++ b/ui/src/app/core-ui/image/components/image-labels/image-labels.component.ts
@@ -0,0 +1,55 @@
+import { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core';
+import { ColorService } from "../../services/color.service";
+
+@Component({
+  selector: 'sp-image-labels',
+  templateUrl: './image-labels.component.html',
+  styleUrls: ['./image-labels.component.css']
+})
+export class ImageLabelsComponent implements OnInit {
+
+  @Input()
+  set labels(labels) {
+    this._labels = labels;
+    this.update();
+  }
+  @Input() enableShortCuts: boolean;
+  @Output() labelChange: EventEmitter<{category, label}> = new EventEmitter<{category, label}>();
+
+  public _labels;
+  public _selectedLabel: {category, label};
+  public categories;
+  public selectedCategory;
+
+  constructor(public colorService: ColorService) { }
+
+  ngOnInit(): void {
+
+  }
+
+  update() {
+    this.categories = Object.keys(this._labels);
+    this.selectedCategory = this.categories[0];
+    this._selectedLabel = {category: this.selectedCategory, label: this._labels[this.selectedCategory][0]};
+    this.labelChange.emit(this._selectedLabel);
+  }
+
+  selectLabel(e: {category, label}) {
+    this._selectedLabel = e;
+    this.labelChange.emit(this._selectedLabel);
+  }
+
+  @HostListener('document:keydown', ['$event'])
+  handleShortCuts(event: KeyboardEvent) {
+    if (this.enableShortCuts) {
+      if (event.code.toLowerCase().includes('digit')) {
+        // Number
+        const value = Number(event.key);
+        if (value !== 0 && value <= this._labels[this.selectedCategory].length) {
+          this.selectLabel({category: this.selectedCategory, label: this._labels[this.selectedCategory][value - 1]});
+        }
+      }
+    }
+  }
+
+}
diff --git a/ui/src/app/core-ui/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.css
similarity index 85%
copy from ui/src/app/core-ui/imageLabeler/interactionMode.ts
copy to ui/src/app/core-ui/image/image-categorize/image-categorize.component.css
index 8ffb4bb..41ecef0 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.css
@@ -6,17 +6,12 @@
  * (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.
- */
-
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
-}
\ No newline at end of file
+ *
+ */
\ No newline at end of file
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
new file mode 100644
index 0000000..01ce6ff
--- /dev/null
+++ b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.html
@@ -0,0 +1,55 @@
+<!--
+  ~ 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>
+
+    <div fxLayout="column" fxLayoutAlign="space-between " >
+        <div  fxLayout="row" fxLayoutAlign="space-around start">
+
+            <sp-image-labels
+                    [labels]="labels"
+                    [enableShortCuts]="true"
+                    (labelChange)="handleLabelChange($event)">
+            </sp-image-labels>
+
+            <div fxLayout="column" fxLayoutAlign="space-between " >
+                <div fxLayout="row" fxLayoutAlign="center center" >
+                    <mat-chip-list style="margin-bottom: 3px; min-height: 40px;">
+                        <mat-chip *ngFor="let label of selectedLabels" [style.background-color]="colorService.getColor(label.label)"
+                                  (removed)="remove(label)">
+                            {{label.label}}
+                            <mat-icon matChipRemove>cancel</mat-icon>
+                        </mat-chip>
+                    </mat-chip-list>
+                </div>
+                <sp-image-container
+                        [imageSrc]="imagesSrcs[imagesIndex]">
+                </sp-image-container>
+            </div>
+        </div>
+        <br />
+        <br />
+        <sp-image-bar style="width: 100%"
+                      [imagesSrcs]="imagesSrcs"
+                      [selectedIndex]="imagesIndex"
+                      [enableShortCuts]="true"
+                      (indexChange)="handleImageIndexChange($event)"
+                      (pageUp)="handleImagePageUp($event)"
+                      (pageDown)="handleImagePageDown($event)">
+        </sp-image-bar>
+    </div>
+</div>
diff --git a/ui/src/app/core-ui/image/image-categorize/image-categorize.component.ts b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.ts
new file mode 100644
index 0000000..a396298
--- /dev/null
+++ b/ui/src/app/core-ui/image/image-categorize/image-categorize.component.ts
@@ -0,0 +1,101 @@
+/*
+ * 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 { AfterViewInit, Component, OnInit } from "@angular/core";
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { DatalakeRestService } from '../../../core-services/datalake/datalake-rest.service';
+import { ColorService } from "../services/color.service";
+
+
+@Component({
+  selector: 'sp-image-categorize',
+  templateUrl: './image-categorize.component.html',
+  styleUrls: ['./image-categorize.component.css']
+})
+export class ImageCategorizeComponent implements OnInit, AfterViewInit {
+
+  // label
+  public labels;
+  public selectedLabels;
+
+  // images
+  public imagesSrcs;
+  public imagesIndex: number;
+
+  constructor(private restService: DatalakeRestService, public colorService: ColorService, private snackBar: MatSnackBar) { }
+
+  ngOnInit(): void {
+    this.selectedLabels = [];
+
+    // 1. get labels
+    this.labels = this.restService.getLabels();
+
+    // 2. get Images
+    this.imagesSrcs = this.restService.getImageSrcs();
+  }
+
+
+  ngAfterViewInit(): void {
+    this.selectedLabels = [];
+    this.imagesIndex = 0;
+  }
+
+  /* sp-image-view handler */
+
+
+  /* sp-image-labels handler */
+  handleLabelChange(label: {category, label}) {
+    this.selectedLabels.push(label);
+  }
+
+  /* sp-image-bar */
+  handleImageIndexChange(index) {
+    this.save();
+    this.selectedLabels = [];
+    this.imagesIndex = index;
+  }
+  handleImagePageUp(e) {
+    this.save();
+    this.selectedLabels = [];
+    alert('Page Up - Load new data');
+  }
+
+  handleImagePageDown(e) {
+    this.save();
+    this.selectedLabels = [];
+    alert('Page Down - Load new data');
+  }
+
+  remove(label) {
+    this.selectedLabels = this.selectedLabels.filter(l => l.label !== label.label);
+  }
+
+  private save() {
+    // TODO
+    this.openSnackBar('TODO: Save save class');
+  }
+
+  private openSnackBar(message: string) {
+    this.snackBar.open(message, '', {
+      duration: 2000,
+      verticalPosition: 'top',
+      horizontalPosition: 'right'
+    });
+  }
+
+
+}
diff --git a/ui/src/app/core-ui/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.css
similarity index 85%
copy from ui/src/app/core-ui/imageLabeler/interactionMode.ts
copy to ui/src/app/core-ui/image/image-labeling/image-labeling.component.css
index 8ffb4bb..41ecef0 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.css
@@ -6,17 +6,12 @@
  * (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.
- */
-
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
-}
\ No newline at end of file
+ *
+ */
\ No newline at end of file
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
new file mode 100644
index 0000000..954c33a
--- /dev/null
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.html
@@ -0,0 +1,68 @@
+<!--
+  ~ 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 (mouseover)="isHoverComponent = true" (mouseout)="isHoverComponent = false">
+
+    <div fxLayout="column" fxLayoutAlign="space-between " >
+        <div  fxLayout="row" fxLayoutAlign="space-around start">
+
+            <sp-image-labels
+                    [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>
+                    <mat-slider [min]="1"  [max]="50" [step]="1" [thumbLabel]="true" [(ngModel)]="brushSize"></mat-slider>
+                </div>
+
+                <sp-image-container
+                        [imageSrc]="imagesSrcs[imagesIndex]"
+                        (childRedraw)="handleChildRedraw($event[0], $event[1])"
+                        (mouseDownLeft)="handleMouseDownLeft($event[0], $event[1], $event[2])"
+                        (mouseMove)="handleMouseMove($event[0], $event[1], $event[2])"
+                        (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])">
+                </sp-image-container>
+            </div>
+
+            <sp-image-annotations
+                    [annotations]="this.cocoFiles[this.imagesIndex].annotations"
+                    [labels]="labels"
+                    (changeAnnotationLabel)="handleChangeAnnotationLabel($event)"
+                    (deleteAnnotation)="handleDeleteAnnotation($event)">
+            </sp-image-annotations>
+        </div>
+        <br />
+        <br />
+        <sp-image-bar style="width: 100%"
+                [imagesSrcs]="imagesSrcs"
+                [selectedIndex]="imagesIndex"
+                [enableShortCuts]="isHoverComponent"
+                (indexChange)="handleImageIndexChange($event)"
+                (pageUp)="handleImagePageUp($event)"
+                (pageDown)="handleImagePageDown($event)">
+        </sp-image-bar>
+    </div>
+</div>
\ No newline at end of file
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
new file mode 100644
index 0000000..42fbd2d
--- /dev/null
+++ b/ui/src/app/core-ui/image/image-labeling/image-labeling.component.ts
@@ -0,0 +1,278 @@
+/*
+ * 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 { AfterViewInit, Component, 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 { ImageContainerComponent } from '../components/image-container/image-container.component';
+import { ICoordinates } from '../model/coordinates';
+import { BrushLabelingService } from '../services/BrushLabeling.service';
+import { PolygonLabelingService } from '../services/PolygonLabeling.service';
+import { ReactLabelingService } from '../services/ReactLabeling.service';
+import { LabelingMode } from '../model/labeling-mode';
+
+@Component({
+  selector: 'sp-image-labeling',
+  templateUrl: './image-labeling.component.html',
+  styleUrls: ['./image-labeling.component.css']
+})
+export class ImageLabelingComponent implements OnInit, AfterViewInit {
+
+  // label
+  public labels;
+  public selectedLabel: {category, label};
+
+  // images
+  public imagesSrcs;
+  public imagesIndex: number;
+
+  public cocoFiles: CocoFormat[];
+
+  public isHoverComponent;
+  public brushSize: number;
+
+  @ViewChild(ImageContainerComponent) imageView: ImageContainerComponent;
+
+
+  public labelingMode: LabelingMode = LabelingMode.ReactLabeling;
+
+  constructor(private restService: DatalakeRestService, private reactLabelingService: ReactLabelingService,
+              private polygonLabelingService: PolygonLabelingService, private brushLabelingService: BrushLabelingService,
+              private snackBar: MatSnackBar) { }
+
+  ngOnInit(): void {
+    this.isHoverComponent = false;
+    this.brushSize = 5;
+
+    // 1. get labels
+    this.labels = this.restService.getLabels();
+
+    // 2. get Images
+    this.imagesSrcs = this.restService.getImageSrcs();
+    this.imagesIndex = 0;
+
+    // 3. get Coco files
+    this.cocoFiles = [];
+    for (const src of this.imagesSrcs) {
+      const coco = new CocoFormat();
+      coco.addImage(src);
+      this.cocoFiles.push(coco);
+    }
+  }
+
+  ngAfterViewInit(): void {
+    this.imagesIndex = 0;
+  }
+
+
+  /* sp-image-view handler */
+  handleMouseDownLeft(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
+    if (this.labelingEnabled()) {
+      switch (this.labelingMode) {
+        case LabelingMode.ReactLabeling: this.reactLabelingService.startLabeling(position);
+          break;
+        case LabelingMode.PolygonLabeling: this.polygonLabelingService.startLabeling(position);
+          break;
+        case LabelingMode.BrushLabeling: this.brushLabelingService.startLabeling(position, this.brushSize);
+      }
+    }
+  }
+
+  handleMouseMove(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
+    switch (this.labelingMode) {
+      case LabelingMode.PolygonLabeling: {
+        this.polygonLabelingService.executeLabeling(position);
+        this.polygonLabelingService.tempDraw(layer, shift, this.selectedLabel.label);
+      }
+    }
+  }
+
+  handleMouseMoveLeft(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
+    if (this.labelingEnabled()) {
+      switch (this.labelingMode) {
+        case LabelingMode.ReactLabeling: {
+          this.reactLabelingService.executeLabeling(position);
+          this.reactLabelingService.tempDraw(layer, shift, this.selectedLabel.label);
+        }
+          break;
+        case  LabelingMode.BrushLabeling: {
+          this.brushLabelingService.executeLabeling(position);
+          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) {
+        case LabelingMode.ReactLabeling: {
+          const result = this.reactLabelingService.endLabeling(position);
+          const coco = this.cocoFiles[this.imagesIndex];
+          const annotation = coco.addReactAnnotationToFirstImage(result[0], result[1],
+            this.selectedLabel.category, this.selectedLabel.label);
+          this.reactLabelingService.draw(annotationLayer, shift, annotation, this.imageView);
+        }
+          break;
+        case LabelingMode.PolygonLabeling: {
+           this.polygonLabelingService.tempDraw(drawLayer, shift, this.selectedLabel.label);
+        }
+          break;
+        case LabelingMode.BrushLabeling: {
+          const result = this.brushLabelingService.endLabeling(position);
+          const coco = this.cocoFiles[this.imagesIndex];
+          const annotation = coco.addBrushAnnotationFirstImage(result[0], result[1],
+            this.selectedLabel.category, this.selectedLabel.label);
+          this.brushLabelingService.draw(annotationLayer, shift, annotation, this.imageView);
+        }
+      }
+    }
+  }
+
+
+  handleImageViewDBClick(layer: Konva.Layer, shift: ICoordinates, position: ICoordinates) {
+    if (this.labelingEnabled()) {
+      switch (this.labelingMode) {
+        case LabelingMode.PolygonLabeling:
+          const points = this.polygonLabelingService.endLabeling(position);
+          const coco = this.cocoFiles[this.imagesIndex];
+          const annotation = coco.addPolygonAnnotationFirstImage(points,
+            this.selectedLabel.category, this.selectedLabel.label);
+          this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
+      }
+    }
+  }
+
+  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 (annotation.isBox()) {
+        this.reactLabelingService.draw(layer, shift, annotation, this.imageView);
+      } else if (annotation.isPolygon() && !annotation.isBrush()) {
+        this.polygonLabelingService.draw(layer, shift, annotation, this.imageView);
+      } else if (annotation.isBrush()) {
+        this.brushLabelingService.draw(layer, shift, annotation, this.imageView);
+      }
+    }
+  }
+
+  handleImageViewShortCuts(key) {
+    if (key === 'delete') {
+      const coco = this.cocoFiles[this.imagesIndex];
+      const toDelete = coco.annotations.filter(anno => anno.isSelected);
+      for (const anno of toDelete) {
+        this.handleDeleteAnnotation(anno);
+      }
+    }
+  }
+
+  /* sp-image-labels handler */
+  handleLabelChange(label: {category, label}) {
+    this.selectedLabel = label;
+  }
+
+  /* sp-image-bar */
+  handleImageIndexChange(index) {
+    this.save();
+    this.imagesIndex = index;
+  }
+  handleImagePageUp(e) {
+    this.save();
+    alert('Page Up - Load new data');
+  }
+
+  handleImagePageDown(e) {
+    this.save();
+    alert('Page Down - Load new data');
+  }
+
+  /* sp-image-annotations handlers */
+  handleChangeAnnotationLabel(change: [Annotation, string, string]) {
+    const coco = this.cocoFiles[this.imagesIndex];
+    const categoryId = coco.getLabelId(change[1], change[2]);
+    change[0].category_id = categoryId;
+    change[0].category_name = change[2];
+    this.imageView.redrawAll();
+  }
+
+  handleDeleteAnnotation(annotation) {
+    if (annotation !== undefined) {
+      const coco = this.cocoFiles[this.imagesIndex];
+      coco.removeAnnotation(annotation.id);
+      this.imageView.redrawAll();
+    }
+  }
+
+  /* utils */
+
+  private labelingEnabled() {
+    const coco = this.cocoFiles[this.imagesIndex];
+    const annotation = coco.annotations.find(anno => anno.isHovered);
+    if (annotation !== undefined) {
+      return false;
+    } else {
+      return true;
+    }
+  }
+
+  private save() {
+    // TODO
+    const coco = this.cocoFiles[this.imagesIndex];
+    console.log(coco);
+    this.openSnackBar('TODO: Save coco file');
+  }
+
+  private openSnackBar(message: string) {
+    this.snackBar.open(message, '', {
+      duration: 2000,
+      verticalPosition: 'top',
+      horizontalPosition: 'right'
+    });
+  }
+
+  /* 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/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.css
similarity index 85%
copy from ui/src/app/core-ui/imageLabeler/interactionMode.ts
copy to ui/src/app/core-ui/image/image-viewer/image-viewer.component.css
index 8ffb4bb..41ecef0 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.css
@@ -6,17 +6,12 @@
  * (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.
- */
-
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
-}
\ No newline at end of file
+ *
+ */
\ No newline at end of file
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
similarity index 52%
copy from ui/src/app/data-explorer/data-explorer.component.html
copy to ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
index 778be74..9b81ad1 100644
--- a/ui/src/app/data-explorer/data-explorer.component.html
+++ b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.html
@@ -16,21 +16,24 @@
   ~
   -->
 
-<div flex class="page-container page-container-padding" style="height: 1px">
-    <div flex="100" layout="column" style="padding:0px;background-color:#f6f6f6; display: inline-block; width: 100%;" >
-        <div flex layout-fill layout="row" layout-align="start center"
-             style="height:48px;padding-left:10px;font-size:14px;line-height:24px;border-bottom:1px solid #ccc">
-            <label style="font-size: 30px; padding-top: 10px;">Data Explorer</label>
+<div>
+    <div fxLayout="column" fxLayoutAlign="space-between " >
+        <div  fxLayout="row" fxLayoutAlign="space-around start">
+            <div fxLayout="column" fxLayoutAlign="space-between " >
+                <sp-image-container
+                        [imageSrc]="imagesSrcs[imagesIndex]">
+                </sp-image-container>
+            </div>
         </div>
-    </div>
-
-    <div class="container-fluid">
-
-        <sp-image-labeler></sp-image-labeler>
-
-
-
-
-        <!--    <sp-explorer></sp-explorer> -->
+        <br />
+        <br />
+        <sp-image-bar style="width: 100%"
+                      [imagesSrcs]="imagesSrcs"
+                      [selectedIndex]="imagesIndex"
+                      [enableShortCuts]="true"
+                      (indexChange)="handleImageIndexChange($event)"
+                      (pageUp)="handleImagePageUp($event)"
+                      (pageDown)="handleImagePageDown($event)">
+        </sp-image-bar>
     </div>
 </div>
diff --git a/ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
similarity index 50%
copy from ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts
copy to ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
index a16799c..bdd01aa 100644
--- a/ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts
+++ b/ui/src/app/core-ui/image/image-viewer/image-viewer.component.ts
@@ -14,28 +14,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-export class ImageTranslationUtil {
-
-  private static lastImageTranslationX = 0;
-  private static lastImageTranslationY = 0;
-  private static lastMouseX = 0;
-  private static lastMouseY = 0;
-
-  static mouseDown(mousePos, imageTranslationX, imageTranslationY) {
-    this.lastMouseX = mousePos[0];
-    this.lastMouseY = mousePos[1];
-    this.lastImageTranslationX = imageTranslationX;
-    this.lastImageTranslationY = imageTranslationY;
+
+import { Component, OnInit } from '@angular/core';
+import { DatalakeRestService } from "../../../core-services/datalake/datalake-rest.service";
+
+@Component({
+  selector: 'sp-image-viewer',
+  templateUrl: './image-viewer.component.html',
+  styleUrls: ['./image-viewer.component.css']
+})
+export class ImageViewerComponent implements OnInit {
+
+  // images
+  public imagesSrcs;
+  public imagesIndex: number;
+
+  constructor(private restService: DatalakeRestService) { }
+
+  ngOnInit(): void {
+    // 1. get Images
+    this.imagesSrcs = this.restService.getImageSrcs();
+    this.imagesIndex = 0;
   }
 
-  static mouseMove(mousePos): [number, number] {
-    let mouseX = mousePos[0];
-    let mouseY = mousePos[1];
-    return [
-      this.lastImageTranslationX + (mouseX - this.lastMouseX)  ,
-      this.lastImageTranslationY + (mouseY- this.lastMouseY  )
-    ]
+  /* sp-image-bar */
+  handleImageIndexChange(index) {
+    this.imagesIndex = index;
+  }
+  handleImagePageUp(e) {
+    alert('Page Up - Load new data');
   }
 
+  handleImagePageDown(e) {
+    alert('Page Down - Load new data');
+  }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-ui/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/image.component.css
similarity index 85%
copy from ui/src/app/core-ui/imageLabeler/interactionMode.ts
copy to ui/src/app/core-ui/image/image.component.css
index 8ffb4bb..41ecef0 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/image.component.css
@@ -6,17 +6,12 @@
  * (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.
- */
-
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
-}
\ No newline at end of file
+ *
+ */
\ No newline at end of file
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/core-ui/image/image.component.html
similarity index 56%
copy from ui/src/app/data-explorer/data-explorer.component.html
copy to ui/src/app/core-ui/image/image.component.html
index 778be74..d93a7ba 100644
--- a/ui/src/app/data-explorer/data-explorer.component.html
+++ b/ui/src/app/core-ui/image/image.component.html
@@ -16,21 +16,13 @@
   ~
   -->
 
-<div flex class="page-container page-container-padding" style="height: 1px">
-    <div flex="100" layout="column" style="padding:0px;background-color:#f6f6f6; display: inline-block; width: 100%;" >
-        <div flex layout-fill layout="row" layout-align="start center"
-             style="height:48px;padding-left:10px;font-size:14px;line-height:24px;border-bottom:1px solid #ccc">
-            <label style="font-size: 30px; padding-top: 10px;">Data Explorer</label>
-        </div>
-    </div>
+<mat-button-toggle-group name="fontStyle" aria-label="Font Style" #group="matButtonToggleGroup" value="view">
+    <mat-button-toggle value="view">Viewer</mat-button-toggle>
+    <mat-button-toggle value="label">Label</mat-button-toggle>
+    <mat-button-toggle value="categorize">Categorize</mat-button-toggle>
+</mat-button-toggle-group>
 
-    <div class="container-fluid">
 
-        <sp-image-labeler></sp-image-labeler>
-
-
-
-
-        <!--    <sp-explorer></sp-explorer> -->
-    </div>
-</div>
+<sp-image-viewer *ngIf="group.value === 'view'"></sp-image-viewer>
+<sp-image-labeling *ngIf="group.value === 'label'"></sp-image-labeling>
+<sp-image-categorize *ngIf="group.value === 'categorize'"></sp-image-categorize>
\ No newline at end of file
diff --git a/ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts b/ui/src/app/core-ui/image/image.component.ts
similarity index 69%
copy from ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
copy to ui/src/app/core-ui/image/image.component.ts
index 9162ba3..11b16dd 100644
--- a/ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
+++ b/ui/src/app/core-ui/image/image.component.ts
@@ -6,18 +6,35 @@
  * (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.
+ *
  */
 
-export enum AnnotationMode {
-  ReactLabeling,
-  ReactResize,
-  PolygonLabeling,
-  PolygonTransform,
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'sp-image',
+  templateUrl: './image.component.html',
+  styleUrls: ['./image.component.css']
+})
+export class ImageComponent implements OnInit {
+
+
+
+  constructor() {
+
+  }
+
+  ngOnInit(): void {
+
+  }
+
+
+
 }
diff --git a/ui/src/app/core-ui/imageLabeler/interactionMode.ts b/ui/src/app/core-ui/image/model/coordinates.ts
similarity index 90%
rename from ui/src/app/core-ui/imageLabeler/interactionMode.ts
rename to ui/src/app/core-ui/image/model/coordinates.ts
index 8ffb4bb..9c7e2f3 100644
--- a/ui/src/app/core-ui/imageLabeler/interactionMode.ts
+++ b/ui/src/app/core-ui/image/model/coordinates.ts
@@ -15,8 +15,7 @@
  * limitations under the License.
  */
 
-export enum InteractionMode {
-  imageViewing,
-  imageAnnotate,
-  imageClassify
-}
\ No newline at end of file
+export interface ICoordinates {
+  x;
+  y;
+}
diff --git a/ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts b/ui/src/app/core-ui/image/model/labeling-mode.ts
similarity index 92%
rename from ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
rename to ui/src/app/core-ui/image/model/labeling-mode.ts
index 9162ba3..6aae804 100644
--- a/ui/src/app/core-ui/imageLabeler/annotation/annotationMode.ts
+++ b/ui/src/app/core-ui/image/model/labeling-mode.ts
@@ -15,9 +15,9 @@
  * limitations under the License.
  */
 
-export enum AnnotationMode {
+export enum LabelingMode {
   ReactLabeling,
-  ReactResize,
   PolygonLabeling,
-  PolygonTransform,
+  BrushLabeling,
+  NoneLabeling,
 }
diff --git a/ui/src/app/core-ui/image/services/BrushLabeling.service.ts b/ui/src/app/core-ui/image/services/BrushLabeling.service.ts
new file mode 100644
index 0000000..d97b0dc
--- /dev/null
+++ b/ui/src/app/core-ui/image/services/BrushLabeling.service.ts
@@ -0,0 +1,147 @@
+/*
+ * 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 Konva from 'konva';
+import { Annotation } from '../../../core-model/coco/Annotation';
+import { ICoordinates } from '../model/coordinates';
+import { ColorService } from './color.service';
+
+@Injectable()
+export class BrushLabelingService {
+
+  private points: number[];
+  private brushsize: number;
+
+  private isLabeling: boolean;
+
+  constructor(private colorService: ColorService) {
+
+  }
+
+
+  startLabeling(position: ICoordinates, brushSize: number) {
+    this.isLabeling = true;
+    this.points = [];
+    this.points.push(position.x);
+    this.points.push(position.y);
+    this.brushsize = brushSize;
+  }
+
+  executeLabeling(position: ICoordinates) {
+    this.points.push(position.x);
+    this.points.push(position.y);
+  }
+
+  endLabeling(position: ICoordinates) {
+    this.isLabeling = false;
+    return [this.points, this.brushsize];
+  }
+
+  tempDraw(layer: Konva.Layer, shift: ICoordinates, label: string) {
+    if (this.isLabeling) {
+      const tmp = [];
+      for (let i = 0; i < this.points.length; i += 2) {
+        tmp.push(this.points[i] + shift.x);
+        tmp.push(this.points[i + 1] + shift.y);
+      }
+
+      const line = new Konva.Line({
+        points: tmp,
+        stroke: this.colorService.getColor(label),
+        opacity: 0.8,
+        strokeWidth: this.brushsize,
+        closed: false
+      });
+      layer.add(line);
+    }
+  }
+
+  draw(layer: Konva.Layer, shift: ICoordinates, annotation: Annotation, imageView) {
+    const tmp = [];
+    for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+      tmp.push(annotation.segmentation[0][i] + shift.x);
+      tmp.push(annotation.segmentation[0][i + 1] + shift.y);
+    }
+
+    const line = new Konva.Line({
+      points: tmp,
+      stroke: this.colorService.getColor(annotation.category_name),
+      opacity: 0.5,
+      strokeWidth: this.brushsize,
+      closed: false,
+      draggable: false,
+    });
+    layer.add(line);
+
+    const transformer = new Konva.Transformer({
+      anchorFill: '#FFFFFF',
+      anchorSize: 10,
+      rotateEnabled: false,
+      enabledAnchors: [],
+      borderStroke: 'green',
+    });
+
+    if (annotation.isSelected) {
+      transformer.attachTo(line);
+    }
+
+    this.addMouseHandler(line, annotation, layer, transformer);
+    this.addClickHandler(line, annotation, layer, transformer);
+
+    layer.add(line);
+    layer.add(transformer);
+  }
+
+  private addClickHandler(rect, annotation, layer, transformer) {
+    rect.on('click', function() {
+      annotation.isSelected = true;
+      transformer.attachTo(this);
+      layer.batchDraw();
+    });
+
+    rect.on('dblclick', function() {
+      annotation.isSelected = false;
+      transformer.detach();
+      layer.batchDraw();
+    });
+
+  }
+
+  private addMouseHandler(rect, annotation, layer, transformer) {
+    rect.on('mouseover', function() {
+      annotation.isHovered = true;
+      rect.opacity(0.8);
+      layer.batchDraw();
+    });
+
+    rect.on('mouseout', function() {
+      annotation.isHovered = false;
+      rect.opacity(0.5);
+      layer.batchDraw();
+    });
+
+    transformer.on('mouseover', function() {
+      annotation.isHovered = true;
+    });
+
+    transformer.on('mouseout', function() {
+      annotation.isHovered = false;
+    });
+  }
+
+}
diff --git a/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts b/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts
new file mode 100644
index 0000000..153e8fd
--- /dev/null
+++ b/ui/src/app/core-ui/image/services/PolygonLabeling.service.ts
@@ -0,0 +1,252 @@
+/*
+ * 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 Konva from 'konva';
+import { Annotation } from '../../../core-model/coco/Annotation';
+import { ICoordinates } from '../model/coordinates';
+import { ColorService } from './color.service';
+
+@Injectable()
+export class PolygonLabelingService {
+
+  private points: number[];
+  private tmpPoints: number[];
+
+  private isLabeling: boolean;
+
+  constructor(private colorService: ColorService) {
+    this.isLabeling = false;
+  }
+
+  static buildAnchors(layer, annotation, imageView, poly) {
+    this.removeAnchors(layer, annotation.id);
+    const anchorGroup = new Konva.Group({name: 'anchor_group_' + annotation.id})
+
+    for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+      PolygonLabelingService.buildAnchor(layer, annotation, i, imageView, poly, anchorGroup);
+    }
+    layer.add(anchorGroup);
+  }
+
+  static buildAnchor(layer, annotation, index, imageView, poly, anchorGroup) {
+    const shift: ICoordinates = imageView.getShift();
+
+    const xx = annotation.segmentation[0][index] + shift.x;
+    const yy = annotation.segmentation[0][index + 1] + shift.y;
+    const anchor = new Konva.Circle({
+      name: 'anchor_' + annotation.id,
+      x: xx,
+      y: yy,
+      radius: 10,
+      fill: 'white',
+      stroke: 'green',
+      strokeWidth: 4,
+      draggable: true,
+    });
+    anchorGroup.add(anchor);
+
+    anchor.on('mouseover', function() {
+      annotation.isHovered = true;
+    });
+
+    anchor.on('mouseout', function() {
+      annotation.isHovered = false;
+    });
+
+    /*    let offset: ICoordinates;
+
+    anchor.on('dragstart', function() {
+      const position = imageView.getImagePointerPosition();
+      offset = {x: annotation.segmentation[0][index] - position.x,
+                y: annotation.segmentation[0][index + 1] - position.y};
+    });*/
+
+    anchor.on('dragmove', function() {
+      const position = imageView.getImagePointerPosition();
+      const _shift: ICoordinates = imageView.getShift();
+
+      annotation.segmentation[0][index] = position.x;
+      annotation.segmentation[0][index + 1] = position.y;
+
+      const tmp = [];
+      for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+        tmp.push(annotation.segmentation[0][i] + _shift.x);
+        tmp.push(annotation.segmentation[0][i + 1] + _shift.y );
+      }
+      poly.points(tmp);
+      poly.x(0);
+      poly.y(0);
+      poly.draw();
+    });
+  }
+
+  static removeAnchors(layer, annotationId) {
+    const tmp = [];
+    for (const child of layer.children) {
+      if (child.name() === 'anchor_group_' + annotationId) {
+        child.destroy();
+      }
+    }
+    layer.batchDraw();
+  }
+
+
+  startLabeling(position: ICoordinates) {
+    if (this.isLabeling) {
+      this.points.push(position.x);
+      this.points.push(position.y);
+    } else {
+      this.isLabeling = true;
+      this.points = [];
+      this.tmpPoints = [];
+      this.points.push(position.x);
+      this.points.push(position.y);
+    }
+  }
+
+  executeLabeling(position: ICoordinates) {
+    if (this.isLabeling) {
+      this.tmpPoints = Object.assign([], this.points);
+      this.tmpPoints.push(position.x);
+      this.tmpPoints.push(position.y);
+    }
+  }
+
+  endLabeling(position: ICoordinates) {
+    this.isLabeling = false;
+    return this.points.slice(0, this.points.length - 2);
+  }
+
+  tempDraw(layer: Konva.Layer, shift: ICoordinates, label: string) {
+    if (this.isLabeling) {
+      const tmp = [];
+      for (let i = 0; i < this.tmpPoints.length; i += 2) {
+        tmp.push(this.tmpPoints[i] + shift.x);
+        tmp.push(this.tmpPoints[i + 1] + shift.y);
+      }
+
+      const poly = new Konva.Line({
+        points: tmp,
+        fill: this.colorService.getColor(label),
+        stroke: 'black',
+        opacity: 0.8,
+        strokeWidth: 4,
+        closed: true
+      });
+      layer.add(poly);
+    }
+  }
+
+  draw(layer: Konva.Layer, shift: ICoordinates, annotation: Annotation, imageView) {
+    const tmp = [];
+    for (let i = 0; i < annotation.segmentation[0].length; i += 2) {
+      tmp.push(annotation.segmentation[0][i] + shift.x);
+      tmp.push(annotation.segmentation[0][i + 1] + shift.y);
+    }
+
+    const poly = new Konva.Line({
+      points: tmp,
+      fill: this.colorService.getColor(annotation.category_name),
+      stroke: 'black',
+      opacity: 0.5,
+      strokeWidth: 4,
+      closed: true,
+      draggable: true
+    });
+
+    const transformer = new Konva.Transformer({
+      anchorFill: '#FFFFFF',
+      anchorSize: 10,
+      rotateEnabled: false,
+      enabledAnchors: [],
+      borderStroke: 'green',
+    });
+
+    if (annotation.isSelected) {
+      transformer.attachTo(poly);
+      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);
+
+    layer.add(poly);
+    layer.add(transformer);
+  }
+
+  private addClickHandler(poly, annotation, layer, transformer, imageView) {
+    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();
+    });
+
+  }
+
+  private addMouseHandler(poly, annotation, layer, transformer) {
+    poly.on('mouseover', function() {
+      annotation.isHovered = true;
+      this.opacity(0.8);
+      layer.batchDraw();
+    });
+
+    poly.on('mouseout', function() {
+      annotation.isHovered = false;
+      this.opacity(0.5);
+      layer.batchDraw();
+    });
+  }
+
+
+  private addDragHandler(poly, annotation, layer, imageView) {
+    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);
+      }
+    });
+
+    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);
+      }
+    });
+
+  }
+
+}
diff --git a/ui/src/app/core-ui/image/services/ReactLabeling.service.ts b/ui/src/app/core-ui/image/services/ReactLabeling.service.ts
new file mode 100644
index 0000000..1059dba
--- /dev/null
+++ b/ui/src/app/core-ui/image/services/ReactLabeling.service.ts
@@ -0,0 +1,198 @@
+/*
+ * 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 Konva from 'konva';
+import { Annotation } from '../../../core-model/coco/Annotation';
+import { ICoordinates } from '../model/coordinates';
+import { ColorService } from './color.service';
+
+@Injectable()
+export class ReactLabelingService {
+
+  private lastPosition: ICoordinates;
+  private reactSize: ICoordinates;
+
+  private isLabeling: boolean;
+
+  constructor(private colorService: ColorService) {
+
+  }
+
+
+  startLabeling(position: ICoordinates) {
+    this.isLabeling = true;
+    this.lastPosition = position;
+    this.reactSize = {x: 0, y: 0};
+  }
+
+  executeLabeling(position: ICoordinates) {
+    this.reactSize.x = position.x - this.lastPosition.x;
+    this.reactSize.y = position.y - this.lastPosition.y;
+  }
+
+  endLabeling(position: ICoordinates) {
+    this.isLabeling = false;
+    if (this.reactSize.x > 0 || this.reactSize.y > 0) {
+      return [this.lastPosition, this.reactSize];
+    }
+  }
+
+  tempDraw(layer: Konva.Layer, shift: ICoordinates, label: string) {
+    if (this.isLabeling && (this.reactSize.x > 0 || this.reactSize.y > 0)) {
+      const box = new Konva.Rect({
+        x: this.lastPosition.x + shift.x,
+        y: this.lastPosition.y + shift.y,
+        width: this.reactSize.x,
+        height: this.reactSize.y,
+        fill: this.colorService.getColor(label),
+        opacity: 0.5,
+        stroke: 'black',
+        strokeWidth: 4,
+        draggable: false
+      });
+      layer.add(box);
+    }
+  }
+
+  draw(layer: Konva.Layer, shift: ICoordinates, annotation: Annotation, imageView) {
+    const rect = new Konva.Rect({
+      x: annotation.bbox[0] + shift.x,
+      y: annotation.bbox[1] + shift.y,
+      width: annotation.bbox[2],
+      height: annotation.bbox[3],
+      fill: this.colorService.getColor(annotation.category_name),
+      opacity: 0.5,
+      stroke: 'black',
+      strokeWidth: 4,
+      draggable: true,
+    });
+
+    const transformer = new Konva.Transformer({
+      anchorFill: '#FFFFFF',
+      anchorSize: 10,
+      rotateEnabled: false,
+      keepRatio: false,
+      borderStroke: 'green',
+    });
+
+    if (annotation.isSelected) {
+      transformer.attachTo(rect);
+    }
+
+    this.addDragHandler(rect, annotation, imageView);
+    this.addTransformHandler(rect, annotation, imageView);
+    this.addMouseHandler(rect, annotation, layer, transformer);
+    this.addClickHandler(rect, annotation, layer, transformer);
+
+    layer.add(rect);
+    layer.add(transformer);
+  }
+
+  private addClickHandler(rect, annotation, layer, transformer) {
+    rect.on('click', function() {
+      annotation.isSelected = true;
+      transformer.attachTo(this);
+      layer.batchDraw();
+    });
+
+    rect.on('dblclick', function() {
+      annotation.isSelected = false;
+      transformer.detach();
+      layer.batchDraw();
+    });
+
+  }
+
+  private addMouseHandler(rect, annotation, layer, transformer) {
+    rect.on('mouseover', function() {
+      annotation.isHovered = true;
+      rect.opacity(0.8);
+      layer.batchDraw();
+    });
+
+    rect.on('mouseout', function() {
+      annotation.isHovered = false;
+      rect.opacity(0.5);
+      layer.batchDraw();
+    });
+
+    transformer.on('mouseover', function() {
+      annotation.isHovered = true;
+    });
+
+    transformer.on('mouseout', function() {
+      annotation.isHovered = false;
+    });
+  }
+
+  private addTransformHandler(rect, annotation, imageView) {
+    let resizer: string;
+
+    rect.on('transformstart', function(e) {
+      resizer = e.evt.currentTarget.parent.movingResizer;
+    });
+
+    rect.on('transform', function(e) {
+      const position = imageView.getImagePointerPosition();
+      if (resizer === 'top-left') {
+        annotation.bbox[2] += annotation.bbox[0] - position.x;
+        annotation.bbox[3] += annotation.bbox[1] - position.y;
+        annotation.bbox[0] = position.x;
+        annotation.bbox[1] = position.y;
+      } else if (resizer === 'top-right') {
+        annotation.bbox[2] = Math.abs(annotation.bbox[0] - position.x);
+        annotation.bbox[3] += annotation.bbox[1] - position.y;
+        annotation.bbox[1] = position.y;
+      } else if (resizer === 'bottom-left') {
+        annotation.bbox[2] += annotation.bbox[0] - position.x;
+        annotation.bbox[3] = Math.abs(annotation.bbox[1] - position.y);
+        annotation.bbox[0] = position.x;
+      } else if (resizer === 'bottom-right') {
+        annotation.bbox[2] = Math.abs(annotation.bbox[0] - position.x);
+        annotation.bbox[3] = Math.abs(annotation.bbox[1] - position.y);
+      } else if (resizer === 'top-center') {
+        annotation.bbox[3] += annotation.bbox[1] - position.y;
+        annotation.bbox[1] = position.y;
+      } else if (resizer === 'middle-right') {
+        annotation.bbox[2] = Math.abs(annotation.bbox[0] - position.x);
+      } else if (resizer === 'middle-left') {
+        annotation.bbox[2] += annotation.bbox[0] - position.x;
+        annotation.bbox[0] = position.x;
+      } else if ( resizer === 'bottom-center') {
+        annotation.bbox[3] = Math.abs(annotation.bbox[1] - position.y);
+      }
+    });
+  }
+
+  private addDragHandler(rect, annotation, imageView) {
+    let offset: ICoordinates;
+
+    rect.on('dragstart', function() {
+      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;
+    });
+
+  }
+
+}
diff --git a/ui/src/app/core-ui/imageLabeler/util/color.util.ts b/ui/src/app/core-ui/image/services/color.service.ts
similarity index 73%
rename from ui/src/app/core-ui/imageLabeler/util/color.util.ts
rename to ui/src/app/core-ui/image/services/color.service.ts
index 65c4526..4ee5583 100644
--- a/ui/src/app/core-ui/imageLabeler/util/color.util.ts
+++ b/ui/src/app/core-ui/image/services/color.service.ts
@@ -15,19 +15,22 @@
  * limitations under the License.
  */
 
-export class ColorUtil {
+import { Injectable } from '@angular/core';
 
-  static getColor(label) {
-    var hash = 0;
-    for (var i = 0; i < label.length; i++) {
-      hash = label.charCodeAt(i) + ((hash << 5) - hash);
+@Injectable()
+export class ColorService {
+
+   getColor(str) {
+    let hash = 0;
+    for (let i = 0; i < str.length; i++) {
+      hash = str.charCodeAt(i) + ((hash << 5) - hash);
     }
-    var colour = '#';
-    for (var i = 0; i < 3; i++) {
-      var value = (hash >> (i * 8)) & 0xFF;
+    let colour = '#';
+    for (let i = 0; i < 3; i++) {
+      const value = (hash >> (i * 8)) & 0xFF;
       colour += ('00' + value.toString(16)).substr(-2);
     }
     return colour;
   }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts b/ui/src/app/core-ui/image/util/imageTranslation.util.ts
similarity index 90%
rename from ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts
rename to ui/src/app/core-ui/image/util/imageTranslation.util.ts
index a16799c..b42ccd8 100644
--- a/ui/src/app/core-ui/imageLabeler/util/imageTranslation.util.ts
+++ b/ui/src/app/core-ui/image/util/imageTranslation.util.ts
@@ -29,13 +29,13 @@ export class ImageTranslationUtil {
   }
 
   static mouseMove(mousePos): [number, number] {
-    let mouseX = mousePos[0];
-    let mouseY = mousePos[1];
+    const mouseX = mousePos[0];
+    const mouseY = mousePos[1];
     return [
       this.lastImageTranslationX + (mouseX - this.lastMouseX)  ,
-      this.lastImageTranslationY + (mouseY- this.lastMouseY  )
-    ]
+      this.lastImageTranslationY + (mouseY - this.lastMouseY  )
+    ];
   }
 
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/core-ui/imageLabeler/annotation/imageAnnotation.ts b/ui/src/app/core-ui/imageLabeler/annotation/imageAnnotation.ts
deleted file mode 100644
index a97afc0..0000000
--- a/ui/src/app/core-ui/imageLabeler/annotation/imageAnnotation.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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 { AnnotationMode } from "./annotationMode";
-import { ReactAnnotationUtil } from "./reactAnnotation.util";
-import { Injectable } from "@angular/core";
-import { CocoFormat } from "../../../core-model/coco/Coco.format";
-import { PolygonAnnotationUtil } from "./polygonAnnotation.util";
-
-@Injectable()
-export class ImageAnnotation {
-
-  private interactionMode: AnnotationMode = AnnotationMode.ReactLabeling;
-  private lastLabelMode: AnnotationMode = AnnotationMode.ReactLabeling;
-  private selectedAnnotation;
-
-  private coco: CocoFormat;
-  private src;
-  public saved: boolean = true;
-
-
-  newImage(src, imageName, width, height) {
-    this.src = src;
-    //TODO get Coco file form backend if exists
-    this.coco = new CocoFormat(imageName, width, height);
-    this.saved = true;
-  }
-
-  mouseDown(imageCord, scale) {
-    this.selectedAnnotation = this.checkForSelectedAnnotation(imageCord, this.coco.annotations, scale);
-
-    if (this.interactionMode == AnnotationMode.PolygonTransform){
-      PolygonAnnotationUtil.mouseDownTransform(imageCord,
-        this.selectedAnnotation, scale)
-    } else if (this.interactionMode == AnnotationMode.ReactLabeling) {
-      ReactAnnotationUtil.mouseDownCreate(imageCord);
-    } else if (this.interactionMode == AnnotationMode.ReactResize){
-      ReactAnnotationUtil.mouseDownTransform(imageCord,
-        this.selectedAnnotation, scale)
-    } else if (this.interactionMode == AnnotationMode.PolygonLabeling){
-      this.saved = false;
-      PolygonAnnotationUtil.mouseDownCreate(imageCord)
-    }
-  }
-
-  mouseMover(imageCord, imageXShift, imageYShift, context, label) {
-    this.saved = false;
-    if (this.interactionMode == AnnotationMode.PolygonTransform){
-      PolygonAnnotationUtil.mouseMoveTransform(imageCord, this.selectedAnnotation)
-    } else if (this.interactionMode == AnnotationMode.ReactLabeling) {
-      ReactAnnotationUtil.mouseMoveCreate(imageCord, imageXShift, imageYShift, context, label);
-    } else if (this.interactionMode == AnnotationMode.ReactResize){
-      ReactAnnotationUtil.mouseMoveTansform(imageCord, this.selectedAnnotation);
-    } else if (this.interactionMode == AnnotationMode.PolygonLabeling){
-      PolygonAnnotationUtil.mouseMoveCreate(imageCord, imageXShift, imageYShift, context, label)
-    }
-  }
-
-  mouseUp(imageCords, label, labelCategory) {
-    if (this.interactionMode == AnnotationMode.ReactLabeling) {
-      let labelId = this.coco.getLabelId(label, labelCategory);
-      ReactAnnotationUtil.mouseUpCreate(imageCords, this.coco, labelId);
-    }
-  }
-
-  dblclick (imageCords, label, labelCategory) {
-    let labelId = this.coco.getLabelId(label, labelCategory);
-    PolygonAnnotationUtil.finishCreate(imageCords, this.coco, labelId)
-  }
-
-  save(): boolean {
-    //TODO save coco file in backend
-    this.saved = true;
-    return true;
-  }
-
-  deleteAnnotation(annotation) {
-    if (annotation !== undefined) {
-      this.coco.removeAnnotation(annotation.id);
-    }
-  }
-
-  deleteSelectedAnnotation() {
-    if (this.selectedAnnotation !== undefined) {
-      this.coco.removeAnnotation(this.selectedAnnotation.id);
-    }
-  }
-
-  annotationHovering(imageCords, scale) {
-    for(let annotation of this.coco.annotations) {
-      annotation.isHovered = false;
-      if (!annotation.isSelected) {
-        if (annotation.isBox()) {
-          annotation.isHovered = ReactAnnotationUtil.checkIfClicked(imageCords, annotation)
-        } else {
-          annotation.isHovered = PolygonAnnotationUtil.checkIfClicked(imageCords, annotation, scale)
-        }
-      }
-    }
-  }
-
-  annotationDraw(imageXShift, imageYShift, scale, context) {
-    for(let annotation of this.coco.annotations) {
-      let label = this.coco.getLabelById(annotation.category_id);
-      if (annotation.isBox()) {
-        ReactAnnotationUtil.draw(annotation, label, context, imageXShift, imageYShift, scale)
-      } else {
-        PolygonAnnotationUtil.draw(annotation, label, context, imageXShift, imageYShift, scale)
-      }
-    }
-  }
-
-  private checkForSelectedAnnotation(imageCord, annotations, scale) {
-    let selectedAnnotation = undefined;
-    for(let annotation of annotations) {
-      let clicked = false;
-      if (annotation.isBox()) {
-        clicked = ReactAnnotationUtil.checkIfClicked(imageCord, annotation)
-      } else {
-        clicked = PolygonAnnotationUtil.checkIfClicked(imageCord, annotation, scale)
-      }
-      if (clicked) {
-        annotation.isHovered = false;
-        selectedAnnotation = annotation;
-      }
-      annotation.isSelected = clicked;
-    }
-
-    if (selectedAnnotation !== undefined) {
-      if (selectedAnnotation.isBox()) {
-        this.interactionMode = AnnotationMode.ReactResize;
-      } else {
-        this.interactionMode = AnnotationMode.PolygonTransform;
-      }
-    } else {
-      this.interactionMode = this.lastLabelMode;
-    }
-
-    return selectedAnnotation
-  }
-
-  changeLabel(annonation, label, category) {
-    let labelId = this.coco.getLabelId(label, category);
-    annonation.category_id = labelId;
-  }
-
-  getAnnotations() {
-    return this.coco?.annotations;
-  }
-
-  getLabelById(id) {
-    return this.coco.getLabelById(id);
-  }
-
-  isReactMode() {
-    return this.interactionMode == AnnotationMode.ReactLabeling || this.interactionMode == AnnotationMode.ReactResize;
-  }
-
-  isPolygonMode() {
-    return this.interactionMode == AnnotationMode.PolygonLabeling || this.interactionMode == AnnotationMode.PolygonTransform;
-  }
-
-  setReactMode() {
-    this.lastLabelMode = AnnotationMode.ReactLabeling;
-    this.interactionMode = AnnotationMode.ReactLabeling;
-  }
-
-  setPolygonMode() {
-    this.lastLabelMode = AnnotationMode.PolygonLabeling;
-    this.interactionMode = AnnotationMode.PolygonLabeling;
-  }
-
-  isPolygonLabeling() {
-    return PolygonAnnotationUtil.isLabeling;
-  }
-
-
-}
diff --git a/ui/src/app/core-ui/imageLabeler/annotation/polygonAnnotation.util.ts b/ui/src/app/core-ui/imageLabeler/annotation/polygonAnnotation.util.ts
deleted file mode 100644
index 25c176b..0000000
--- a/ui/src/app/core-ui/imageLabeler/annotation/polygonAnnotation.util.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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 { ColorUtil } from "../util/color.util";
-import * as pointInPolygon from 'point-in-polygon';
-
-export class PolygonAnnotationUtil {
-
-  private static backgroundHoverAlpha = 0.6;
-  private static backgroundAlpha = 0.2;
-
-  public static isLabeling;
-  private static points;
-
-  //mouse position
-  private static lastImageCordX = 0;
-  private static lastImageCordY = 0;
-
-  private static selectedPoint = undefined;
-
-  static mouseDownCreate(imageCord) {
-    if (this.isLabeling) {
-      this.points.push(imageCord)
-    } else {
-      this.isLabeling = true;
-      this.points = [];
-      this.points.push(imageCord)
-    }
-  }
-
-  static mouseDownTransform(imageCord, annotation, scale) {
-    this.lastImageCordX = imageCord[0];
-    this.lastImageCordY = imageCord[1];
-
-    this.selectedPoint = this.getPointId(imageCord, annotation, scale);
-  }
-
-  static mouseMoveCreate(imageCord, imageXShift, imageYShift, context, label) {
-    context.strokeStyle = ColorUtil.getColor(label);
-    context.fillStyle = context.strokeStyle;
-    context.globalAlpha = this.backgroundHoverAlpha;
-
-    context.beginPath();
-    context.moveTo(this.points[0][0] + imageXShift, this.points[0][1] + imageYShift);
-    for (var i = 1; i < this.points.length; i++) {
-      context.lineTo(this.points[i][0] + imageXShift, this.points[i][1] + imageYShift);
-    }
-
-    context.lineTo(imageCord[0] + imageXShift, imageCord[1] + imageYShift);
-    context.closePath();
-    context.stroke();
-    context.fill();
-    context.globalAlpha = 1;
-  }
-
-  static mouseMoveTransform(imageCord, annotation) {
-    if (this.selectedPoint !== undefined) {
-      console.log(2 * this.selectedPoint)
-      annotation.segmentation[0][2 * this.selectedPoint] = imageCord[0];
-      annotation.segmentation[0][2 * this.selectedPoint + 1]  = imageCord[1];
-    }
-  }
-
-  static finishCreate(imageCords, coco, labelId) {
-    this.isLabeling = false;
-    //this.points.push(imageCords);
-
-    let points = [];
-    for (let i = 0; i < this.points.length-1 ; i+=1) {
-      points.push(this.points[i][0]);
-      points.push(this.points[i][1]);
-    }
-    console.log(points);
-    coco.addPolygonAnnotation(points, labelId)
-  }
-
-  static draw(annotation, label, context, imageXShift, imageYShift, scale) {
-    if (annotation.isHovered) {
-      context.globalAlpha = this.backgroundHoverAlpha
-    } else if (annotation.isSelected) {
-      context.globalAlpha = this.backgroundHoverAlpha;
-    } else {
-      context.globalAlpha = this.backgroundAlpha;
-    }
-    context.strokeStyle = ColorUtil.getColor(label);
-    context.fillStyle = context.strokeStyle;
-
-    context.beginPath();
-    let points = annotation.segmentation[0];
-
-    context.moveTo(points[0] + imageXShift, points[1] + imageYShift);
-    for (var i = 2; i < points.length; i+=2) {
-      context.lineTo(points[i] + imageXShift, points[i+1] + imageYShift);
-    }
-    context.closePath();
-    context.fill();
-    context.globalAlpha = 1;
-    context.stroke();
-
-    if (annotation.isSelected) {
-      let size = this.getResizeCirlceSize(scale);
-
-      for (var i = 0; i < points.length; i+=2) {
-        context.beginPath();
-        context.arc(points[i] + imageXShift, points[i+1] + imageYShift, size, 0, 2 * Math.PI);
-        context.fill();
-      }
-    }
-  }
-
-  private static getResizeCirlceSize(scale) {
-    return Math.floor(10 / scale);
-  }
-
-  private static getPointId(imageCords, annotation, scale) {
-    let points =  annotation.segmentation[0];
-    for (var i = 0; i < points.length; i+=2) {
-      if (Math.abs(imageCords[0] - points[i]) < this.getResizeCirlceSize(scale) &&
-        Math.abs(imageCords[1] - points[i+1]) < this.getResizeCirlceSize(scale)) {
-        return i / 2;
-      }
-    }
-    return undefined;
-  }
-
-  public static checkIfClicked(imageCords, annotation, scale) {
-    let points = [];
-    for (var i = 0; i < annotation.segmentation[0].length; i+=2) {
-      points.push([annotation.segmentation[0][i], annotation.segmentation[0][i+1]]);
-    }
-    let result = pointInPolygon(imageCords, points);
-    if (result) {
-      return result;
-    }
-    if (annotation.isSelected && this.getPointId(imageCords, annotation, scale) !== undefined) {
-      return true;
-    }
-    return false;
-  }
-
-}
diff --git a/ui/src/app/core-ui/imageLabeler/annotation/reactAnnotation.util.ts b/ui/src/app/core-ui/imageLabeler/annotation/reactAnnotation.util.ts
deleted file mode 100644
index 505b78b..0000000
--- a/ui/src/app/core-ui/imageLabeler/annotation/reactAnnotation.util.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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 { ColorUtil } from "../util/color.util";
-
-export class ReactAnnotationUtil {
-
-  private static backgroundHoverAlpha = 0.6;
-  private static backgroundAlpha = 0.2;
-
-  //mouse position
-  private static lastImageCordX = 0;
-  private static lastImageCordY = 0;
-
-  private static isMouseDown = false;
-
-  private static reactHeight = 0;
-  private static reactWidth = 0;
-
-  //resize
-  private static pressedTopLeft = false;
-  private static pressedTopRight = false;
-  private static pressedButtomLeft = false;
-  private static pressedButtomRight = false;
-  private static pressedTop = false;
-  private static pressedRight = false;
-  private static pressedLeft = false;
-  private static pressedButtom = false;
-
-  private static offSetX;
-  private static offSetY;
-
-  static mouseDownCreate(imageCord) {
-    this.lastImageCordX = imageCord[0];
-    this.lastImageCordY = imageCord[1];
-    this.isMouseDown = true;
-  }
-
-  static mouseDownTransform(imageCord, annotation, scale) {
-    this.lastImageCordX = imageCord[0];
-    this.lastImageCordY = imageCord[1];
-
-    this.setSelectedResizeBox(annotation, scale);
-
-    this.offSetX = annotation.bbox[0] - imageCord[0];
-    this.offSetY = annotation.bbox[1] - imageCord[1];
-  }
-
-  static mouseMoveCreate(imageCord, imageXShift, imageYShift, context, label) {
-      if(this.isMouseDown) {
-        this.reactWidth = imageCord[0] - this.lastImageCordX;
-        this.reactHeight = imageCord[1] - this.lastImageCordY;
-
-        context.strokeStyle = ColorUtil.getColor(label);
-        context.fillStyle = context.strokeStyle;
-        context.beginPath();
-        context.globalAlpha = this.backgroundHoverAlpha;
-        context.fillRect(this.lastImageCordX + imageXShift, this.lastImageCordY + imageYShift,
-          this.reactWidth, this.reactHeight);
-        context.globalAlpha = 1;
-        context.strokeRect(this.lastImageCordX + imageXShift, this.lastImageCordY + imageYShift,
-          this.reactWidth, this.reactHeight);
-        context.fillText(label, this.lastImageCordX + imageXShift, this.lastImageCordY,- 5 );
-      }
-  }
-
-  static mouseMoveTansform(imageCord, annotation) {
-
-    if (this.pressedTopLeft) {
-      annotation.bbox[2] += annotation.bbox[0]- imageCord[0];
-      annotation.bbox[3] += annotation.bbox[1]- imageCord[1];
-      annotation.bbox[0] = imageCord[0];
-      annotation.bbox[1] = imageCord[1];
-    } else if (this.pressedTopRight) {
-      annotation.bbox[2] = Math.abs(annotation.bbox[0] - imageCord[0]);
-      annotation.bbox[3] += annotation.bbox[1] - imageCord[1];
-      annotation.bbox[1] = imageCord[1];
-    } else if (this.pressedButtomLeft) {
-      annotation.bbox[2] += annotation.bbox[0]- imageCord[0];
-      annotation.bbox[3] = Math.abs(annotation.bbox[1] - imageCord[1]);
-      annotation.bbox[0] = imageCord[0];
-    } else if (this.pressedButtomRight) {
-      annotation.bbox[2] = Math.abs(annotation.bbox[0] - imageCord[0]);
-      annotation.bbox[3] = Math.abs(annotation.bbox[1] - imageCord[1]);
-    } else if (this.pressedTop) {
-      annotation.bbox[3] += annotation.bbox[1] - imageCord[1];
-      annotation.bbox[1] = imageCord[1];
-    } else if (this.pressedRight) {
-      annotation.bbox[2] = Math.abs(annotation.bbox[0] - imageCord[0]);
-    } else if (this.pressedLeft) {
-      annotation.bbox[2] += annotation.bbox[0] - imageCord[0];
-      annotation.bbox[0] = imageCord[0];
-    } else if (this.pressedButtom) {
-      annotation.bbox[3] = Math.abs(annotation.bbox[1] - imageCord[1]);
-    } else {
-      annotation.bbox[0] = imageCord[0] + this.offSetX ;
-      annotation.bbox[1] = imageCord[1] + this.offSetY;
-    }
-
-  }
-
-  static mouseUpCreate(imageCords, coco, labelId) {
-    this.isMouseDown = false;
-
-    let reactWidth = imageCords[0] - this.lastImageCordX;
-    let reactHeight = imageCords[1] - this.lastImageCordY;
-
-    if (reactWidth > 0 && reactHeight > 0) {
-      coco.addReactAnnotation(this.lastImageCordX, this.lastImageCordY , reactWidth, reactHeight, labelId);
-      console.log('Add react Label:', this.lastImageCordX, this.lastImageCordY, reactWidth, reactHeight, labelId)
-    }
-   }
-
-  static draw(annotation, label, context, imageXShift, imageYShift, scale) {
-    let bbox = annotation.bbox;
-   // this.drawBox(bbox[0] + imageXShift, bbox[1] + imageYShift, bbox[2], bbox[3], label, color, context, annotation.isHovered);
-
-    if (annotation.isHovered) {
-      context.globalAlpha = this.backgroundHoverAlpha
-    } else if (annotation.isSelected) {
-      context.globalAlpha = this.backgroundHoverAlpha;
-    } else {
-      context.globalAlpha = this.backgroundAlpha;
-    }
-    context.strokeStyle = ColorUtil.getColor(label);
-    context.fillStyle = context.strokeStyle;
-    context.beginPath();
-    context.fillRect(bbox[0] + imageXShift, bbox[1] + imageYShift, bbox[2], bbox[3]);
-    context.globalAlpha = 1;
-    context.strokeRect(bbox[0] + imageXShift, bbox[1] + imageYShift, bbox[2], bbox[3]);
-    context.font = '12px Arial';
-    context.fillText(label, bbox[0] + imageXShift, bbox[1] + imageYShift - 5 );
-    //context.stroke();
-
-    //Control boxes for transformation
-    if (annotation.isSelected) {
-      let size = this.getResizeBoxSize(scale);
-      this.drawTransformBox(bbox[0] + imageXShift, bbox[1] + imageYShift, size, size, context);
-      this.drawTransformBox(bbox[0] + bbox[2] + imageXShift - size, bbox[1] + imageYShift, size, size, context);
-      this.drawTransformBox(bbox[0] + imageXShift, bbox[1] + bbox[3] + imageYShift  - size, size, size, context);
-      this.drawTransformBox( bbox[0] + bbox[2] + imageXShift  - size, bbox[1] + bbox[3] + imageYShift  - size, size, size, context);
-
-      this.drawTransformBox(bbox[0] + imageXShift + size, bbox[1] + imageYShift, annotation.bbox[2] - 2* size, size, context);
-      this.drawTransformBox(bbox[0] + imageXShift, bbox[1] + imageYShift + size, size, annotation.bbox[3] - 2* size, context);
-      this.drawTransformBox(bbox[0] + bbox[2] + imageXShift - size, bbox[1] + imageYShift + size, size, annotation.bbox[3] - 2* size, context);
-      this.drawTransformBox(bbox[0] + imageXShift + size, bbox[1] + bbox[3] + imageYShift - size, annotation.bbox[2] - 2* size, size, context);
-    }
-
-  }
-
-  private static getResizeBoxSize(scale) {
-    return Math.floor(15 / scale);
-  }
-
-  private static drawTransformBox(x, y, widght, heigt, context) {
-    //context.fillStyle = '#fafafa';
-
-    context.beginPath();
-   // context.fillRect(x, y, widght, heigt);
-    //context.strokeStyle = 'black';
-    context.strokeRect(x, y, widght, heigt);
-    context.stroke();
-  }
-
-  private static setSelectedResizeBox(annotation, scale) {
-    this.pressedTopLeft = false;
-    this.pressedTopRight = false;
-    this.pressedButtomLeft = false;
-    this.pressedButtomRight = false;
-    this.pressedTop = false;
-    this.pressedRight = false;
-    this.pressedLeft = false;
-    this.pressedButtom = false;
-
-    let size = this.getResizeBoxSize(scale);
-
-    if (annotation.bbox[0] <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + size  &&
-      annotation.bbox[1] <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + size) {
-      this.pressedTopLeft = true;
-    } else if (annotation.bbox[0] + annotation.bbox[2] - size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + annotation.bbox[2] &&
-      annotation.bbox[1] <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + size) {
-      this.pressedTopRight = true;
-    } else if (annotation.bbox[0] <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + size &&
-      annotation.bbox[1] + annotation.bbox[3] >= this.lastImageCordY && this.lastImageCordY >= annotation.bbox[1] + annotation.bbox[3] - size) {
-      this.pressedButtomLeft = true;
-      return true;
-    } else if (annotation.bbox[0] + annotation.bbox[2] - size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + annotation.bbox[2] &&
-      annotation.bbox[1] + annotation.bbox[3] >= this.lastImageCordY && this.lastImageCordY >= annotation.bbox[1] + annotation.bbox[3] - size) {
-      this.pressedButtomRight = true;
-    } else if(annotation.bbox[0] + size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + annotation.bbox[2] - size  &&
-      annotation.bbox[1] <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + size) {
-      this.pressedTop = true;
-      console.log('pressed top')
-    } else if (annotation.bbox[0] + annotation.bbox[2] - size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + annotation.bbox[2] &&
-      annotation.bbox[1] + size <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + annotation.bbox[3]  - size) {
-      this.pressedRight = true;
-      console.log('pressedRight')
-    } else if (annotation.bbox[0] - size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + size &&
-      annotation.bbox[1] + size <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + annotation.bbox[3]  - size) {
-      this.pressedLeft = true;
-      console.log('pressedLeft')
-    } else if (annotation.bbox[0] + size <= this.lastImageCordX && this.lastImageCordX <= annotation.bbox[0] + annotation.bbox[2] - size  &&
-      annotation.bbox[1] + annotation.bbox[3] - size <= this.lastImageCordY && this.lastImageCordY <= annotation.bbox[1] + annotation.bbox[3]) {
-      this.pressedButtom = true;
-      console.log('pressedButtom')
-    }
-  }
-
-  public static checkIfClicked(imageCords, annotation) {
-    if (annotation.isBox()) {
-      if (annotation.bbox[0] <= imageCords[0] && imageCords[0] <= annotation.bbox[0] + annotation.bbox[2] &&
-        annotation.bbox[1] <= imageCords[1] && imageCords[1] <= annotation.bbox[1] + annotation.bbox[3]
-      ) {
-        return true;
-      }
-    }
-  }
-
-
-}
\ No newline at end of file
diff --git a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.html b/ui/src/app/core-ui/imageLabeler/imageLabeler.component.html
deleted file mode 100644
index fba9a88..0000000
--- a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!--
-  ~ 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>
-    <button mat-stroked-button [style.background-color]="isImageViewingMode() ? 'lightgrey' : 'white'" (click)="setImageViewInteractionMode()">Viewing</button>
-    <button mat-stroked-button [style.background-color]="isImageAnnotateMode() ? 'lightgrey' : 'white'" (click)="setImageAnnotateInteractionMode()">Annotate</button>
-    <button mat-stroked-button [style.background-color]="isImageClassifyMode() ? 'lightgrey' : 'white'" (click)="setImageClassifyInteractionMode()">Classify</button>
-</div>
-
-<div fxLayout="column" fxLayoutAlign="space-between " (mouseover)="enterCanvas()" (mouseout)="leaveCanvas()">
-    <div  fxLayout="row" fxLayoutAlign="space-around start">
-        <div fxLayout="column" fxLayoutAlign="space-around center" *ngIf="isImageAnnotateMode() || isImageClassifyMode()">
-            <h2>Labels</h2>
-            <div  class="labelCategorySelectContainer"
-                 style="padding-left: 5px; padding-right: 5px; border-radius: 50px; font-size: 20px;">
-                <mat-form-field style="margin-top: -15px; margin-bottom: -10px">
-                    <mat-select [(value)]="labelCategory">
-                        <mat-option *ngFor="let labelCategory of labelCategories" [value]="labelCategory">
-                            {{labelCategory}}
-                        </mat-option>
-                    </mat-select>
-                </mat-form-field>
-            </div>
-            <mat-list>
-                <mat-list-item *ngFor="let label of labels[labelCategory]; index as i"
-                               [style.background-color]="selectedLabel == label ? 'lightgrey' : 'white'"
-                               style="height: 30px; padding-top: 5px; padding-buttom: 5px; border-radius: 50px; margin-bottom: 5px"
-                               (click)="selectLabel(label)">
-                    <mat-icon matListIcon [style.color]="getColor(label)" style="margin-top: -8px;">color_lens</mat-icon>
-                    <h4 style="margin-top: -3px;"> {{label}} <label *ngIf="i < 10"> #{{i+1}}</label> </h4>
-                </mat-list-item>
-            </mat-list>
-        </div>
-
-        <div fxLayout="column" fxLayoutAlign="space-around center">
-
-            <div *ngIf="isImageClassifyMode()" style="height: 40px">
-                <mat-chip-list>
-                    <mat-chip *ngFor="let clazz of imageClassification.getClasses()" (removed)="removeClass(clazz)"
-                              [removable]="true" [style.background-color]="getColor(clazz)">
-                        {{clazz}}
-                        <mat-icon matChipRemove>cancel</mat-icon>
-                    </mat-chip>
-                </mat-chip-list>
-            </div>
-
-            <!--
-            <mat-hint>Tip: Move the image with the right mouse button and zoom with the mouse wheel, Use number shortcut to select label</mat-hint>
-            <mat-hint>Tip: Use number 'E' and 'Q' to get previous/next image, Move image with WASD, Delete selected Annotatoin with 'Delete' button</mat-hint>
-            -->
-            <div *ngIf="isImageAnnotateMode()">
-                <button mat-button (click)="imageAnnotation.setReactMode()" [style.background-color]="imageAnnotation.isReactMode() ? 'lightgrey' : 'white'"> <mat-icon>crop_3_2</mat-icon></button>
-                <button mat-button (click)="imageAnnotation.setPolygonMode()" [style.background-color]="imageAnnotation.isPolygonMode() ? 'lightgrey' : 'white'"> <mat-icon>details</mat-icon></button>
-            </div>
-
-            <button mat-button [disabled]="imageAnnotation.saved && imageClassification.saved" (click)="save()"><mat-icon>save</mat-icon></button>
-
-            <canvas (mousedown)="imageMouseDown($event)" (mousemove)="imageMouseMove($event)" (mouseup)="imageMouseUp($event)"
-                    #canvas width="800" height="500" (dblclick)="dblclick($event)">
-                Your browser does not support the canvas element.
-            </canvas>
-            <div class="controlButtons">
-                <button mat-button (click)="zoomin()"> <mat-icon>zoom_in</mat-icon></button>
-                <button mat-button (click)="zoomout()"> <mat-icon>zoom_out</mat-icon></button>
-            </div>
-        </div>
-
-        <div fxLayout="column" fxLayoutAlign="space-between center" *ngIf="isImageAnnotateMode()">
-            <h2>Annotations</h2>
-            <mat-list>
-                <mat-list-item *ngFor="let annotation of imageAnnotation.getAnnotations()" (mouseover)="enterAnnotation(annotation)" (mouseout)="leaveAnnotation(annotation)"
-                               style="height: 30px; 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]="getColor(getLabelById(annotation.category_id))" style="margin-top: -8px;">color_lens</mat-icon>
-                    <mat-form-field>
-                        <mat-select [value]="getLabelById(annotation.category_id)">
-                            <mat-optgroup *ngFor="let labelCategor of labelCategories" [label]="labelCategor">
-                                <mat-option *ngFor="let label of labels[labelCategor]" [value]="label" (click)="changeLabel(annotation, label, labelCategory)">
-                                    {{label}}
-                                </mat-option>
-                            </mat-optgroup>
-                        </mat-select>
-                    </mat-form-field>
-                    <button mat-icon-button (click)="deleteAnnotation(annotation)" style="margin-top: -10px; margin-left: 10px"> <mat-icon>delete_forever</mat-icon></button>
-                </mat-list-item>
-            </mat-list>
-        </div>
-
-
-    </div>
-
-    <br />
-    <br />
-
-    <div fxLayout="row" fxLayoutAlign="space-around center" >
-        <button mat-icon-button (click)="previousImage()"> <mat-icon>keyboard_arrow_left</mat-icon></button>
-
-        <div fxLayout="row" fxLayoutAlign="center " class="imageBar">
-            <img *ngFor="let src of imagesSrcs; let i = index" src="{{src}}" (click)="imagesSrcIndex = i; changeImage(imagesSrcIndex)"
-                 [style.border]="i == imagesSrcIndex ? '5px solid #39b54a' : 'none'">
-        </div>
-
-
-        <button mat-icon-button (click)="nextImage()"> <mat-icon>keyboard_arrow_right</mat-icon></button>
-
-    </div>
-</div>
-
-
-
diff --git a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.ts b/ui/src/app/core-ui/imageLabeler/imageLabeler.component.ts
deleted file mode 100644
index 4e18ce3..0000000
--- a/ui/src/app/core-ui/imageLabeler/imageLabeler.component.ts
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * 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 { AfterViewInit, Component, HostListener, OnInit, ViewChild } from "@angular/core";
-import { ImageTranslationUtil } from "./util/imageTranslation.util";
-import { DatalakeRestService } from "../../core-services/datalake/datalake-rest.service";
-import { ColorUtil } from "./util/color.util";
-import { ImageAnnotation } from "./annotation/imageAnnotation";
-import { InteractionMode } from "./interactionMode";
-import { ImageClassification } from "./classification/imageClassification";
-import { MatSnackBar } from "@angular/material/snack-bar";
-
-@Component({
-  selector: 'sp-image-labeler',
-  templateUrl: './imageLabeler.component.html',
-  styleUrls: ['./imageLabeler.component.css']
-})
-export class ImageLabelerComponent implements OnInit, AfterViewInit {
-
-  @ViewChild('canvas') canvasRef;
-  private canvas;
-  private context;
-
-  private isLeftMouseDown = false;
-  private isRightMouseDown = false;
-
-  //canvas properties
-  private canvasWidth;
-  private canvasHeight;
-  private isHoverComponent;
-
-  //image
-  public imagesSrcs;
-  public imagesSrcIndex;
-  private image;
-  private imageTranslationX = 0;
-  private imageTranslationY = 0;
-
-  public labels;
-  public labelCategories;
-  public labelCategory;
-  private selectedLabel;
-
-  public interactionMode: InteractionMode = InteractionMode.imageAnnotate;
-
-  //scale
-  private scale: number = 1;
-
-
-  constructor(private restService: DatalakeRestService, public imageAnnotation: ImageAnnotation, public imageClassification: ImageClassification,
-              private snackBar: MatSnackBar) {
-
-  }
-
-  ngOnInit(): void {
-    //1. get Image Paths
-    this.imagesSrcs = this.restService.getImageSrcs();
-    this.imagesSrcIndex = 0;
-    //2. get Images
-
-    //3. get Labels
-    this.labels = this.restService.getLabels();
-    this.labelCategories = Object.keys(this.restService.getLabels());
-    this.labelCategory = this.labelCategories[1];
-    this.selectedLabel = this.labels[this.labelCategory][0];
-
-    this.isHoverComponent = false;
-  }
-
-  ngAfterViewInit() {
-    this.canvas = this.canvasRef.nativeElement;
-    this.context = this.canvas.getContext('2d');
-    this.canvasWidth = this.canvas.width;
-    this.canvasHeight= this.canvas.height;
-
-    this.canvas.addEventListener('contextmenu', event => event.preventDefault());
-    this.canvas.addEventListener('DOMMouseScroll',event => this.scroll(event),false);
-    this.canvas.addEventListener('mousewheel',event => this.scroll(event),false);
-
-    this.changeImage('https://cdn.pixabay.com/photo/2017/10/29/21/05/bridge-2900839_1280.jpg');
-    this.context.lineWidth = 2;
-  }
-
-  changeImage(index) {
-    this.image = new Image();
-
-    this.image.onload = () => {
-      let src = this.imagesSrcs[this.imagesSrcIndex]
-      this.imageAnnotation.newImage(src,"Test.png", this.image.width, this.image.height);
-      this.imageClassification.newImage(src);
-      console.log('Image width: ' + this.image.width);
-      console.log('Image height: ' + this.image.height);
-      this.scale = Math.min(1, this.canvasWidth / this.image.width, this.canvasHeight / this.image.height);
-      console.log('Set Scale to: ' + this.scale);
-      this.draw();
-    };
-    this.image.src = this.imagesSrcs[this.imagesSrcIndex];
-  }
-
-  imageMouseDown(e) {
-    if (e.which == 1) {
-      //left click
-      this.isLeftMouseDown = true;
-
-      switch (this.interactionMode) {
-        case InteractionMode.imageAnnotate: this.imageAnnotation.mouseDown(this.getImageCords(e.clientX, e.clientY), this.scale);
-          break;
-      }
-
-    } else if (e.which == 2) {
-      //middle click
-    } else {
-      //right click
-      this.isRightMouseDown = true;
-      ImageTranslationUtil.mouseDown(this.getCanvasCords(e.clientX, e.clientY), this.imageTranslationX, this.imageTranslationY);
-    }
-  }
-
-  imageMouseMove(e) {
-    //TODO solve duplicated code
-    if (this.imageAnnotation.isPolygonLabeling()) {
-      this.startDraw();
-      let imageXShift = (this.canvasWidth - this.image.width) / 2;
-      let imageYShift =(this.canvasHeight - this.image.height) / 2;
-
-      this.imageAnnotation.annotationDraw(imageXShift, imageYShift, this.scale, this.context);
-      this.imageAnnotation.mouseMover(this.getImageCords(e.clientX, e.clientY), imageXShift, imageYShift,
-        this.context, this.selectedLabel);
-      this.endDraw();
-    } else if (this.isLeftMouseDown) {
-
-      switch (this.interactionMode) {
-        case InteractionMode.imageAnnotate: {
-            this.startDraw();
-            let imageXShift = (this.canvasWidth - this.image.width) / 2;
-            let imageYShift =(this.canvasHeight - this.image.height) / 2;
-            this.imageAnnotation.annotationDraw(imageXShift, imageYShift, this.scale, this.context);
-            this.imageAnnotation.mouseMover(this.getImageCords(e.clientX, e.clientY), imageXShift, imageYShift,
-              this.context, this.selectedLabel);
-            this.endDraw();
-          }
-          break;
-      }
-
-    } else if (this.isRightMouseDown) {
-      let translation = ImageTranslationUtil.mouseMove(this.getCanvasCords(e.clientX, e.clientY));
-      this.imageTranslationX = translation[0];
-      this.imageTranslationY = translation[1];
-      this.draw();
-    } else {
-      this.imageAnnotation.annotationHovering(this.getImageCords(e.clientX, e.clientY), this.scale);
-      this.draw();
-    }
-
-  }
-
-  imageMouseUp(e) {
-    if (this.isLeftMouseDown) {
-      this.isLeftMouseDown = false;
-      switch (this.interactionMode) {
-        case InteractionMode.imageAnnotate: {
-            this.imageAnnotation.mouseUp(this.getImageCords(e.clientX, e.clientY), this.selectedLabel, this.labelCategory);
-            if (!this.imageAnnotation.isPolygonLabeling()) {
-              this.draw()
-            }
-        }
-          break;
-      }
-    }
-    if (this.isRightMouseDown) {
-      this.isRightMouseDown = false;
-    }
-  }
-
-  dblclick (e) {
-    if (this.interactionMode = InteractionMode.imageAnnotate) {
-      this.imageAnnotation.dblclick(this.getImageCords(e.clientX, e.clientY), this.selectedLabel, this.labelCategory);
-    }
-  }
-
-  startDraw() {
-    this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
-
-    let newWidth = this.canvasWidth * this.scale;
-    let newHeight = this.canvasHeight * this.scale;
-
-    this.context.save();
-
-    this.context.translate(-((newWidth - this.canvasWidth) / 2) + this.imageTranslationX,
-      -((newHeight - this.canvasHeight) / 2) + this.imageTranslationY);
-    this.context.scale(this.scale, this.scale);
-
-    this.context.drawImage(this.image, this.canvasWidth / 2 - this.image.width / 2, this.canvasHeight / 2 - this.image.height / 2);
-  }
-
-  endDraw() {
-    this.context.restore();
-
-    this.context.beginPath();
-    this.context.globalAlpha = 0.8;
-    this.context.fillStyle = 'lightgrey';
-    this.context.fillRect(0, 0, 50, 20);
-    this.context.globalAlpha = 1;
-    this.context.font = '12px Arial';
-    this.context.fillStyle = 'black';
-    this.context.fillText((Math.round(this.scale  * 100) / 100).toFixed(2) + " x", 5,15);
-    this.context.stroke();
-  }
-
-  draw() {
-    this.startDraw();
-    let imageXShift = (this.canvasWidth - this.image.width) / 2;
-    let imageYShift =(this.canvasHeight - this.image.height) / 2;
-    this.imageAnnotation.annotationDraw(imageXShift, imageYShift, this.scale, this.context);
-    this.endDraw();
-  }
-
-  @HostListener('document:keydown', ['$event'])
-  handleShortCuts(event: KeyboardEvent) {
-    if (this.isHoverComponent) {
-      if (event.code.toLowerCase().includes('digit')) {
-        // Number
-        let value = Number(event.key);
-        if (value != 0 && value <= this.labels[this.labelCategory].length) {
-          this.selectLabel(this.labels[this.labelCategory][value - 1]);
-        }
-      } else {
-        let key = event.key;
-        switch (key.toLowerCase()) {
-          case 'q': this.previousImage();
-            break;
-          case 'e': this.nextImage();
-            break;
-          case 'w': this.imageTranslationY += 5; this.draw();
-            break;
-          case 'a': this.imageTranslationX += 5; this.draw();
-            break;
-          case 's': this.imageTranslationY -= 5; this.draw();
-            break;
-          case 'd': this.imageTranslationX -= 5; this.draw();
-            break;
-          case 'delete': this.imageAnnotation.deleteSelectedAnnotation();
-            this.draw();
-        }
-        if (this.interactionMode == InteractionMode.imageAnnotate) {
-          switch (key.toLowerCase()) {
-            case 'r': this.imageAnnotation.setReactMode();
-              break;
-            case 'f': this.imageAnnotation.setPolygonMode();
-              this.draw();
-          }
-        }
-      }
-    }
-  }
-
-  getColor(label) {
-    return ColorUtil.getColor(label);
-  }
-
-  getCanvasCords(clientX, clientY): [any, any] {
-    return [
-      Math.floor(clientX - this.canvas.getBoundingClientRect().left),
-      Math.floor(clientY - this.canvas.getBoundingClientRect().top),
-    ]
-  }
-
-  getImageCords(clientX, clientY): [any, any] {
-    return [
-      Math.floor(((clientX - this.canvas.getBoundingClientRect().left) / this.scale) - ((this.canvasWidth / this.scale - this.image.width) / 2) - (this.imageTranslationX / this.scale)),
-      Math.floor(((clientY - this.canvas.getBoundingClientRect().top) / this.scale) - ((this.canvasHeight / this.scale - this.image.height) / 2) - (this.imageTranslationY / this.scale)),
-    ]
-  }
-
-  save() {
-    let success: boolean;
-
-    if (!this.imageAnnotation.saved) {
-      success = this.imageAnnotation.save();
-    }
-    if (!this.imageClassification.saved) {
-      success = this.imageClassification.save();
-    }
-    if (success) {
-      this.openSnackBar('Saved');
-    } else {
-      this.openSnackBar('Error while saving');
-    }
-  }
-
-  openSnackBar(message: string) {
-    this.snackBar.open(message, '', {
-      duration: 2000,
-      verticalPosition: 'top',
-      horizontalPosition: 'right'
-    });
-  }
-
-  //UI Callbacks
-
-  nextImage() {
-    if (this.imagesSrcIndex < this.imagesSrcs.length - 1) {
-      this.save();
-      this.imagesSrcIndex++;
-      this.changeImage(this.imagesSrcIndex);
-    }
-  }
-
-  previousImage() {
-    if (this.imagesSrcIndex > 0) {
-      this.save();
-      this.imagesSrcIndex--;
-      this.changeImage(this.imagesSrcIndex);
-    }
-  }
-
-  scroll(e) {
-    this.scale += e.wheelDeltaY * (1/6000);
-    this.draw();
-  }
-
-  zoomin()
-  {
-    this.scale += 0.05;
-    this.draw();
-  }
-  zoomout()
-  {
-    this.scale -= 0.05;
-    this.draw();
-  }
-
-  selectLabel(label) {
-    this.selectedLabel = label;
-    switch (this.interactionMode) {
-      case InteractionMode.imageClassify: this.imageClassification.addClass(label);
-        break;
-    }
-  }
-
-  enterCanvas() {
-    this.isHoverComponent = true;
-  }
-
-  leaveCanvas() {
-    this.isHoverComponent = false;
-  }
-
-  getLabelById(id) {
-    return this.imageAnnotation.getLabelById(id);
-  }
-
-  setImageViewInteractionMode() {
-    this.save();
-    this.interactionMode = InteractionMode.imageViewing;
-  }
-
-  setImageAnnotateInteractionMode() {
-    this.save();
-    this.interactionMode = InteractionMode.imageAnnotate;
-  }
-
-  setImageClassifyInteractionMode() {
-    this.save();
-    this.interactionMode = InteractionMode.imageClassify;
-  }
-
-  isImageViewingMode() {
-    return this.interactionMode == InteractionMode.imageViewing;
-  }
-
-  isImageAnnotateMode() {
-    return this.interactionMode == InteractionMode.imageAnnotate;
-
-  }
-
-  isImageClassifyMode() {
-    return this.interactionMode == InteractionMode.imageClassify;
-  }
-  
-  //annotations ui callbacks
-  
-  enterAnnotation(annotation) {
-    annotation.isHovered = true;
-    this.draw()
-  }
-
-  leaveAnnotation(annotation) {
-    annotation.isHovered = false;
-    this.draw()
-  }
-  
-  deleteAnnotation(annotation) {
-   this.imageAnnotation.deleteAnnotation(annotation);
-   this.draw();
-  }
-
-  changeLabel(annonation, label, category) {
-    this.imageAnnotation.changeLabel(annonation, label, category);
-    this.draw();
-  }
-
-  //classification ui callbacks
-  
-  removeClass(clazz) {
-    this.imageClassification.removeClass(clazz);
-  }
-
-}
diff --git a/ui/src/app/data-explorer/data-explorer.component.html b/ui/src/app/data-explorer/data-explorer.component.html
index 778be74..0c8719e 100644
--- a/ui/src/app/data-explorer/data-explorer.component.html
+++ b/ui/src/app/data-explorer/data-explorer.component.html
@@ -25,8 +25,8 @@
     </div>
 
     <div class="container-fluid">
-
-        <sp-image-labeler></sp-image-labeler>
+        <!--<sp-image-labeler></sp-image-labeler>-->
+        <sp-image></sp-image>