diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts
index 861aae4b718480d9afca1d856ef5d53eef153664..13248f4a0d39349ba8f58b45cbc309246b1c9788 100644
--- a/src/atlasViewer/atlasViewer.component.ts
+++ b/src/atlasViewer/atlasViewer.component.ts
@@ -1,8 +1,8 @@
-import { Component, HostBinding, ViewChild, ViewContainerRef, OnDestroy, OnInit, TemplateRef, AfterViewInit, ElementRef, Renderer2 } from "@angular/core";
+import { Component, HostBinding, ViewChild, ViewContainerRef, OnDestroy, OnInit, TemplateRef, AfterViewInit, Renderer2 } from "@angular/core";
 import { Store, select, ActionsSubject } from "@ngrx/store";
-import { ViewerStateInterface, isDefined, FETCHED_SPATIAL_DATA, UPDATE_SPATIAL_DATA, TOGGLE_SIDE_PANEL, safeFilter, OPEN_SIDE_PANEL, CLOSE_SIDE_PANEL } from "../services/stateStore.service";
-import { Observable, Subscription, combineLatest, interval, merge, of, fromEvent } from "rxjs";
-import { map, filter, distinctUntilChanged, delay, concatMap, debounceTime, withLatestFrom, switchMap, takeUntil, scan, takeLast } from "rxjs/operators";
+import { ViewerStateInterface, isDefined, FETCHED_SPATIAL_DATA, UPDATE_SPATIAL_DATA, safeFilter } from "../services/stateStore.service";
+import { Observable, Subscription, combineLatest, interval, merge, of } from "rxjs";
+import { map, filter, distinctUntilChanged, delay, concatMap, withLatestFrom } from "rxjs/operators";
 import { AtlasViewerDataService } from "./atlasViewer.dataService.service";
 import { WidgetServices } from "./widgetUnit/widgetService.service";
 import { LayoutMainSide } from "../layouts/mainside/mainside.component";
@@ -13,7 +13,6 @@ import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service";
 import { NehubaContainer } from "../ui/nehubaContainer/nehubaContainer.component";
 import { colorAnimation } from "./atlasViewer.animation"
 import { FixedMouseContextualContainerDirective } from "src/util/directives/FixedMouseContextualContainerDirective.directive";
-import { DatabrowserService } from "src/ui/databrowserModule/databrowser.service";
 import { AGREE_COOKIE, AGREE_KG_TOS, SHOW_KG_TOS, SHOW_BOTTOM_SHEET } from "src/services/state/uiState.store";
 import { TabsetComponent } from "ngx-bootstrap/tabs";
 import { LocalFileService } from "src/services/localFile.service";
@@ -37,8 +36,6 @@ const filterFn = (segment) => typeof segment.segment !== 'string'
 })
 
 export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
-
-  @ViewChild('floatingMouseContextualContainer', { read: ViewContainerRef }) floatingMouseContextualContainer: ViewContainerRef
   
   @ViewChild('cookieAgreementComponent', {read: TemplateRef}) cookieAgreementComponent : TemplateRef<any>
   @ViewChild('kgToS', {read: TemplateRef}) kgTosComponent: TemplateRef<any>
@@ -49,7 +46,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
   @ViewChild(FixedMouseContextualContainerDirective) rClContextualMenu: FixedMouseContextualContainerDirective
 
   @ViewChild('mobileMenuTabs') mobileMenuTabs: TabsetComponent
-  @ViewChild('sidenav', { read: ElementRef} ) mobileSideNav: ElementRef
 
   /**
    * required for styling of all child components
@@ -76,7 +72,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
   public dedicatedView$: Observable<string | null>
   public onhoverSegments$: Observable<string[]>
   public onhoverSegmentsForFixed$: Observable<string[]>
-  public onhoverLandmarksForFixed$: Observable<any>
+  
   public onhoverLandmark$ : Observable<{landmarkName: string, datasets: any} | null>
   private subscriptions: Subscription[] = []
 
@@ -104,7 +100,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
     public urlService: AtlasViewerURLService,
     public apiService: AtlasViewerAPIServices,
     private matDialog: MatDialog,
-    private databrowserService: DatabrowserService,
     private dispatcher$: ActionsSubject,
     private rd: Renderer2,
     public localFileService: LocalFileService,
@@ -194,13 +189,16 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
         if(landmark === null)
           return landmark
         const idx = Number(landmark.replace('label=',''))
-        if(isNaN(idx))
-          return `Landmark index could not be parsed as a number: ${landmark}`
-        return  {
-                  landmarkName: spatialDatas[idx].name,
-                  datasets: (spatialDatas[idx].dataset
-                      && spatialDatas[idx].dataset.length)? spatialDatas[idx].dataset : null
-                }
+        if(isNaN(idx)) {
+          console.warn(`Landmark index could not be parsed as a number: ${landmark}`)
+          return {
+            landmarkName: idx
+          }
+        } else {
+          return  {
+            landmarkName: spatialDatas[idx].name
+          }
+        }
       })
     )
 
@@ -218,8 +216,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
     ).pipe(
       map(([segments, onhoverLandmark]) => onhoverLandmark ? null : segments ),
       map(segments => {
-        if (!segments)
-          return null
+        if (!segments) return null
         const filteredSeg = segments.filter(filterFn)
         return filteredSeg.length > 0
           ? segments.map(s => s.segment) 
@@ -234,11 +231,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
       distinctUntilChanged(),
     )
 
-
-    this.subscriptions.push(
-      this.newViewer$.subscribe(template => this.selectedTemplate = template)
-    )
-
     this.subscriptions.push(
       this.selectedParcellation$.subscribe(parcellation => {
         this.selectedParcellation = parcellation
@@ -408,17 +400,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
       withLatestFrom(this.onhoverSegments$),
       map(([_flag, onhoverSegments]) => onhoverSegments || [])
     )
-
-    this.onhoverLandmarksForFixed$ = this.rClContextualMenu.onShow.pipe(
-      withLatestFrom(this.onhoverLandmark$),
-      map(([_flag, onhoverLandmark]) => onhoverLandmark || [])
-    )
-
-    /**
-     * TODO clean up code
-     * do not do this imperatively
-     */
-    this.closeMenuWithSwipe(this.mobileSideNav)
   }
 
   /**
@@ -486,8 +467,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
     this.rClContextualMenu.show()
   }
 
-  private selectedTemplate: any
-
   openLandmarkUrl(dataset) {
     this.rClContextualMenu.hide()
     window.open(dataset.externalLink, "_blank")
@@ -495,48 +474,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
 
   @HostBinding('attr.version')
   public _version : string = VERSION
-
-  /**
-   * TODO deprecated
-   */
-  changeMenuState({open, close}:{open?:boolean, close?:boolean} = {}) {
-    if (open) {
-      return this.store.dispatch({
-        type: OPEN_SIDE_PANEL
-      })
-    }
-    if (close) {
-      return this.store.dispatch({
-        type: CLOSE_SIDE_PANEL
-      })
-    }
-    this.store.dispatch({
-      type: TOGGLE_SIDE_PANEL
-    })
-  }
-
-  closeMenuWithSwipe(documentToSwipe: ElementRef) {
-    if (documentToSwipe && documentToSwipe.nativeElement) {
-      const swipeDistance = 150; // swipe distance
-      const swipeLeft$ = fromEvent(documentToSwipe.nativeElement, 'touchstart')
-          .pipe(
-              switchMap(startEvent =>
-                  fromEvent(documentToSwipe.nativeElement, 'touchmove')
-                      .pipe(
-                          takeUntil(fromEvent(documentToSwipe.nativeElement, 'touchend')),
-                          map(event => event['touches'][0].pageX),
-                          scan((acc, pageX) => Math.round(startEvent['touches'][0].pageX - pageX), 0),
-                          takeLast(1),
-                          filter(difference => difference >= swipeDistance)
-                      )))
-      this.subscriptions.push(
-        swipeLeft$.subscribe(() => {
-          this.changeMenuState({close: true})
-        })
-      )
-    }
-  }
-
 }
 
 export interface NgLayerInterface{
diff --git a/src/atlasViewer/atlasViewer.style.css b/src/atlasViewer/atlasViewer.style.css
index 23c6702a2296eba0c7e0c9b2bfa8fd7d653b1e0c..d8dd38d79c50bdde5e9a19342486d0be3fc0449c 100644
--- a/src/atlasViewer/atlasViewer.style.css
+++ b/src/atlasViewer/atlasViewer.style.css
@@ -50,29 +50,14 @@ layout-floating-container
   margin: 0.8em 0.4em;
 }
 
