From 52188d72335cec26c1668cd81addefc7965f19fe Mon Sep 17 00:00:00 2001
From: "jose.ignacio.fagian" <nachofagian@gmail.com>
Date: Fri, 20 Jul 2018 20:23:30 -0300
Subject: [PATCH] Implementacion de barra de controles

---
 Frontend Angular 4/src/app/app.module.ts      |   5 +-
 .../src/app/layout/layout.module.ts           |   2 +-
 .../plotter/graph3D/graph3D.component.html    | 242 +++++++++++++-----
 .../plotter/graph3D/graph3D.component.scss    |  24 +-
 .../plotter/graph3D/graph3D.component.ts      |  70 +++--
 .../layout/plotter/graph3D/graph3D.helper.ts  |  27 ++
 .../layout/plotter/graph3D/graph3D.module.ts  |   5 +-
 Frontend Angular 4/src/app/shared/config.ts   |   8 +-
 .../app/shared/utils/closePopoverDirective.ts |  34 +++
 9 files changed, 326 insertions(+), 91 deletions(-)
 create mode 100644 Frontend Angular 4/src/app/shared/utils/closePopoverDirective.ts

diff --git a/Frontend Angular 4/src/app/app.module.ts b/Frontend Angular 4/src/app/app.module.ts
index 084f634..51ad01f 100644
--- a/Frontend Angular 4/src/app/app.module.ts	
+++ b/Frontend Angular 4/src/app/app.module.ts	
@@ -7,10 +7,11 @@ import { AppComponent } from './app.component';
 import { AuthGuard } from './shared/guards/auth.guard';
 import { SessionService } from './shared/services/session.service';
 import { NotificacionService } from './shared/services/notificacion.service';
