From d6ad18e80bd2134d3140323b7bb539faa987a864 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Wed, 12 Sep 2018 11:29:22 +0200
Subject: [PATCH] feat: loading indicators

---
 src/index.html                                |  4 +
 src/res/css/extra_styles.css                  | 72 ++++++++++++++++++
 .../nehubaContainer.component.ts              | 75 ++++++++++++++++---
 .../nehubaContainer/nehubaContainer.style.css | 29 +++++++
 .../nehubaContainer.template.html             | 22 ++++++
 .../nehubaViewer/nehubaViewer.component.ts    |  9 +--
 6 files changed, 197 insertions(+), 14 deletions(-)

diff --git a/src/index.html b/src/index.html
index 33f639768..ef550de05 100644
--- a/src/index.html
+++ b/src/index.html
@@ -11,6 +11,10 @@
 </head>
 <body>
   <atlas-viewer>
+    Loading the atlas viewer 
+    <span class = "homeAnimationDots loadingAnimationDots">&bull;</span>
+    <span class = "homeAnimationDots loadingAnimationDots">&bull;</span>
+    <span class = "homeAnimationDots loadingAnimationDots">&bull;</span>
   </atlas-viewer>
 </body>
 </html>
\ No newline at end of file
diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css
index 82f035c9b..ae82ca6de 100644
--- a/src/res/css/extra_styles.css
+++ b/src/res/css/extra_styles.css
@@ -145,3 +145,75 @@ markdown-dom pre code
 {
   width:1em;
 }