-div[floatingMouseContextualContainer]
+[contextualBlock]
 {
-  position : absolute;
-  left: 0;
-  top : 0;
-  width : 0px;
-  height: 0px;
-}
-
-div[contextualBlock]
-{
-  margin-top: 1px;
-  white-space: nowrap;
-  display:inline-block;
-  width:auto;
-  padding: 0.3em 0.5em;
   background-color:rgba(200,200,200,0.8);
 }
 
-:host-context([darktheme="true"]) div[contextualBlock]
+:host-context([darktheme="true"]) [contextualBlock]
 {
   background-color : rgba(30,30,30,0.8);
-  color : rgba(250,250,250,0.8);
 }
 
 
diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html
index 6a67f8a11f9113e3b7ddce2e6ba20c949913a26e..65bd7abfbf9c02838ad6b5704cbcaaf88ef966e1 100644
--- a/src/atlasViewer/atlasViewer.template.html
+++ b/src/atlasViewer/atlasViewer.template.html
@@ -46,7 +46,12 @@
 <ng-template #viewerBody>
   <div class="atlas-container" (drag-drop)="localFileService.handleFileDrop($event)">
 
-    <ui-nehuba-container (contextmenu)="$event.stopPropagation(); $event.preventDefault();"> <!--nehubaClickHandler($event)-->
+    <ui-nehuba-container
+      iav-mouse-hover
+      #iavMouseHoverEl="iavMouseHover"
+      [currentOnHoverObs$]="iavMouseHoverEl.currentOnHoverObs$"
+      [currentOnHover]="iavMouseHoverEl.currentOnHoverObs$ | async"
+      (contextmenu)="$event.stopPropagation(); $event.preventDefault();">
     </ui-nehuba-container>
   
     <div class="z-index-10 position-absolute pe-none w-100 h-100">
@@ -104,7 +109,7 @@
     </div>
 
     <div class="d-flex flex-row justify-content-end z-index-10 position-absolute pe-none w-100 h-100">
-      <signin-banner signinWrapper [ngStyle]="{'margin-right': !selectedTemplate? '20px': ''}">
+      <signin-banner signinWrapper>
       </signin-banner>
     </div>
   
@@ -115,7 +120,7 @@
   
       </div>
       
-      <!-- TODO deprecate -->
+      <!-- TODO document fixedMouseContextualContainerDirective , then deprecate this -->
       <!-- TODO move to nehuba overlay container -->
       <panel-component class="shadow" fixedMouseContextualContainerDirective #rClContextMenu>
         <div heading>
@@ -130,23 +135,6 @@
             class="p-2">
             Search for data relating to:
           </div>
-
-          <div *ngIf="(onhoverLandmarksForFixed$ | async) as onhoverLandmarksForFixed">
-            <div *ngIf="onhoverLandmarksForFixed && onhoverLandmarksForFixed.datasets && onhoverLandmarksForFixed.datasets.length > 0">
-              <div class="p-2">
-                Explore datasets for {{onhoverLandmarksForFixed.landmarkName}}
-              </div>
-              <div
-                      *ngFor="let dataset of onhoverLandmarksForFixed.datasets"
-                      class="ws-no-wrap text-left pe-all btn btn-sm btn-secondary btn-block mt-0"
-                      data-toggle="tooltip"
-                      data-placement="top"
-                      (click)="openLandmarkUrl(dataset)"
-                      [title]="dataset.name">
-                {{ dataset.name }} <i class="fas fa-external-link-alt"></i>
-              </div>
-            </div>
-          </div>
           
           <div
             *ngFor="let onhoverSegmentFixed of (onhoverSegmentsForFixed$ | async)"
@@ -187,20 +175,32 @@
         </div>
       </panel-component>
       
-      <div floatingMouseContextualContainer floatingMouseContextualContainerDirective>
-        <div
-          *ngIf="onhoverLandmark$ | async"
-          contextualBlock>
-          {{ (onhoverLandmark$ | async)?.landmarkName }} <i><small class = "mute-text">{{ toggleMessage }}</small></i>
-        </div>
-        <div
-          *ngIf="onhoverSegments$ | async; let onhoverSegments"
+      <div floatingMouseContextualContainerDirective>
+
+        <div class="d-inline-block"
+          iav-mouse-hover
+          #iavMouseHoverConetxtualBlock="iavMouseHover"
           contextualBlock>
-          <div
-            *ngFor="let segment of onhoverSegments"
-            [innerHtml]="segment | transformOnhoverSegment">
-          </div>
-          <i><small class = "mute-text">{{ toggleMessage }}</small></i>
+
+          <ng-container *ngFor="let labelText of iavMouseHoverConetxtualBlock.currentOnHoverObs$ | async | mouseOverTextPipe">
+
+            <mat-list dense>
+
+              <mat-list-item>
+
+                <mat-icon [fontSet]="(labelText.label | mouseOverIconPipe).fontSet"
+                  [fontIcon]="(labelText.label | mouseOverIconPipe).fontIcon"
+                  mat-list-icon>
+
+                </mat-icon>
+                
+                <div matLine
+                  *ngFor="let text of labelText.text"
+                  [innerHTML]="text">
+                </div>
+              </mat-list-item>
+            </mat-list>
+          </ng-container>
         </div>
         <!-- TODO Potentially implementing plugin contextual info -->
       </div>
diff --git a/src/atlasViewer/onhoverSegment.pipe.ts b/src/atlasViewer/onhoverSegment.pipe.ts
index baff7b9d5d1de04b0d6c5327aabf2a41a532ff4f..9119b115f7595ac1d412d6c9728803cd79c0745f 100644
--- a/src/atlasViewer/onhoverSegment.pipe.ts
+++ b/src/atlasViewer/onhoverSegment.pipe.ts
@@ -1,5 +1,5 @@
 import { PipeTransform, Pipe, SecurityContext } from "@angular/core";