-import {NotificacionModule} from './notificacion/notificacion.module'
+import {NotificacionModule} from './notificacion/notificacion.module';
+
 @NgModule({
     declarations: [
-        AppComponent,
+        AppComponent
     ],
     imports: [
         NotificacionModule,
diff --git a/Frontend Angular 4/src/app/layout/layout.module.ts b/Frontend Angular 4/src/app/layout/layout.module.ts
index 9777481..ab31a0b 100644
--- a/Frontend Angular 4/src/app/layout/layout.module.ts	
+++ b/Frontend Angular 4/src/app/layout/layout.module.ts	
@@ -23,7 +23,7 @@ import { NotificacionModule } from '../notificacion/notificacion.module';
     declarations: [
         LayoutComponent,
         HeaderComponent,
-        SidebarComponent
+        SidebarComponent        
     ],
     providers: [AuthenticationService, HaskellService]
 })
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.html b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.html
index add6d7d..2cbdffc 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.html	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.html	
@@ -1,93 +1,201 @@
 <div class="card">
-    <div class="controls">
-			<div class="btn-group ddown">
-				<button 
-					type="button" 
-					class="btn btn-secondary"
-					style="min-width: 70px;"
-					(click)=changeZoomType()
-				>
-					{{getZoom3DTypeName(zoomType)}}
-				</button>
-				<div class="btn-group" ngbDropdown role="group" aria-label="Button group with nested dropdown">
-					<button class="btn btn-secondary dropdown-toggle-split" ngbDropdownToggle></button>
-					<div class="dropdown-menu" ngbDropdownMenu>
-						<button 
-							*ngFor="let type of [1,2,3,4]" 
-							class="dropdown-item"
-							[disabled]="type === zoomType"
-							(click)=changeZoomType(type)
-						>
-							{{getZoom3DTypeName(type)}}
-						</button>
-					</div>
-				</div>
-			</div> 
-
+	<div class="controls">
+		<div class="btn-group ddown">
 			<button 
-				ngbPopover="Zoom +"  
-				triggers="mouseenter:mouseleave" 
-				data-placement="bottom" 
-				class="btn btn-sm btn-secondary" 
-				(click)=zoomIn() 
+				type="button" 
+				class="btn btn-secondary"
+				style="min-width: 70px;"
+				(click)=changeZoomType()
 			>
-				<i class="fa fa-plus"></i>
+				{{getZoom3DTypeName(graphProps.zoomType)}}
 			</button>
+			<div class="btn-group" ngbDropdown role="group" aria-label="Button group with nested dropdown">
+				<button class="btn btn-secondary dropdown-toggle-split" ngbDropdownToggle></button>
+				<div class="dropdown-menu" ngbDropdownMenu>
+					<button 
+						*ngFor="let type of [1,2,3,4]" 
+						class="dropdown-item"
+						[disabled]="type === graphProps.zoomType"
+						(click)=changeZoomType(type)
+					>
+						{{getZoom3DTypeName(type)}}
+					</button>
+				</div>
+			</div>
+		</div> 
 
-			<button 
-				ngbPopover="Zoom -"  
-				triggers="mouseenter:mouseleave" 
-				data-placement="bottom" 
-				class="btn btn-sm btn-secondary" 
-				(click)=zoomOut() 
-			>
-				<i class="fa fa-minus"></i>
-			</button>
+		<button 
+			ngbPopover="Zoom +"  
+			triggers="mouseenter:mouseleave" 
+			data-placement="bottom" 
+			class="btn btn-sm btn-secondary" 
+			(click)=zoomIn() 
+		>
+			<i class="fa fa-plus"></i>
+		</button>
 
-			<button 
-				ngbPopover="Centrar"  
-				triggers="mouseenter:mouseleave" 
-				data-placement="bottom" 
-				class="btn btn-sm btn-secondary" 
-				(click)=zoomMas() 
-			>
-				<i class="fa fa-arrows"></i>
-			</button>
+		<button 
+			ngbPopover="Zoom -"  
+			triggers="mouseenter:mouseleave" 
+			data-placement="bottom" 
+			class="btn btn-sm btn-secondary" 
+			(click)=zoomOut() 
+		>
+			<i class="fa fa-minus"></i>
+		</button>
 
-			<button 
-				ngbPopover="Borrar"  
-				triggers="mouseenter:mouseleave" 
-				data-placement="bottom" 
-				class="btn btn-sm btn-secondary" 
-				(click)=zoomMas() 
-			>
-				<i class="fa fa-trash"></i>
-			</button>
+		<button 
+			ngbPopover="Centrar"  
+			triggers="mouseenter:mouseleave" 
+			data-placement="bottom" 
+			class="btn btn-sm btn-secondary" 
+			(click)=center() 
+		>
+			<i class="fa fa-arrows"></i>
+		</button>
 
-			<button 
-			ngbPopover="Configuración"  
+		<button 
+			closePopoverOnOutsideClick
+			class="btn btn-sm btn-secondary" 
+			placement="bottom" 
+			[ngbPopover]=popoverAxesSize
+			popoverTitle="Rango de ejes"
+			#popover="ngbPopover"
+			tiggers="click"
+		>
+			<i class="fa fa-arrows-h"></i>
+		</button>
+		<ng-template #popoverAxesSize>
+			<div class="axes-size">
+				<div class="axe">
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.xMin"
+						[max]="graphProps.range.xMax-1"
+						[min]="-99" 
+						(change)="onChangeAxesSize('xMin', $event)"
+					/>
+					<div class="less-than">
+						<span>&#8804;</span>x<span>&#8804;</span>
+					</div>
+					
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.xMax"
+						[max]="99"
+						[min]="graphProps.range.xMin+1" 
+						(change)="onChangeAxesSize('xMax', $event)"
+					/>
+				</div>
+
+				<div class="axe">
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.yMin"
+						[max]="graphProps.range.yMax-1"
+						[min]="-99" 
+						(change)="onChangeAxesSize('yMin', $event)"
+					/>
+					<div class="less-than">
+						<span>&#8804;</span>y<span>&#8804;</span>
+					</div>
+					
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.yMax"
+						[max]="99"
+						[min]="graphProps.range.yMin+1" 
+						(change)="onChangeAxesSize('yMax', $event)"
+					/>
+				</div>
+
+				<div class="axe">
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.zMin"
+						[max]="graphProps.range.zMax-1"
+						[min]="-99" 
+						(change)="onChangeAxesSize('zMin', $event)"
+					/>
+					<div class="less-than">
+						<span>&#8804;</span>z<span>&#8804;</span>
+					</div>
+					
+					<input 
+						type="number" 
+						class="form-control form-control-sm" 
+						[(ngModel)]="graphProps.range.zMax"
+						[max]="99"
+						[min]="graphProps.range.zMin+1" 
+						(change)="onChangeAxesSize('zMax', $event)"
+					/>
+				</div>
+			</div>
+		</ng-template>
+		
+
+		<button 
+			ngbPopover="Borrar"  
 			triggers="mouseenter:mouseleave" 
 			data-placement="bottom" 
 			class="btn btn-sm btn-secondary" 
-			(click)=zoomMas() 
+			(click)=clear() 
+		>
+			<i class="fa fa-trash"></i>
+		</button>
+
+		<button 
+		[ngbPopover]=popoverConfig
+			closePopoverOnOutsideClick
+			placement="bottom" 
+		
+			tiggers="click"
+			class="btn btn-sm btn-secondary" 
+			popoverTitle="Configuración"
 		>
 			<i class="fa fa-gear"></i>
 		</button>
- 		
+
+		<ng-template #popoverConfig>
+			<div style="width: 140px;">
+				<label class="d-block">
+					<input type="checkbox"[checked]=graphProps.showAxes (click)="changeAxesVisibility()">
+					Mostrar grilla
+				</label>
+
+				<div style="display: flex;">
+					<span style="margin-right: 8px; align-self: center;">
+						Quality:
+					</span>
+
+					<input 
+						type="number" 
+						style="width: 55px;"
+						class="form-control form-control-sm" 
+					/>
+				</div>
+			</div>
+		</ng-template>
+
+	
 	</div>
 		
 	<div class="card-block contenedor-canvas" >
 		<animation-control
 			[minSpeed]="60"
-			[value]="animation.value"
-			[speed]="animation.speed"
-			[visible]="animation.visible"
-			[playing]="animation.playing"
+			[value]="animationProps.value"
+			[speed]="animationProps.speed"
+			[visible]="animationProps.visible"
+			[playing]="animationProps.playing"
 			[onChangeSpeed]="onAnimationChangeSpeed"
 			[onTogglePlay]="onAnimationTogglePlay"
 		>
 		</animation-control>
-
 		
 		<div #graph3DElement style="width: 100%; height: 100%;">
 		</div>
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.scss b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.scss
index 9b83024..fe06fa3 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.scss	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.scss	
@@ -14,7 +14,25 @@
 		vertical-align: bottom;
 
 		button {
-			padding: 2.5px 5px;
+			padding: 2.5px 8px 2.5px 3px;
+		}
+	}
+
+	.axes-size {
+		width: 165px;
+
+		.axe {
+			display: flex;
+
+			&:not(:last-child) {
+				margin-bottom: 6px;
+			}
+
+			.less-than {
+				padding: 0 2.5px 0 5px;
+				font-size: 17px; 
+				letter-spacing: 4px;
+			}
 		}
 	}
 }