+
+@keyframes explode
+{
+  0% {
+    opacity: 0.0;
+  }
+  30% { 
+    opacity: 1.0
+  }
+  100% {
+    opacity: 0.0;
+  }
+}
+
+.loadingAnimationDots:nth-child(1)
+{
+  animation: explode 1s ease infinite running;
+}
+.loadingAnimationDots:nth-child(2)
+{
+  animation: explode 1s ease 0.2s infinite running;  
+}
+.loadingAnimationDots:nth-child(3)
+{
+  animation: explode 1s ease 0.4s infinite running;  
+}
+.loadingAnimationDots:nth-child(4)
+{
+  animation: explode 1s ease 0.6s infinite running;  
+}
+.loadingAnimationDots:nth-child(5)
+{
+  animation: explode 1s ease 0.8s infinite running;  
+}
+
+.homeAnimationDots:nth-child(1)
+{
+  color: red;
+}
+.homeAnimationDots:nth-child(2)
+{
+  color: blue;
+}
+.homeAnimationDots:nth-child(3)
+{
+  color: green;
+}
+
+@keyframes spinning
+{
+  from {
+    transform: rotate(0deg);
+  }
+  to{
+    transform: rotate(359deg);
+  }
+}
+
+#homeSpinning
+{
+  font-size: 200%;
+}
+
+.spinnerAnimationCircle
+{
+  width: 1em;
+  height:1em;
+  border-radius: 50%;
+  border: 0.2em rgba(128,128,128,0.2) solid;
+  border-top: 0.2em rgba(128,128,128,0.99) solid;
+  animation: spinning 700ms linear infinite running;
+}
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index 594637892..71b944c9f 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -27,6 +27,11 @@ export class NehubaContainer implements OnInit, OnDestroy{
 
   public viewerLoaded : boolean = false
 
+  public sliceViewLoading0$: Observable<boolean>
+  public sliceViewLoading1$: Observable<boolean>
+  public sliceViewLoading2$: Observable<boolean>
+  public perspectiveViewLoading$: Observable<string|null>
+
   private newViewer$ : Observable<any>
   private selectedParcellation$ : Observable<any>
   private selectedRegions$ : Observable<any[]>
@@ -47,7 +52,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
 
   private ngLayersRegister : NgViewerStateInterface = {layers : [], forceShowSegment: null}
   private ngLayers$ : Observable<NgViewerStateInterface>
-  private selectedParcellationNgId : string
+  
   public selectedParcellation : any | null
 
   private cr : ComponentRef<NehubaViewerUnit>
@@ -161,6 +166,12 @@ export class NehubaContainer implements OnInit, OnDestroy{
         .pipe(
           scan((acc:Event[],event:Event)=>{
             const target = (event as Event).target as HTMLElement
+            /**
+             * 0 | 1
+             * 2 | 3
+             * 
+             * 4 ???
+             */
             const key = target.offsetLeft < 5 && target.offsetTop < 5 ?
               0 :
               target.offsetLeft > 5 && target.offsetTop < 5 ?
@@ -186,6 +197,60 @@ export class NehubaContainer implements OnInit, OnDestroy{
       [0,1,2].forEach(idx=>this.nanometersToOffsetPixelsFn[idx] = (events[idx] as any).detail.nanometersToOffsetPixels)
     })
 
+    this.sliceViewLoading0$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent')
+      .pipe(
+        filter((event:Event) => (event.target as HTMLElement).offsetLeft < 5 && (event.target as HTMLElement).offsetTop < 5),
+        map(event => {
+          const e = (event as any);
+          const num1 = typeof e.detail.missingChunks === 'number' ? e.detail.missingChunks : 0
+          const num2 = typeof e.detail.missingImageChunks === 'number' ? e.detail.missingImageChunks : 0
+          return Math.max(num1, num2) > 0
+        })
+      )
+
+    this.sliceViewLoading1$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent')
+      .pipe(
+        filter((event:Event) => (event.target as HTMLElement).offsetLeft > 5 && (event.target as HTMLElement).offsetTop < 5),
+        map(event => {
+          const e = (event as any);
+          const num1 = typeof e.detail.missingChunks === 'number' ? e.detail.missingChunks : 0
+          const num2 = typeof e.detail.missingImageChunks === 'number' ? e.detail.missingImageChunks : 0
+          return Math.max(num1, num2) > 0
+        })
+      )
+
+    this.sliceViewLoading2$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent')
+      .pipe(
+        filter((event:Event) => (event.target as HTMLElement).offsetLeft < 5 && (event.target as HTMLElement).offsetTop > 5),
+        map(event => {
+          const e = (event as any);
+          const num1 = typeof e.detail.missingChunks === 'number' ? e.detail.missingChunks : 0
+          const num2 = typeof e.detail.missingImageChunks === 'number' ? e.detail.missingImageChunks : 0
+          return Math.max(num1, num2) > 0
+        })
+      )
+
+    /* missing chunk perspective view */
+    this.perspectiveViewLoading$ = fromEvent(this.elementRef.nativeElement, 'perpspectiveRenderEvent')
+      .pipe(
+        filter(event => isDefined(event) && isDefined((event as any).detail) && isDefined((event as any).detail.lastLoadedMeshId) ),
+        map(event => {
+          
+          const e = (event as any)
+          const lastLoadedIdString = e.detail.lastLoadedMeshId.split(',')[0]
+          const lastLoadedIdNum = Number(lastLoadedIdString)
+          return e.detail.meshesLoaded >= this.regionsLabelIndexMap.size
+            ? null
+            : isNaN(lastLoadedIdNum)
+              ? 'Loading unknown chunk'
+              : lastLoadedIdNum >= 65500
+                ? 'Loading auxiliary chunk'
+                : this.regionsLabelIndexMap.get(lastLoadedIdNum)
+                  ? `Loading ${this.regionsLabelIndexMap.get(lastLoadedIdNum).name}`
+                  : 'Loading unknown chunk ...'
+        })
+      )
+
     this.combinedSpatialData$ = combineLatest(
       combineLatest(
         this.fetchedSpatialDatasets$,
@@ -397,13 +462,6 @@ export class NehubaContainer implements OnInit, OnDestroy{
     return pos
   }
 
-  // get combinedSpatialData$(){
-  //   return (this.fetchedSpatialData
-  //     .filter(() => this.spatialResultsVisible)
-  //     .map(v => Object.assign({}, v, {type: 'spatial'})) as any[])
-  //     .concat(this.userLandmarks.map(v => Object.assign({}, v, {type: 'user'})))
-  // }
-
   getPositionX(quadrant:number,data:any){
     return this.returnTruePos(quadrant,data)[0]
   }
@@ -426,7 +484,6 @@ export class NehubaContainer implements OnInit, OnDestroy{
     this.regionsLabelIndexMap = getLabelIndexMap(parcellation.regions)
     this.nehubaViewer.regionsLabelIndexMap = this.regionsLabelIndexMap
     this.nehubaViewer.parcellationId = parcellation.ngId
-    this.selectedParcellationNgId = parcellation.ngId
     this.selectedParcellation = parcellation
   }
 
diff --git a/src/ui/nehubaContainer/nehubaContainer.style.css b/src/ui/nehubaContainer/nehubaContainer.style.css
index 83626740a..ac5c9d805 100644
--- a/src/ui/nehubaContainer/nehubaContainer.style.css
+++ b/src/ui/nehubaContainer/nehubaContainer.style.css
@@ -107,4 +107,33 @@ div[linksContainer]
 {
   display:inline-block;
   margin-left:1em;
+}
+
+div[landmarkMasterContainer] > div > [landmarkContainer] > div.loadingIndicator
+{
+  left: auto;
+  top: auto;
+  right: 0;
+  bottom: 0;
+  margin-right: 0.2em;
+  margin-bottom: 0.2em;
+  width: 100%;
+  height:2em;
+  display: flex;
+  flex-direction: row-reverse;
+}
+
+div.loadingIndicator div.spinnerAnimationCircle
+{
+  font-size:150%;
+}
+
+[perspectiveLoadingText]
+{
+  margin-right: 1em;
+}
+
+:host-context([darktheme="true"]) [perspectiveLoadingText]
+{
+  color:rgba(255,255,255,0.8);
 }
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html
index 0e22c3267..2d2c633e7 100644
--- a/src/ui/nehubaContainer/nehubaContainer.template.html
+++ b/src/ui/nehubaContainer/nehubaContainer.template.html
@@ -20,6 +20,12 @@
         [positionY] = "getPositionY(0,spatialData)"
         [positionZ] = "getPositionZ(0,spatialData)">
       </nehuba-2dlandmark-unit>
+
+      <div *ngIf = "sliceViewLoading0$ | async" class = "loadingIndicator">
+        <div class = "spinnerAnimationCircle">
+
+        </div>
+      </div>
     </layout-floating-container>
   </div>
   <div>
@@ -36,6 +42,11 @@
         [positionY] = "getPositionY(1,spatialData)"
         [positionZ] = "getPositionZ(1,spatialData)">
       </nehuba-2dlandmark-unit>
+      <div *ngIf = "sliceViewLoading1$ | async" class = "loadingIndicator">
+        <div class = "spinnerAnimationCircle">
+
+        </div>
+      </div>
     </layout-floating-container>
   </div>
   <div>
@@ -52,12 +63,23 @@
         [positionY] = "getPositionY(2,spatialData)"
         [positionZ] = "getPositionZ(2,spatialData)">
       </nehuba-2dlandmark-unit>
+      <div *ngIf = "sliceViewLoading2$ | async" class = "loadingIndicator">
+        <div class = "spinnerAnimationCircle">
+
+        </div>
+      </div>
     </layout-floating-container>
   </div>
   <div>
     <layout-floating-container  
       pos11 
       landmarkContainer>
+      <div *ngIf = "perspectiveViewLoading$ | async" class = "loadingIndicator">
+        <div class = "spinnerAnimationCircle"></div>
+        <div perspectiveLoadingText>
+          {{ perspectiveViewLoading$ | async }}
+        </div>
+      </div>
     </layout-floating-container>
   </div>
 </div>
diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
index 53e26e19d..fdc89f294 100644
--- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
+++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
@@ -87,12 +87,10 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
   public mouseOverSegment : number | null
 
   ngAfterViewInit(){
-    this.nehubaViewer = export_nehuba.createNehubaViewer(this.config,(err)=>{
+    this.nehubaViewer = export_nehuba.createNehubaViewer(this.config, (err)=>{
       /* print in debug mode */
+      console.log('xgui3783', err)
     });
-
-    // console.log(export_nehuba)
-    (<any>window).quat = export_nehuba.quat
     
     if(this.regionsLabelIndexMap){
       const managedLayers = this.nehubaViewer.ngviewer.layerManager.managedLayers
@@ -487,7 +485,8 @@ export interface ViewerState{
 }
 
 export function getAuxilliaryLabelIndices(){
-  return Array.from(Array(36)).map((_,i)=>65500+i)
+  return [65535]
+  // return Array.from(Array(36)).map((_,i)=>65500+i)
 }
 
 export const ICOSAHEDRON = `# vtk DataFile Version 2.0
-- 
GitLab