-import { DomSanitizer } from "@angular/platform-browser";
+import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
 
 @Pipe({
   name: 'transformOnhoverSegment'
@@ -14,7 +14,7 @@ export class TransformOnhoverSegmentPipe implements PipeTransform{
     return ` <span class="text-muted">(${this.sanitizer.sanitize(SecurityContext.HTML, text)})</span>`
   }
 
-  public transform(segment: any | number){
+  public transform(segment: any | number): SafeHtml{
     return this.sanitizer.bypassSecurityTrustHtml((
       (segment.name || segment) +
       (segment.status
diff --git a/src/main.module.ts b/src/main.module.ts
index 50ba1a22d5d3c4f5fbe8af4980272da10827aad3..6dd663fae585edfc1048ea2c5c8d5dc5beece6f9 100644
--- a/src/main.module.ts
+++ b/src/main.module.ts
@@ -4,7 +4,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop'
 import { UIModule } from "./ui/ui.module";
 import { LayoutModule } from "./layouts/layout.module";
 import { AtlasViewer } from "./atlasViewer/atlasViewer.component";
-import { StoreModule, Store, select } from "@ngrx/store";
+import { StoreModule } from "@ngrx/store";
 import { viewerState, dataStore,spatialSearchState,uiState, ngViewerState, pluginState, viewerConfigState, userConfigState, UserConfigStateUseEffect } from "./services/stateStore.service";
 import { GetNamesPipe } from "./util/pipes/getNames.pipe";
 import { CommonModule } from "@angular/common";
@@ -46,9 +46,10 @@ import { ConfirmDialogComponent } from "./components/confirmDialog/confirmDialog
 import { ViewerStateUseEffect } from "./services/state/viewerState.store";
 import { NgViewerUseEffect } from "./services/state/ngViewerState.store";
 import { DatabrowserModule } from "./ui/databrowserModule/databrowser.module";
+import { UIService } from "./services/uiService.service";
+import { UtilModule } from "./util/util.module";
 
 import 'hammerjs'
-import { UIService } from "./services/uiService.service";
 
 import 'src/res/css/version.css'
 import 'src/theme.scss'
@@ -64,6 +65,7 @@ import 'src/res/css/extra_styles.css'
     UIModule,
     DatabrowserModule,
     AngularMaterialModule,
+    UtilModule,
     
     TooltipModule.forRoot(),
     TabsModule.forRoot(),
diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts
index b58f86c33349151322501584766e2cc3984f9ddb..396ebfe8ea69d2ccce217f87f6ace0de7536421a 100644
--- a/src/services/state/uiState.store.ts
+++ b/src/services/state/uiState.store.ts
@@ -6,7 +6,10 @@ import { LOCAL_STORAGE_CONST, COOKIE_VERSION, KG_TOS_VERSION } from 'src/util/co
 const defaultState : UIStateInterface = {
   mouseOverSegments: [],
   mouseOverSegment: null,
+  
   mouseOverLandmark: null,
+  mouseOverUserLandmark: null,
+
   focusedSidePanel: null,
   sidePanelOpen: false,
 
@@ -34,6 +37,13 @@ export function uiState(state:UIStateInterface = defaultState,action:UIAction){
         ...state,
         mouseOverSegment : action.segment
       }
+    case MOUSEOVER_USER_LANDMARK:
+      const { payload = {} } = action
+      const { userLandmark: mouseOverUserLandmark = null } = payload
+      return {
+        ...state,
+        mouseOverUserLandmark
+      }
     case MOUSE_OVER_LANDMARK:
       return {
         ...state,
@@ -103,10 +113,13 @@ export interface UIStateInterface{
     }
     segment: any | null
   }[]
-  sidePanelOpen : boolean
-  mouseOverSegment : any | number
-  mouseOverLandmark : any 
-  focusedSidePanel : string | null
+  sidePanelOpen: boolean
+  mouseOverSegment: any | number
+
+  mouseOverLandmark: any
+  mouseOverUserLandmark: any
+
+  focusedSidePanel: string | null
 
   snackbarMessage: Symbol
 
@@ -119,7 +132,7 @@ export interface UIStateInterface{
 export interface UIAction extends Action{
   segment: any | number
   landmark: any
-  focusedSidePanel? : string
+  focusedSidePanel?: string
   segments?:{
     layer: {
       name: string
@@ -129,11 +142,14 @@ export interface UIAction extends Action{
   snackbarMessage: string
 
   bottomSheetTemplate: TemplateRef<any>
+
+  payload: any
 }
 
 export const MOUSE_OVER_SEGMENT = `MOUSE_OVER_SEGMENT`
 export const MOUSE_OVER_SEGMENTS = `MOUSE_OVER_SEGMENTS`
 export const MOUSE_OVER_LANDMARK = `MOUSE_OVER_LANDMARK`
+export const MOUSEOVER_USER_LANDMARK = `MOUSEOVER_USER_LANDMARK`
 
 export const TOGGLE_SIDE_PANEL = 'TOGGLE_SIDE_PANEL'
 export const CLOSE_SIDE_PANEL = `CLOSE_SIDE_PANEL`
diff --git a/src/services/state/viewerState.store.ts b/src/services/state/viewerState.store.ts
index 359cf2be6547ee998f73cf05b36b9909ed1e1ae4..5bf19bbae79fdf73b7a0fdc30aa66c6a6fbd873c 100644
--- a/src/services/state/viewerState.store.ts
+++ b/src/services/state/viewerState.store.ts
@@ -3,8 +3,10 @@ import { UserLandmark } from 'src/atlasViewer/atlasViewer.apiService.service';
 import { NgLayerInterface } from 'src/atlasViewer/atlasViewer.component';
 import { Injectable } from '@angular/core';
 import { Actions, Effect, ofType } from '@ngrx/effects';
-import { withLatestFrom, map, shareReplay, startWith, tap } from 'rxjs/operators';
+import { withLatestFrom, map, shareReplay, startWith, filter, distinctUntilChanged } from 'rxjs/operators';
 import { Observable } from 'rxjs';
+import { MOUSEOVER_USER_LANDMARK } from './uiState.store';
+import { generateLabelIndexId } from '../stateStore.service';
 
 export interface ViewerStateInterface{
   fetchedTemplates : any[]
@@ -250,20 +252,132 @@ export class ViewerStateUseEffect{
         }
       })
     )
+
+    this.mouseoverUserLandmarks = this.actions$.pipe(
+      ofType(ACTION_TYPES.MOUSEOVER_USER_LANDMARK_LABEL),
+      withLatestFrom(this.currentLandmarks$),
+      map(([ action, currentLandmarks ]) => {
+        const { payload } = action as any
+        const { label } = payload
+        if (!label) return {
+          type: MOUSEOVER_USER_LANDMARK,
+          payload: {
+            userLandmark: null
+          }
+        }
+
+        const idx = Number(label.replace('label=', ''))
+        if (isNaN(idx)) {
+          console.warn(`Landmark index could not be parsed as a number: ${idx}`)
+          return {
+            type: MOUSEOVER_USER_LANDMARK,
+            payload: {
+              userLandmark: null
+            }
+          }
+        }
+
+        return {
+          type: MOUSEOVER_USER_LANDMARK,
+          payload: {
+            userLandmark: currentLandmarks[idx]
+          }
+        }
+      })
+
+    )
+
+    const doubleClickOnViewer$ = this.actions$.pipe(
+      ofType(ACTION_TYPES.DOUBLE_CLICK_ON_VIEWER),
+      map(action => {
+        const { payload } = action as any
+        const { segments, landmark, userLandmark } = payload
+        return { segments, landmark, userLandmark }
+      }),
+      shareReplay(1)
+    )
+
+    this.doubleClickOnViewerToggleRegions$ = doubleClickOnViewer$.pipe(
+      filter(({ segments }) => segments && segments.length > 0),
+      withLatestFrom(this.store$.pipe(
+        select('viewerState'),
+        select('regionsSelected'),
+        distinctUntilChanged(),
+        startWith([])
+      )),
+      map(([{ segments }, regionsSelected]) => {
+        const selectedSet = new Set(regionsSelected.map(generateLabelIndexId))
+        const toggleArr = segments.map(({ segment, layer }) => generateLabelIndexId({ ngId: layer.name, ...segment }))
+
+        const deleteFlag = toggleArr.some(id => selectedSet.has(id))
+
+        for (const id of toggleArr){
+          if (deleteFlag) selectedSet.delete(id)
+          else selectedSet.add(id)
+        }
+        
+        return {
+          type: SELECT_REGIONS_WITH_ID,
+          selectRegionIds: [...selectedSet]
+        }
+      })
+    )
+
+    this.doubleClickOnViewerToggleLandmark$ = doubleClickOnViewer$.pipe(
+      filter(({ landmark }) => !!landmark),
+      withLatestFrom(this.store$.pipe(
+        select('viewerState'),
+        select('landmarksSelected'),
+        startWith([])
+      )),
+      map(([{ landmark }, selectedSpatialDatas]) => {
+
+        const selectedIdx = selectedSpatialDatas.findIndex(data => data.name === landmark.name)
+
+        const newSelectedSpatialDatas = selectedIdx >= 0
+          ? selectedSpatialDatas.filter((_, idx) => idx !== selectedIdx)
+          : selectedSpatialDatas.concat(landmark)
+
+        return {
+          type: SELECT_LANDMARKS,
+          landmarks: newSelectedSpatialDatas
+        }
+      })
+    )
+
+    this.doubleClickOnViewerToogleUserLandmark$ = doubleClickOnViewer$.pipe(
+      filter(({ userLandmark }) => userLandmark)
+    )
   }
 
   private currentLandmarks$: Observable<any[]>
 
+  @Effect()
+  mouseoverUserLandmarks: Observable<any>
+
   @Effect()
   removeUserLandmarks: Observable<any>
 
   @Effect()
   addUserLandmarks$: Observable<any>
+
+  @Effect()
+  doubleClickOnViewerToggleRegions$: Observable<any>
+
+  @Effect()
+  doubleClickOnViewerToggleLandmark$: Observable<any>
+
+  // @Effect()
+  doubleClickOnViewerToogleUserLandmark$: Observable<any>
 }
 
 const ACTION_TYPES = {
   ADD_USERLANDMARKS: `ADD_USERLANDMARKS`,
-  REMOVE_USER_LANDMARKS: 'REMOVE_USER_LANDMARKS'
+  REMOVE_USER_LANDMARKS: 'REMOVE_USER_LANDMARKS',
+  MOUSEOVER_USER_LANDMARK_LABEL: 'MOUSEOVER_USER_LANDMARK_LABEL',
+
+  SINGLE_CLICK_ON_VIEWER: 'SINGLE_CLICK_ON_VIEWER',
+  DOUBLE_CLICK_ON_VIEWER: 'DOUBLE_CLICK_ON_VIEWER'
 }
 
 export const VIEWERSTATE_ACTION_TYPES = ACTION_TYPES
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index c0fe9adee278ef8c31425492f5e03dae84017cac..35899d499480c8887c7923c2f7bd72a91b14610f 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -1,9 +1,9 @@
-import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentFactory, ComponentRef, OnInit, OnDestroy, ElementRef } from "@angular/core";
+import { Component, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentFactory, ComponentRef, OnInit, OnDestroy, ElementRef, Input, OnChanges } from "@angular/core";
 import { NehubaViewerUnit, computeDistance } from "./nehubaViewer/nehubaViewer.component";
 import { Store, select } from "@ngrx/store";
-import { ViewerStateInterface, safeFilter, CHANGE_NAVIGATION, isDefined, ADD_NG_LAYER, REMOVE_NG_LAYER, NgViewerStateInterface, MOUSE_OVER_LANDMARK, SELECT_LANDMARKS, Landmark, PointLandmarkGeometry, PlaneLandmarkGeometry, OtherLandmarkGeometry, getNgIds, getMultiNgIdsRegionsLabelIndexMap, generateLabelIndexId, DataEntry } from "src/services/stateStore.service";
+import { ViewerStateInterface, safeFilter, CHANGE_NAVIGATION, isDefined, ADD_NG_LAYER, REMOVE_NG_LAYER, NgViewerStateInterface, MOUSE_OVER_LANDMARK, Landmark, PointLandmarkGeometry, PlaneLandmarkGeometry, OtherLandmarkGeometry, getNgIds, getMultiNgIdsRegionsLabelIndexMap, generateLabelIndexId, DataEntry } from "src/services/stateStore.service";
 import { Observable, Subscription, fromEvent, combineLatest, merge, of } from "rxjs";
-import { filter,map, take, scan, debounceTime, distinctUntilChanged, switchMap, skip, withLatestFrom, buffer, tap, switchMapTo, shareReplay, mapTo, takeUntil } from "rxjs/operators";
+import { filter,map, take, scan, debounceTime, distinctUntilChanged, switchMap, skip, buffer, tap, switchMapTo, shareReplay, mapTo, takeUntil, throttleTime } from "rxjs/operators";
 import { AtlasViewerAPIServices, UserLandmark } from "../../atlasViewer/atlasViewer.apiService.service";
 import { timedValues } from "../../util/generator";
 import { AtlasViewerConstantsServices } from "../../atlasViewer/atlasViewer.constantService.service";
@@ -87,7 +87,7 @@ const scanFn : (acc:[boolean, boolean, boolean], curr: CustomEvent) => [boolean,
   ]
 })
 
-export class NehubaContainer implements OnInit, OnDestroy{
+export class NehubaContainer implements OnInit, OnChanges, OnDestroy{
 
   @ViewChild('container',{read:ViewContainerRef}) container : ViewContainerRef
 
@@ -112,10 +112,16 @@ export class NehubaContainer implements OnInit, OnDestroy{
 
   private fetchedSpatialDatasets$ : Observable<Landmark[]>
   private userLandmarks$ : Observable<UserLandmark[]>
-  public onHoverSegmentName$ : Observable<string>
+  
   public onHoverSegment$ : Observable<any>
+
+  @Input()
+  private currentOnHover: {segments:any, landmark:any, userLandmark: any}
+
+  @Input()
+  private currentOnHoverObs$: Observable<{segments:any, landmark:any, userLandmark: any}>
+
   public onHoverSegments$: Observable<any[]>
-  private onHoverLandmark$ : Observable<any|null>
 
   private navigationChanges$ : Observable<any>
   public spatialResultsVisible$ : Observable<boolean>
@@ -272,111 +278,6 @@ export class NehubaContainer implements OnInit, OnDestroy{
       distinctUntilChanged()
     )
 
-    this.onHoverSegments$ = this.store.pipe(
-      select('uiState'),
-      select('mouseOverSegments'),
-      filter(v => !!v),
-      distinctUntilChanged((o, n) => o.length === n.length
-        && n.every(segment =>
-          o.find(oSegment => oSegment.layer.name === segment.layer.name
-            && oSegment.segment === segment.segment)))
-    )
-
-    const sortByFreshness: (acc: any[], curr: any[]) => any[] = (acc, curr) => {
-
-      const getLayerName = ({layer} = {layer:{}}) => {
-        const { name } = <any>layer
-        return name
-      }
-
-      const newEntries = curr.filter(entry => {
-        const name = getLayerName(entry)
-        return acc.map(getLayerName).indexOf(name) < 0
-      })
-
-      const entryChanged: (itemPrevState, newArr) => boolean = (itemPrevState, newArr) => {
-        const layerName = getLayerName(itemPrevState)
-        const { segment } = itemPrevState
-        const foundItem = newArr.find((_item) =>
-          getLayerName(_item) === layerName)
-
-        if (foundItem) {
-          const { segment:foundSegment } = foundItem
-          return segment !== foundSegment 
-        } else {
-          /**
-           * if item was not found in the new array, meaning hovering nothing
-           */
-          return segment !== null
-        }
-      }
-
-      const getItemFromLayerName = (item, arr) => {
-        const foundItem = arr.find(i => getLayerName(i) === getLayerName(item))
-        return foundItem
-          ? foundItem
-          : {
-            layer: item.layer,
-            segment: null
-          }
-      }
-
-      const getReduceExistingLayers = (newArr) => ([changed, unchanged], _curr) => {
-        const changedFlag = entryChanged(_curr, newArr)
-        return changedFlag
-          ? [ changed.concat( getItemFromLayerName(_curr, newArr) ), unchanged ]
-          : [ changed, unchanged.concat(_curr) ]
-      }
-
-      /**
-       * now, for all the previous layers, separate into changed and unchanged layers
-       */
-      const [changed, unchanged] = acc.reduce(getReduceExistingLayers(curr), [[], []])
-      return [...newEntries, ...changed, ...unchanged]
-    } 
-
-    this.onHoverSegment$ = this.onHoverSegments$.pipe(
-      scan(sortByFreshness, []),
-      /**
-       * take the first element after sort by freshness
-       */
-      map(arr => arr[0]),
-      /**
-       * map to the older interface
-       */
-      filter(v => !!v),
-      map(({ segment }) => {
-
-        return {
-          labelIndex: (isNaN(segment) && Number(segment.labelIndex)) || null,
-          foundRegion: (isNaN(segment) && segment) || null
-        }
-      })
-    )
-
-    this.onHoverLandmark$ = this.store.pipe(
-      select('uiState'),
-      filter(state => isDefined(state)),
-      map(state => state.mouseOverLandmark)
-    )
-
-    // TODO hack, even though octant is hidden, it seems with VTK, one can highlight
-    this.onHoverSegmentName$ = combineLatest(
-      this.store.pipe(
-        select('uiState'),
-        filter(state=>isDefined(state)),
-        map(state=>state.mouseOverSegment ?
-          state.mouseOverSegment.constructor === Number ? 
-            state.mouseOverSegment.toString() : 
-            state.mouseOverSegment.name :
-          '' ),
-        distinctUntilChanged()
-      ),
-      this.onHoverLandmark$
-    ).pipe(
-      map(results => results[1] === null ? results[0] : '')
-    )
-
     this.sliceViewLoadingMain$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent').pipe(
       scan(scanFn, [null, null, null]),
       shareReplay(1)
@@ -552,6 +453,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
       shareReplay(1)
     )
 
+    // TODO deprecate
     /* each time a new viewer is initialised, take the first event to get the translation function */
     this.subscriptions.push(
       this.newViewer$.pipe(
@@ -833,11 +735,11 @@ export class NehubaContainer implements OnInit, OnDestroy{
       this.navigationChanges$,
       this.selectedRegions$,
     ).subscribe(([navigation,regions])=>{
-      this.nehubaViewer.initNav = 
-        Object.assign({},navigation,{
-          positionReal : true
-        })
-      this.nehubaViewer.initRegions = regions.map(({ ngId, labelIndex }) =>generateLabelIndexId({ ngId, labelIndex }))
+      this.nehubaViewer.initNav = {
+        ...navigation,
+        positionReal: true
+      }
+      this.nehubaViewer.initRegions = regions.map(({ ngId, labelIndex }) => generateLabelIndexId({ ngId, labelIndex }))
     })
 
     this.subscriptions.push(
@@ -845,18 +747,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
     )
 
     /* handler to open/select landmark */
-    const clickObs$ = fromEvent(this.elementRef.nativeElement, 'click').pipe(
-        withLatestFrom(this.onHoverLandmark$),
-        filter(results => results[1] !== null),
-        map(results => results[1]),
-        withLatestFrom(
-          this.store.pipe(
-            select('dataStore'),
-            safeFilter('fetchedSpatialData'),
-            map(state => state.fetchedSpatialData)
-          )
-        )
-      )
+    const clickObs$ = fromEvent(this.elementRef.nativeElement, 'click')
 
     this.subscriptions.push(
       clickObs$.pipe(
@@ -865,39 +756,14 @@ export class NehubaContainer implements OnInit, OnDestroy{
             debounceTime(200)
           )
         ),
-        filter(arr => arr.length >= 2),
-        map(arr => [...arr].reverse()[0]),
-        withLatestFrom(this.selectedLandmarks$)
+        filter(arr => arr.length >= 2)
       )
-        .subscribe(([clickObs, selectedSpatialDatas]) => {
-          const [landmark, spatialDatas] = clickObs
-          const idx = Number(landmark.replace('label=',''))
-          if(isNaN(idx)){
-            console.warn(`Landmark index could not be parsed as a number: ${landmark}`)
-            return
-          }
-
-          const newSelectedSpatialDatas = selectedSpatialDatas.findIndex(data => data.name === spatialDatas[idx].name) >= 0
-            ? selectedSpatialDatas.filter(v => v.name !== spatialDatas[idx].name)
-            : selectedSpatialDatas.concat(Object.assign({}, spatialDatas[idx], {_label: landmark}) )
-          
+        .subscribe(() => {
+          const { currentOnHover } = this
           this.store.dispatch({
-            type : SELECT_LANDMARKS,
-            landmarks : newSelectedSpatialDatas
+            type : VIEWERSTATE_ACTION_TYPES.DOUBLE_CLICK_ON_VIEWER,
+            payload: { ...currentOnHover }
           })
-          // if(this.datasetViewerRegistry.has(spatialDatas[idx].name)){
-          //   return
-          // }
-          // this.datasetViewerRegistry.add(spatialDatas[idx].name)
-          // const comp = this.datasetViewerFactory.create(this.injector)
-          // comp.instance.dataset = spatialDatas[idx]
-          // comp.onDestroy(() => this.datasetViewerRegistry.delete(spatialDatas[idx].name))
-          // this.widgetServices.addNewWidget(comp, {
-          //   exitable : true,
-          //   persistency : false,
-          //   state : 'floating',
-          //   title : `Spatial Dataset - ${spatialDatas[idx].name}`
-          // })
         })
     )
 
@@ -919,7 +785,85 @@ export class NehubaContainer implements OnInit, OnDestroy{
   public showObliqueSelection$ : Observable<boolean>
   public showObliqueRotate$ : Observable<boolean>
 
-  ngAfterViewInit(){
+  ngOnChanges(){
+    if (this.currentOnHoverObs$) {
+      this.onHoverSegments$ = this.currentOnHoverObs$.pipe(
+        map(({ segments }) => segments)
+      )
+
+      const sortByFreshness: (acc: any[], curr: any[]) => any[] = (acc, curr) => {
+
+        const getLayerName = ({layer} = {layer:{}}) => {
+          const { name } = <any>layer
+          return name
+        }
+  
+        const newEntries = curr.filter(entry => {
+          const name = getLayerName(entry)
+          return acc.map(getLayerName).indexOf(name) < 0
+        })
+  
+        const entryChanged: (itemPrevState, newArr) => boolean = (itemPrevState, newArr) => {
+          const layerName = getLayerName(itemPrevState)
+          const { segment } = itemPrevState
+          const foundItem = newArr.find((_item) =>
+            getLayerName(_item) === layerName)
+  
+          if (foundItem) {
+            const { segment:foundSegment } = foundItem
+            return segment !== foundSegment 
+          } else {
+            /**
+             * if item was not found in the new array, meaning hovering nothing
+             */
+            return segment !== null
+          }
+        }
+  
+        const getItemFromLayerName = (item, arr) => {
+          const foundItem = arr.find(i => getLayerName(i) === getLayerName(item))
+          return foundItem
+            ? foundItem
+            : {
+              layer: item.layer,
+              segment: null
+            }
+        }
+  
+        const getReduceExistingLayers = (newArr) => ([changed, unchanged], _curr) => {
+          const changedFlag = entryChanged(_curr, newArr)
+          return changedFlag
+            ? [ changed.concat( getItemFromLayerName(_curr, newArr) ), unchanged ]
+            : [ changed, unchanged.concat(_curr) ]
+        }
+  
+        /**
+         * now, for all the previous layers, separate into changed and unchanged layers
+         */
+        const [changed, unchanged] = acc.reduce(getReduceExistingLayers(curr), [[], []])
+        return [...newEntries, ...changed, ...unchanged]
+      } 
+
+      // TODO to be deprected soon
+
+      this.onHoverSegment$ = this.onHoverSegments$.pipe(
+        scan(sortByFreshness, []),
+        /**
+         * take the first element after sort by freshness
+         */
+        map(arr => arr[0]),
+        /**
+         * map to the older interface
+         */
+        filter(v => !!v),
+        map(({ segment }) => {
+          return {
+            labelIndex: (isNaN(segment) && Number(segment.labelIndex)) || null,
+            foundRegion: (isNaN(segment) && segment) || null
+          }
+        })
+      )
+    }
   }
 
   ngOnDestroy(){
@@ -971,6 +915,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
     return this.returnTruePos(quadrant,data)[2]
   }
 
+  // handles mouse enter/leave landmarks in 2D
   handleMouseEnterLandmark(spatialData:any){
     spatialData.highlight = true
     this.store.dispatch({
@@ -1111,7 +1056,9 @@ export class NehubaContainer implements OnInit, OnDestroy{
     )
 
     this.nehubaViewerSubscriptions.push(
-      this.nehubaViewer.mouseoverLandmarkEmitter.subscribe(label => {
+      this.nehubaViewer.mouseoverLandmarkEmitter.pipe(
+        throttleTime(100)
+      ).subscribe(label => {
         this.store.dispatch({
           type : MOUSE_OVER_LANDMARK,
           landmark : label
@@ -1119,33 +1066,15 @@ export class NehubaContainer implements OnInit, OnDestroy{
       })
     )
 
-    // TODO hack, even though octant is hidden, it seems with vtk one can mouse on hover
     this.nehubaViewerSubscriptions.push(
-      this.nehubaViewer.regionSelectionEmitter.pipe(
-        withLatestFrom(this.onHoverLandmark$),
-        filter(results => results[1] === null),
-        withLatestFrom(this.onHoverSegments$),
-        map(results => results[1]),
-        filter(arr => arr.length > 0),
-        map(arr => {
-          return arr.map(({ layer, segment }) => {
-            const ngId = segment.ngId || layer.name
-            const labelIndex = segment.labelIndex
-            return generateLabelIndexId({ ngId, labelIndex })
-          })
-        })
-      ).subscribe((ids:string[]) => {
-        const deselectFlag = ids.some(id => this.selectedRegionIndexSet.has(id))
-
-        const set = new Set(this.selectedRegionIndexSet)
-        if (deselectFlag) {
-          ids.forEach(id => set.delete(id))
-        } else {
-          ids.forEach(id => set.add(id))
-        }
+      this.nehubaViewer.mouseoverUserlandmarkEmitter.pipe(
+        throttleTime(160)
+      ).subscribe(label => {
         this.store.dispatch({
-          type: SELECT_REGIONS_WITH_ID,
-          selectRegionIds: [...set]
+          type: VIEWERSTATE_ACTION_TYPES.MOUSEOVER_USER_LANDMARK_LABEL,
+          payload: {
+            label
+          }
         })
       })
     )
@@ -1271,6 +1200,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
     }
   }
 
+  // TODO deprecate
   handleNavigationPositionAndNavigationZoomChange(navigation){
     if(!navigation.position){
       return
diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html
index 32cf2f9b7c437e9e9317e7cc05d214e2eebd6f06..d2c23e12870634e5402ebd87272dfa7869281a2d 100644
--- a/src/ui/nehubaContainer/nehubaContainer.template.html
+++ b/src/ui/nehubaContainer/nehubaContainer.template.html
@@ -44,7 +44,6 @@
     *ngIf="!(useMobileUI$ | async)"
     [selectedTemplate]="selectedTemplate"
     [isMobile]="useMobileUI$ | async"
-    [onHoverSegmentName]="onHoverSegmentName$ | async"
     [nehubaViewer]="nehubaViewer">
   </ui-status-card>
 </layout-floating-container>
@@ -190,7 +189,7 @@
     <!-- place holder when no fav data is available -->
     <mat-card *ngIf="(!(favDataEntries$ | async)) || (favDataEntries$ | async).length === 0">
       <mat-card-content class="muted">
-        No pinned dataset ... yet.
+        No pinned datasets.
       </mat-card-content>
     </mat-card>
 
diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
index f4131f84bc6473b0efec458eb409a5afc5e4ad49..3d86c2cfe5915ad9959032433c08099d164f6fbf 100644
--- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
+++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
@@ -60,6 +60,7 @@ export class NehubaViewerUnit implements OnInit, OnDestroy{
       }
     }> = new EventEmitter()
   @Output() mouseoverLandmarkEmitter : EventEmitter<number | null> = new EventEmitter()
+  @Output() mouseoverUserlandmarkEmitter: EventEmitter<number | null> = new EventEmitter()
   @Output() regionSelectionEmitter : EventEmitter<{segment:number, layer:{name?: string, url?: string}}> = new EventEmitter()
   @Output() errorEmitter : EventEmitter<any> = new EventEmitter()
 
@@ -368,9 +369,9 @@ export class NehubaViewerUnit implements OnInit, OnDestroy{
       //   [0,1,2].forEach(idx => this.viewportToDatas[idx] = events[idx].detail.viewportToData)
       // })
       pipeFromArray([...takeOnePipe])(fromEvent(this.elementRef.nativeElement, 'viewportToData'))
-      .subscribe((events:CustomEvent[]) => {
-        [0,1,2].forEach(idx => this.viewportToDatas[idx] = events[idx].detail.viewportToData)
-      })
+        .subscribe((events:CustomEvent[]) => {
+          [0,1,2].forEach(idx => this.viewportToDatas[idx] = events[idx].detail.viewportToData)
+        })
     )
   }
 
@@ -770,6 +771,12 @@ export class NehubaViewerUnit implements OnInit, OnDestroy{
         .subscribe(obj => this.mouseoverLandmarkEmitter.emit(obj.value))
     )
 
+    this.ondestroySubscriptions.push(
+      this.nehubaViewer.mouseOver.layer
+        .filter(obj => obj.layer.name === this.constantService.ngUserLandmarkLayerName)
+        .subscribe(obj => this.mouseoverUserlandmarkEmitter.emit(obj.value))
+    )
+
     this._s4$ = this.nehubaViewer.navigationState.position.inRealSpace
       .filter(v=>typeof v !== 'undefined' && v !== null)
       .subscribe(v=>this.navPosReal=v)
diff --git a/src/ui/searchSideNav/searchSideNav.component.ts b/src/ui/searchSideNav/searchSideNav.component.ts
index 21ee2294c33fc2db0ceefac48dd27e7e5d6db6f3..fe072947e18e765d9d9da4664bf0dcf65fc45a66 100644
--- a/src/ui/searchSideNav/searchSideNav.component.ts
+++ b/src/ui/searchSideNav/searchSideNav.component.ts
@@ -5,7 +5,7 @@ import { LayerBrowser } from "../layerbrowser/layerbrowser.component";
 import { Observable, Subscription } from "rxjs";
 import { Store, select } from "@ngrx/store";
 import { map, startWith, scan, filter, mapTo } from "rxjs/operators";
-import { VIEWERSTATE_ACTION_TYPES } from "../viewerStateController/viewerState.base";
+import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "../viewerStateController/viewerState.base";
 import { trackRegionBy } from '../viewerStateController/regionHierachy/regionHierarchy.component'
 
 @Component({
@@ -79,7 +79,7 @@ export class SearchSideNav implements OnInit, OnDestroy {
 
   removeRegion(region: any){
     this.store$.dispatch({
-      type: VIEWERSTATE_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY,
+      type: VIEWERSTATE_CONTROLLER_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY,
       payload: { region }
     })
   }
diff --git a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
index e32fa8cb4e4e58760e373c2857d37b454f423584..e34a1fd34a17713358efeff465b7ea1028bf47a0 100644
--- a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
+++ b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts
@@ -6,7 +6,7 @@ import { getMultiNgIdsRegionsLabelIndexMap, generateLabelIndexId } from "src/ser
 import { FormControl } from "@angular/forms";
 import { MatAutocompleteSelectedEvent, MatDialog } from "@angular/material";
 import { ADD_TO_REGIONS_SELECTION_WITH_IDS, SELECT_REGIONS } from "src/services/state/viewerState.store";
-import { VIEWERSTATE_ACTION_TYPES } from "../viewerState.base";
+import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "../viewerState.base";
 import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service";
 
 const filterRegionBasedOnText = searchTerm => region => region.name.toLowerCase().includes(searchTerm.toLowerCase())
@@ -127,9 +127,9 @@ export class RegionTextSearchAutocomplete{
   // TODO handle mobile
   handleRegionClick({ mode = null, region = null } = {}){
     const type = mode === 'single'
-      ? VIEWERSTATE_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY
+      ? VIEWERSTATE_CONTROLLER_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY
       : mode === 'double'
-        ? VIEWERSTATE_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY
+        ? VIEWERSTATE_CONTROLLER_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY
         : ''
     this.store$.dispatch({
       type,
diff --git a/src/ui/viewerStateController/regionsListView/currentlySelectedRegions/currentlySelectedRegions.component.ts b/src/ui/viewerStateController/regionsListView/currentlySelectedRegions/currentlySelectedRegions.component.ts
index 7b02be507c2ad53a7c7ddfeea986bdef57aab2c7..15dd459928e4e730535da6831a0dc06bc173818d 100644
--- a/src/ui/viewerStateController/regionsListView/currentlySelectedRegions/currentlySelectedRegions.component.ts
+++ b/src/ui/viewerStateController/regionsListView/currentlySelectedRegions/currentlySelectedRegions.component.ts
@@ -3,7 +3,7 @@ import { Store, select } from "@ngrx/store";
 import { Observable } from "rxjs";
 import { distinctUntilChanged, startWith } from "rxjs/operators";
 import { DESELECT_REGIONS } from "src/services/state/viewerState.store";
-import { VIEWERSTATE_ACTION_TYPES } from "src/ui/viewerStateController/viewerState.base";
+import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "src/ui/viewerStateController/viewerState.base";
 
 @Component({
   selector: 'currently-selected-regions',
@@ -39,7 +39,7 @@ export class CurrentlySelectedRegions {
 
   public gotoRegion(event: MouseEvent, region:any){
     this.store$.dispatch({
-      type: VIEWERSTATE_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY,
+      type: VIEWERSTATE_CONTROLLER_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY,
       payload: { region }
     })
   }
diff --git a/src/ui/viewerStateController/viewerState.base.ts b/src/ui/viewerStateController/viewerState.base.ts
index 72d3b99c7c4302e525d7258781ce50307f8f7581..957be297a44f2f030fa0c0e84d7a697043239b2f 100644
--- a/src/ui/viewerStateController/viewerState.base.ts
+++ b/src/ui/viewerStateController/viewerState.base.ts
@@ -209,6 +209,7 @@ const ACTION_TYPES = {
   DOUBLE_CLICK_ON_REGIONHIERARCHY: 'DOUBLE_CLICK_ON_REGIONHIERARCHY',
   SELECT_TEMPLATE_WITH_NAME: 'SELECT_TEMPLATE_WITH_NAME',
   SELECT_PARCELLATION_WITH_NAME: 'SELECT_PARCELLATION_WITH_NAME',
+
 }
 
-export const VIEWERSTATE_ACTION_TYPES = ACTION_TYPES
+export const VIEWERSTATE_CONTROLLER_ACTION_TYPES = ACTION_TYPES
diff --git a/src/ui/viewerStateController/viewerState.useEffect.ts b/src/ui/viewerStateController/viewerState.useEffect.ts
index 3b5e4a625304e0335eec195ee4696730e3d47d3d..4dc0831faf978faf05d2ea2a3152a9714c2541bf 100644
--- a/src/ui/viewerStateController/viewerState.useEffect.ts
+++ b/src/ui/viewerStateController/viewerState.useEffect.ts
@@ -3,7 +3,7 @@ import { Injectable, OnInit, OnDestroy } from "@angular/core";
 import { Actions, ofType, Effect } from "@ngrx/effects";
 import { Store, select, Action } from "@ngrx/store";
 import { shareReplay, distinctUntilChanged, map, withLatestFrom, filter } from "rxjs/operators";
-import { VIEWERSTATE_ACTION_TYPES } from "./viewerState.base";
+import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "./viewerState.base";
 import { CHANGE_NAVIGATION, SELECT_REGIONS, NEWVIEWER, GENERAL_ACTION_TYPES, SELECT_PARCELLATION, isDefined } from "src/services/stateStore.service";
 import { regionFlattener } from "src/util/regionFlattener";
 import { UIService } from "src/services/uiService.service";
@@ -46,7 +46,7 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
     )
 
     this.selectParcellationWithName$ = this.actions$.pipe(
-      ofType(VIEWERSTATE_ACTION_TYPES.SELECT_PARCELLATION_WITH_NAME),
+      ofType(VIEWERSTATE_CONTROLLER_ACTION_TYPES.SELECT_PARCELLATION_WITH_NAME),
       map(action => {
         const { payload = {} } = action as ViewerStateAction
         const { name } = payload
@@ -84,7 +84,7 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
     )
     
     this.selectTemplateWithName$ = this.actions$.pipe(
-      ofType(VIEWERSTATE_ACTION_TYPES.SELECT_TEMPLATE_WITH_NAME),
+      ofType(VIEWERSTATE_CONTROLLER_ACTION_TYPES.SELECT_TEMPLATE_WITH_NAME),
       map(action => {
         const { payload = {} } = action as ViewerStateAction
         const { name } = payload
@@ -121,7 +121,7 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
     )
 
     this.doubleClickOnHierarchy$ = this.actions$.pipe(
-      ofType(VIEWERSTATE_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY),
+      ofType(VIEWERSTATE_CONTROLLER_ACTION_TYPES.DOUBLE_CLICK_ON_REGIONHIERARCHY),
       map(action => {
         const { payload = {} } = action as ViewerStateAction
         const { region } = payload
@@ -155,7 +155,7 @@ export class ViewerStateControllerUseEffect implements OnInit, OnDestroy{
     )
 
     this.singleClickOnHierarchy$ = this.actions$.pipe(
-      ofType(VIEWERSTATE_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY),
+      ofType(VIEWERSTATE_CONTROLLER_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY),
       withLatestFrom(this.selectedRegions$),
       map(([action, regionsSelected]) => {
 
diff --git a/src/util/directives/floatingMouseContextualContainer.directive.ts b/src/util/directives/floatingMouseContextualContainer.directive.ts
index 2f62b11aac7311055c9023ba1c32e83077807bbb..556052c751cc5953c797ed7bdbf3883dcdd744ae 100644
--- a/src/util/directives/floatingMouseContextualContainer.directive.ts
+++ b/src/util/directives/floatingMouseContextualContainer.directive.ts
@@ -1,4 +1,5 @@
 import { Directive, HostListener, HostBinding } from "@angular/core";
+import { DomSanitizer, SafeUrl } from "@angular/platform-browser";
 
 @Directive({
   selector: '[floatingMouseContextualContainerDirective]'
@@ -8,13 +9,21 @@ export class FloatingMouseContextualContainerDirective{
   
   private mousePos: [number, number] = [0, 0]
 
+  constructor(private sanitizer: DomSanitizer){
+
+  }
+
   @HostListener('document:mousemove', ['$event'])
   mousemove(event:MouseEvent){
     this.mousePos = [event.clientX, event.clientY]
+
+    this.transform = `translate(${this.mousePos[0]}px,${this.mousePos[1]}px)`
   }
 
+  @HostBinding('style')
+  style: SafeUrl = this.sanitizer.bypassSecurityTrustStyle('position: absolute; width: 0; height: 0; top: 0; left: 0;')
+
+
   @HostBinding('style.transform')
-  get transform(){
-    return `translate(${this.mousePos[0]}px,${this.mousePos[1]}px)`
-  }
+  transform: string = `translate(${this.mousePos[0]}px,${this.mousePos[1]}px)`
 }
\ No newline at end of file
diff --git a/src/util/mouseOver.directive.spec.ts b/src/util/mouseOver.directive.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..656931eecdb8e8a0dc05c3df70b752f21da79db9
--- /dev/null
+++ b/src/util/mouseOver.directive.spec.ts
@@ -0,0 +1,50 @@
+import { temporalPositveScanFn } from './mouseOver.directive'
+import { Subject } from 'rxjs';
+import {} from 'jasmine'
+import { scan, take, skip } from 'rxjs/operators';
+
+const segmentsPositive = { segments: [{ hello: 'world' }] } as {segments:any}
+const segmentsNegative = { segments: null }
+
+const userLandmarkPostive = { userLandmark: true }
+const userLandmarkNegative = { userLandmark: null }
+
+describe('temporalPositveScanFn', () => {
+  const subscriptions = []
+  afterAll(() => {
+    while(subscriptions.length > 0) subscriptions.pop().unsubscribe()
+  })
+
+  it('should scan obs as expected', (done) => {
+
+    const source = new Subject()
+
+    const testFirstEv = source.pipe(
+      scan(temporalPositveScanFn, []),
+      take(1)
+    )
+
+    const testSecondEv = source.pipe(
+      scan(temporalPositveScanFn, []),
+      skip(1),
+      take(1)
+    )
+
+    const testThirdEv = source.pipe(
+      scan(temporalPositveScanFn, []),
+      skip(2),
+      take(1)
+    )
+    subscriptions.push(
+      testFirstEv.subscribe(
+        arr => expect(arr).toBe([ segmentsPositive ]),
+        null,
+        () => done()
+      )
+    )
+
+    source.next(segmentsPositive)
+    source.next(userLandmarkPostive)
+    source.next(segmentsNegative)
+  })
+})
diff --git a/src/util/mouseOver.directive.ts b/src/util/mouseOver.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..46333a540d835a74efee3ff1eba98635a833db09
--- /dev/null
+++ b/src/util/mouseOver.directive.ts
@@ -0,0 +1,207 @@
+import { Directive, Pipe, PipeTransform, SecurityContext } from "@angular/core";
+import { Store, select } from "@ngrx/store";
+import { filter, distinctUntilChanged, map, shareReplay, scan, startWith } from "rxjs/operators";
+import { merge, Observable, combineLatest } from "rxjs";
+import { TransformOnhoverSegmentPipe } from "src/atlasViewer/onhoverSegment.pipe";
+import { SafeHtml, DomSanitizer } from "@angular/platform-browser";
+
+
+/**
+ * Scan function which prepends newest positive (i.e. defined) value
+ * 
+ * e.g. const source = new Subject()
+ * source.pipe(
+ *  scan(temporalPositveScanFn, [])
+ * ).subscribe(console.log) // outputs
+ * 
+ * 
+ * 
+ */
+export const temporalPositveScanFn = (acc: {segments:any, landmark:any, userLandmark: any}[], curr: {segments:any, landmark:any, userLandmark: any}) => {
+
+  const keys = Object.keys(curr)
+  const isPositive = keys.some(key => !!curr[key])
+    
+  return isPositive
+    ? [curr, ...(acc.filter(item => !keys.some(key => !!item[key])))] as {segments?:any, landmark?:any, userLandmark?: any}[]
+    : acc.filter(item => !keys.some(key => !!item[key]))
+}
+
+@Directive({
+  selector: '[iav-mouse-hover]',
+  exportAs: 'iavMouseHover'
+})
+
+export class MouseHoverDirective{
+
+  public onHoverObs$: Observable<{segments:any, landmark:any, userLandmark: any}>
+  public currentOnHoverObs$: Observable<{segments:any, landmark:any, userLandmark: any}>
+
+  constructor(private store$: Store<any>){
+
+    const onHoverUserLandmark$ = this.store$.pipe(
+      select('uiState'),
+      map(state => state.mouseOverUserLandmark)
+    )
+
+    const onHoverLandmark$ = combineLatest(
+      this.store$.pipe(
+        select('uiState'),
+        map(state => state.mouseOverLandmark)
+      ),
+      this.store$.pipe(
+        select('dataStore'),
+        select('fetchedSpatialData'),
+        startWith([])
+      )
+    ).pipe(
+      map(([landmark, spatialDatas]) => {
+        if(landmark === null) return landmark
+        const idx = Number(landmark.replace('label=',''))
+        if(isNaN(idx)) {
+          console.warn(`Landmark index could not be parsed as a number: ${landmark}`)
+          return {
+            landmarkName: idx
+          }
+        } else {
+          return {
+            ...spatialDatas[idx],
+            landmarkName: spatialDatas[idx].name
+          }
+        }
+      })
+    )
+
+    const onHoverSegments$ = this.store$.pipe(
+      select('uiState'),
+      select('mouseOverSegments'),
+      filter(v => !!v),
+      distinctUntilChanged((o, n) => o.length === n.length
+        && n.every(segment =>
+          o.find(oSegment => oSegment.layer.name === segment.layer.name
+            && oSegment.segment === segment.segment)))
+    )
+
+    const mergeObs = merge(
+      onHoverSegments$.pipe(
+        distinctUntilChanged(),
+        map(segments => {
+          return { segments }
+        })
+      ),
+      onHoverLandmark$.pipe(
+        distinctUntilChanged(),
+        map(landmark => {
+          return { landmark }
+        })
+      ),
+      onHoverUserLandmark$.pipe(
+        distinctUntilChanged(),
+        map(userLandmark => {
+          return { userLandmark }
+        })
+      )
+    ).pipe(
+      shareReplay(1)
+    )
+
+    this.onHoverObs$ = mergeObs.pipe(
+      scan((acc, curr) => {
+        return {
+          ...acc,
+          ...curr
+        }
+      }, { segments: null, landmark: null, userLandmark: null }),
+      shareReplay(1)
+    )
+
+    this.currentOnHoverObs$ = mergeObs.pipe(
+      scan(temporalPositveScanFn, []),
+      map(arr => arr[0]),
+      map(val => {
+        return {
+          segments: null,
+          landmark: null,
+          userLandmark: null,
+          ...val
+        }
+      }),
+      shareReplay(1)
+    )
+  }
+}
+
+
+@Pipe({
+  name: 'mouseOverTextPipe'
+})
+
+export class MouseOverTextPipe implements PipeTransform{
+
+  private transformOnHoverSegmentPipe: TransformOnhoverSegmentPipe
+  constructor(private sanitizer: DomSanitizer){
+    this.transformOnHoverSegmentPipe = new TransformOnhoverSegmentPipe(this.sanitizer)
+  }
+
+  private renderText = ({ label, obj }): SafeHtml[] => {
+    switch(label) {
+      case 'landmark':
+        return [this.sanitizer.sanitize(SecurityContext.HTML, obj.landmarkName)]
+      case 'segments':
+        return obj.map(({ segment }) => this.transformOnHoverSegmentPipe.transform(segment))
+      case 'userLandmark':
+        return [this.sanitizer.sanitize(SecurityContext.HTML, obj.id)]
+      default:
+        console.log(obj)
+        return [this.sanitizer.bypassSecurityTrustHtml(`Cannot be displayed: label: ${label}`)]
+    }
+  }
+
+  public transform(inc: {segments:any, landmark:any, userLandmark: any}): {label: string, text: SafeHtml[]} [] { 
+    const keys = Object.keys(inc)
+    return keys
+      // if is segments, filter out if lengtth === 0
+      .filter(key => Array.isArray(inc[key]) ? inc[key].length > 0 : true )
+      // for other properties, check if value is defined
+      .filter(key => !!inc[key])
+      .map(key => {
+        return {
+          label: key,
+          text: this.renderText({ label: key, obj: inc[key] })
+        }
+      })
+  }
+}
+
+@Pipe({
+  name: 'mouseOverIconPipe'
+})
+
+export class MouseOverIconPipe implements PipeTransform{
+
+  public transform(type: string): {fontSet:string, fontIcon:string}{
+
+    switch(type) {
+      case 'landmark':
+        return {
+          fontSet:'fas',
+          fontIcon: 'fa-map-marker-alt'
+        }
+      case 'segments':
+        return {
+          fontSet: 'fas',
+          fontIcon: 'fa-brain'
+        }
+      case 'userLandmark':
+        return {
+          fontSet:'fas',
+          fontIcon: 'fa-map-marker-alt'
+        }
+      default:
+        return {
+          fontSet: 'fas',
+          fontIcon: 'fa-file'  
+        }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/util/util.module.ts b/src/util/util.module.ts
index 7baaf43fbe1c60c10d8fb34c417d71abb5251074..239488050a1507df1091d7fb5264ef14e576c27c 100644
--- a/src/util/util.module.ts
+++ b/src/util/util.module.ts
@@ -3,19 +3,26 @@ import { FilterNullPipe } from "./pipes/filterNull.pipe";
 import { FilterRowsByVisbilityPipe } from "src/components/flatTree/filterRowsByVisibility.pipe";
 import { StopPropagationDirective } from "./directives/stopPropagation.directive";
 import { DelayEventDirective } from "./directives/delayEvent.directive";
+import { MouseHoverDirective, MouseOverTextPipe, MouseOverIconPipe } from "./mouseOver.directive";
 
 @NgModule({
   declarations: [
     FilterNullPipe,
     FilterRowsByVisbilityPipe,
     StopPropagationDirective,
-    DelayEventDirective
+    DelayEventDirective,
+    MouseHoverDirective,
+    MouseOverTextPipe,
+    MouseOverIconPipe
   ],
   exports: [
     FilterNullPipe,
     FilterRowsByVisbilityPipe,
     StopPropagationDirective,
-    DelayEventDirective
+    DelayEventDirective,
+    MouseHoverDirective,
+    MouseOverTextPipe,
+    MouseOverIconPipe
   ]
 })