@@ -22,4 +40,8 @@
 .dropdown-item:disabled{
 	background-color: #f7f7f7;
 	color: #9e9e9e;
+}
+
+.d-block{
+	display: block;
 }
\ No newline at end of file
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.ts b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.ts
index 532dcdd..690432c 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.ts	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.ts	
@@ -1,7 +1,7 @@
 import { Component, OnInit, ViewChild, ElementRef, NgZone } from '@angular/core';
 import * as graph3DLib from 'graph3d';
 import { GHCIService } from '../../../shared/services/ghci.service';
-import { formatJSON, AnimationProps, Zoom3DType } from './graph3D.helper';
+import { formatJSON, AnimationProps, Zoom3DType, GraphProps, Default_GraphProps } from './graph3D.helper';
 
 @Component({
   selector: 'graph3d-component',
@@ -18,16 +18,17 @@ export class Graph3DComponent implements OnInit {
   @ViewChild('graph3DElement') 
   private graph3DRef: ElementRef;
 
-  public zoomType: Zoom3DType = Zoom3DType.Normal;
-
-  private animation : AnimationProps = {
+  private graphProps : GraphProps = Default_GraphProps;
+  
+  private animationProps : AnimationProps = {
     visible: false,
     playing: false,
     value: 0,
     speed: 1000
   };
+  
 
-  constructor(private ghciService: GHCIService, private zone: NgZone) {
+  constructor(ghciService: GHCIService, private zone: NgZone) {
     this.ghciServiceSub = ghciService.messages.subscribe(
       message => {
         if (message.tipo == "canvas3D") {
@@ -38,12 +39,13 @@ export class Graph3DComponent implements OnInit {
         else if (message.tipo == "animacion3D") {
           const frames = message.resultado.map((frame) => JSON.parse(formatJSON(frame)));
 
-          this.animation.visible = true;
-          this.animation.playing = true;
-          this.animation.value = 0;
+          this.animationProps.visible = true;
+          this.animationProps.playing = true;
+          this.animationProps.value = 0;
 
+          graph3DLib.clear();
           graph3DLib.initializeAnimation(frames, 
-            (value) => this.animation.value = value
+            (value) => this.animationProps.value = value
           );
 
           graph3DLib.playAnimation();
@@ -53,9 +55,9 @@ export class Graph3DComponent implements OnInit {
   }
 
   ngOnInit() {
-    this.zone.runOutsideAngular(() => {
+  //  this.zone.runOutsideAngular(() => {
       graph3DLib.initialize(this.graph3DRef.nativeElement);
-    })
+    //})
   }
 
   ngOnDestroy() {
@@ -71,30 +73,52 @@ export class Graph3DComponent implements OnInit {
   }
 
   onAnimationChangeSpeed = (value) => {
-    this.animation.speed = parseInt(value);
+    this.animationProps.speed = parseInt(value);
     graph3DLib.changeSpeedAnimation(parseInt(value));
   }
 
   onAnimationTogglePlay = () => {
-    if (this.animation.playing) {
+    if (this.animationProps.playing) {
       graph3DLib.pauseAnimation();
     }
     else {
       graph3DLib.playAnimation();
     }
     
-    this.animation.playing = !this.animation.playing;
+    this.animationProps.playing = !this.animationProps.playing;
   }
 
   public changeZoomType = (type: Zoom3DType = null) => {
     if (type != null) {
-      this.zoomType = type;
+      this.graphProps.zoomType = type;
     } 
     else {
-      this.zoomType = (this.zoomType % 4) + 1;
+      this.graphProps.zoomType = (this.graphProps.zoomType % 4) + 1;
     }
 
-    graph3DLib.changeZoomType(this.zoomType);
+    graph3DLib.changeZoomType(this.graphProps.zoomType);
+  }
+
+  public changeAxesVisibility = () => {
+    this.graphProps.showAxes = !this.graphProps.showAxes;
+    graph3DLib.showAxes(this.graphProps.showAxes);
+  }
+
+  public onChangeAxesSize = (v, event) => {
+    let value = this.graphProps.range[v];
+
+    const min = parseInt(event.target.min);
+    const max = parseInt(event.target.max);
+
+    if (value < min) {
+      this.graphProps.range[v] = min;
+    } 
+    
+    if (value > max) {
+      this.graphProps.range[v] = max;
+    }
+    
+    graph3DLib.changeAxesSize(this.graphProps.range)
   }
 
   public zoomIn = () => {
@@ -105,6 +129,18 @@ export class Graph3DComponent implements OnInit {
     graph3DLib.changeZoom(false);
   }
   
+  public clear = () => {
+    this.animationProps.visible = false;
+
+    graph3DLib.clear();
+  }
+  
+  public center = () => {
+    this.graphProps = Default_GraphProps;
+
+    graph3DLib.reset();
+  }
+
   public getZoom3DTypeName = (type: Zoom3DType) => {
     switch (type) {
       case Zoom3DType.Normal:
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.helper.ts b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.helper.ts
index a13ebd2..90fc980 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.helper.ts	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.helper.ts	
@@ -8,6 +8,7 @@ export function formatJSON(jsonString: string) : string {
 	)
 }
 
+
 export interface AnimationProps {
 	visible?: boolean,
 	playing?: boolean,
@@ -22,3 +23,29 @@ export enum Zoom3DType {
 	ZAxis,
 }
 
+export interface GraphProps {
+	zoomType?: Zoom3DType,
+	showAxes?: boolean,
+	range: {
+		xMin?: number,
+		xMax?: number,
+		yMin?: number,
+		yMax?: number,
+		zMin?: number,
+		zMax?: number
+	}
+}
+
+export const Default_GraphProps : GraphProps = {
+	zoomType: Zoom3DType.Normal,
+	showAxes: true,
+	range: {
+		xMin: -10,
+		xMax: 10,
+		yMin: -10,
+		yMax: 10,
+		zMin: -10,
+		zMax: 10
+	}
+}
+
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.module.ts b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.module.ts
index 0497860..1df9cb3 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.module.ts	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.module.ts	
@@ -5,12 +5,15 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 import { FormsModule } from '@angular/forms';
 import { Graph3DComponent } from './graph3D.component';
 import { AnimationControlComponent } from '../animation-control/animation-control.component';
+import { ClosePopoverOnOutsideClickDirective } from '../../../shared/utils/closePopoverDirective';
+
 
 @NgModule({
     imports: [FormsModule, RouterModule, CommonModule, NgbModule],
     declarations: [
         AnimationControlComponent, 
-        Graph3DComponent
+        Graph3DComponent,
+        ClosePopoverOnOutsideClickDirective
     ],
     entryComponents: [
         AnimationControlComponent
diff --git a/Frontend Angular 4/src/app/shared/config.ts b/Frontend Angular 4/src/app/shared/config.ts
index 269b083..1100f6f 100644
--- a/Frontend Angular 4/src/app/shared/config.ts	
+++ b/Frontend Angular 4/src/app/shared/config.ts	
@@ -5,5 +5,9 @@
 //export const GHCI_URL = 'ws://localhost:9090/endpoint';
 
 //Configuracion dinamica pensando en servidor con ip dinamica
-export const SERVER = window.location.protocol + '//' + window.location.host;//'http://localhost:9090';
-export const GHCI_URL = window.location.protocol == 'http:'?  'ws://'+window.location.host+'/endpoint': 'wss://'+window.location.host+'/endpoint';
+
+// export const SERVER = window.location.protocol + '//' + window.location.host;//'http://localhost:9090';
+// export const GHCI_URL = window.location.protocol == 'http:'?  'ws://'+window.location.host+'/endpoint': 'wss://'+window.location.host+'/endpoint';
+
+export const SERVER = 'http://192.168.95.3:9090';
+export const GHCI_URL = 'ws://192.168.95.3:9090/endpoint';
diff --git a/Frontend Angular 4/src/app/shared/utils/closePopoverDirective.ts b/Frontend Angular 4/src/app/shared/utils/closePopoverDirective.ts
new file mode 100644
index 0000000..2faa926
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/utils/closePopoverDirective.ts	
@@ -0,0 +1,34 @@
+import { Directive, HostListener, ElementRef, ComponentRef } from '@angular/core';
+import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
+import { NgbPopoverWindow } from '@ng-bootstrap/ng-bootstrap/popover/popover';
+
+@Directive({
+  selector: '[closePopoverOnOutsideClick][ngbPopover]'
+})
+export class ClosePopoverOnOutsideClickDirective {
+
+  constructor(private elementRef: ElementRef,
+              private ngbPopover: NgbPopover) {
+
+  }
+
+  @HostListener('document:click', ['$event'])
+  private documentClicked(event: MouseEvent): void {
+
+    // Popover is open
+    if (this.ngbPopover && this.ngbPopover.isOpen()) {
+
+      // Not clicked on self element
+      if (!this.elementRef.nativeElement.contains(event.target)) {
+
+        // Hacking typescript to access private member
+        const popoverWindowRef: ComponentRef<NgbPopoverWindow> = (this.ngbPopover as any)._windowRef;
+
+        // If clicked outside popover window
+        if (!popoverWindowRef.location.nativeElement.contains(event.target)) {
+          this.ngbPopover.close();
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
-- 
GitLab