diff --git a/Frontend Angular 4/package.json b/Frontend Angular 4/package.json index 6e4eb1048cde875ebd679310a1c430b377a1b381..95d1e855724e415188c696dfa9aec0e355d827a0 100644 --- a/Frontend Angular 4/package.json +++ b/Frontend Angular 4/package.json @@ -31,7 +31,8 @@ "ng2-slider-component": "^1.0.9", "rxjs": "^5.1.0", "tippy.js": "^1.2.0", - "zone.js": "^0.8.4" + "zone.js": "^0.8.4", + "graph3D": "git://github.com/ifagian/graph3D#master" }, "devDependencies": { "@angular/cli": "1.2.6", diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html index 0e2031ad57a826aa1ffd9c923bae9fc0a9e87ef9..07a5f6a4ccfc5fbf0b6363db862f68b4a548c023 100644 --- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html +++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html @@ -78,6 +78,11 @@ <ng-template ngbTabContent> <canvas-component (canvasComp)=canvasC></canvas-component> </ng-template> + </ngb-tab> + <ngb-tab id="FigurasBtn2" title="Figuras 3D"> + <ng-template ngbTabContent> + <graph3d-component (graph3DComp)=graph3DComp></graph3d-component> + </ng-template> </ngb-tab> </ngb-tabset> diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts index eef61f11cff59d53139bca4ecc8497d5285f2082..7a45f4c2148ad1cc4947af688bd6dfe1539b86ba 100644 --- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts +++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts @@ -19,6 +19,7 @@ import { CodemirrorComponent } from 'ng2-codemirror'; import { NgbPopoverConfig, NgbPopover} from '@ng-bootstrap/ng-bootstrap'; import { NgbPopoverWindow } from '@ng-bootstrap/ng-bootstrap/popover/popover'; import { NotificacionService } from '../../shared/services/notificacion.service'; +import { Graph3DComponent } from '../plotter/graph3D/graph3D.component'; import 'rxjs/add/operator/catch'; import 'rxjs/add/operator/map'; @@ -351,6 +352,7 @@ export class MateFunComponent { } @ViewChild(CanvasComponent) canvasC: CanvasComponent; + @ViewChild(Graph3DComponent) graph3DComp: Graph3DComponent; funcionSTR: string = 'Math.sin(x)*x*x-20'; consola: string = ''; diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts b/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts index 850c3c3679a86f6294f43a90b7c31aaf40ebc2b1..bad4eed34065e757b990e6eea5ee894582ca0459 100644 --- a/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts +++ b/Frontend Angular 4/src/app/layout/matefun/matefun.module.ts @@ -10,11 +10,14 @@ import { MateFunRoutingModule } from './matefun-routing.module'; import { CodemirrorModule } from 'ng2-codemirror'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NotificacionModule } from '../../notificacion/notificacion.module'; +import { Graph3DModule } from '../plotter/graph3D/graph3D.module'; + @NgModule({ imports: [ CommonModule, FormsModule, CanvasModule, + Graph3DModule, NotificacionModule, MateFunRoutingModule, CodemirrorModule, diff --git a/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.html b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.html new file mode 100644 index 0000000000000000000000000000000000000000..fe8fec8dc2fd80fae4da3f473b5de564545eb058 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.html @@ -0,0 +1,44 @@ +<div *ngIf="visible"> + <button + class="btn btn-sm btn-secondary" + data-placement="bottom" + *ngIf="!playing" + style=" float:left; margin-top: -5px; margin-right: 5px" + (click)="onTogglePlay()" + > + <i class="fa fa-play"></i> + </button> + + <button + class="btn btn-sm btn-secondary" + data-placement="bottom" + *ngIf="playing" + style=" float:left; margin-top: -5px; margin-right: 5px" + (click)="onTogglePlay()" + > + <i class="fa fa-pause"></i> + </button> + + <ngb-progressbar + style="float: left; width: 45%" + type="info" + [value]="value" + > + </ngb-progressbar> + + <span + style="float: right; margin-left: 10px" + > + {{speed}}ms + </span> + + <input + style="float: right; width: 20%" + type="range" + [min]="minSpeed" + max="1500" + [value]="speed" + (input)="onChangeSpeed($event.target.value)" + /> + +</div> \ No newline at end of file diff --git a/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.scss b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.spec.ts b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..15a503f890d9e329759924273eb625e3d489b583 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.spec.ts @@ -0,0 +1,25 @@ +// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +// import { AnimationControlComponent } from './animation-control.component'; + +// describe('AnimationControlComponent', () => { +// let component: AnimationControlComponent; +// let fixture: ComponentFixture<AnimationControlComponent>; + +// beforeEach(async(() => { +// TestBed.configureTestingModule({ +// declarations: [ AnimationControlComponent ] +// }) +// .compileComponents(); +// })); + +// beforeEach(() => { +// fixture = TestBed.createComponent(AnimationControlComponent); +// component = fixture.componentInstance; +// fixture.detectChanges(); +// }); + +// it('should be created', () => { +// expect(component).toBeTruthy(); +// }); +// }); diff --git a/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.ts b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..085382cc914b1bc5a52803f82bd08f0b93a93b5d --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/animation-control/animation-control.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'animation-control', + templateUrl: './animation-control.component.html', + styleUrls: ['./animation-control.component.scss'] +}) +export class AnimationControlComponent implements OnInit { + + @Input() visible: boolean; + @Input() playing: boolean; + + @Input() value: number; + + @Input() minSpeed: number; + @Input() speed: number; + + @Input() onTogglePlay: Function; + @Input() onChangeSpeed: Function; + + constructor() { } + + ngOnInit() { + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..d5e26165dabc57cd2edbe5006c3e075b935344c2 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.html @@ -0,0 +1,84 @@ +<div class="card"> + <div class="controls"> + <div class="btn-group ddown" style=""> + <button type="button" class="btn btn-secondary">Normal</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 class="dropdown-item">Eje x</button> + <button class="dropdown-item">Eje y</button> + <button class="dropdown-item">Eje z</button> + </div> + </div> + </div> + + <button + ngbPopover="Zoom +" + triggers="mouseenter:mouseleave" + data-placement="bottom" + class="btn btn-sm btn-secondary" + (click)=zoomMas() + > + <i class="fa fa-plus"></i> + </button> + + <button + ngbPopover="Zoom -" + triggers="mouseenter:mouseleave" + data-placement="bottom" + class="btn btn-sm btn-secondary" + (click)=zoomMas() + > + <i class="fa fa-minus"></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="Borrar" + triggers="mouseenter:mouseleave" + data-placement="bottom" + class="btn btn-sm btn-secondary" + (click)=zoomMas() + > + <i class="fa fa-trash"></i> + </button> + + <button + ngbPopover="Configuración" + triggers="mouseenter:mouseleave" + data-placement="bottom" + class="btn btn-sm btn-secondary" + (click)=zoomMas() + > + <i class="fa fa-gear"></i> + </button> + + </div> + + <div class="card-block contenedor-canvas" > + <animation-control + [minSpeed]="60" + [value]="animation.value" + [speed]="animation.speed" + [visible]="animation.visible" + [playing]="animation.playing" + [onChangeSpeed]="onAnimationChangeSpeed" + [onTogglePlay]="onAnimationTogglePlay" + > + </animation-control> + + + <div #graph3DElement style="width: 100%; height: 100%;"> + </div> + </div> + +</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 new file mode 100644 index 0000000000000000000000000000000000000000..43a8fe9b2c0925a2cb7167b04ea91b7d68c476e3 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.scss @@ -0,0 +1,20 @@ +.controls { + margin-top: -40px; + height: 35px; + padding: 4px; + align-self: flex-end; + + .button { + float:right; + margin-right: 165px; + margin-top: -55px + } + + .ddown { + vertical-align: bottom; + + button { + padding: 2.5px 5px; + } + } +} \ No newline at end of file diff --git a/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.spec.ts b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..513c2458e4828ec6c4039afb0e14f4ca49f3cd48 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Graph3DComponent } from './graph3D.component'; + +describe('Graph3DComponent', () => { + let component: Graph3DComponent; + let fixture: ComponentFixture<Graph3DComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ Graph3DComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(Graph3DComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000000000000000000000000000000000000..7acf104493d8f3664d6de8c876fb76fe764c0fbe --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.component.ts @@ -0,0 +1,87 @@ +import { Component, OnInit, ViewChild, ElementRef, NgZone } from '@angular/core'; +import * as graph3DLib from 'graph3d'; +import { GHCIService } from '../../../shared/services/ghci.service'; +import { formatJSON, AnimationProps } from './graph3D.helper'; + +@Component({ + selector: 'graph3d-component', + templateUrl: './graph3D.component.html', + styleUrls: ['./graph3D.component.scss'], + host: { + '(window:resize)': 'onResize($event)' + } +}) +export class Graph3DComponent implements OnInit { + + private ghciServiceSub: any; + + @ViewChild('graph3DElement') + private graph3DRef: ElementRef; + + private animation : AnimationProps = { + visible: false, + playing: false, + value: 0, + t:1, + speed: 1000 + }; + + constructor(private ghciService: GHCIService, private zone: NgZone) { + this.ghciServiceSub = ghciService.messages.subscribe( + message => { + if (message.tipo == "canvas3D") { + const figures = JSON.parse(formatJSON(message.resultado)); + + graph3DLib.drawFigures(figures); + } + 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; + + graph3DLib.initializeAnimation(frames, + (value) => this.animation.value = value + ); + + graph3DLib.playAnimation(); + } + } + ) + } + + ngOnInit() { + this.zone.runOutsideAngular(() => { + graph3DLib.initialize(this.graph3DRef.nativeElement); + }) + } + + ngOnDestroy() { + if (this.ghciServiceSub) { + this.ghciServiceSub.unsubscribe(); + } + } + + onResize(event){ + const {width, height} = this.graph3DRef.nativeElement.getBoundingClientRect(); + + graph3DLib.changeSize({width, height}); + } + + onAnimationChangeSpeed = (value) => { + this.animation.speed = parseInt(value); + graph3DLib.changeSpeedAnimation(parseInt(value)); + } + + onAnimationTogglePlay = () => { + if (this.animation.playing) { + graph3DLib.pauseAnimation(); + } + else { + graph3DLib.playAnimation(); + } + + this.animation.playing = !this.animation.playing; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..d143e786136f9d948b0c810e1df4a0ca1fa2173d --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.helper.ts @@ -0,0 +1,17 @@ +export function formatJSON(jsonString: string) : string { + const regexRot = /\"rot\"\:\((\d*.\d*),(\d*.\d*),(\d*.\d*)\)/g; + + return jsonString.replace( + regexRot, (match, x, y, z) => { + return `"rot": { "x": ${x}, "y": ${y}, "z": ${z} }` + } + ) +} + +export interface AnimationProps { + visible?: boolean, + playing?: boolean, + value?: number, + speed?: number, + t: any +} \ No newline at end of file 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 new file mode 100644 index 0000000000000000000000000000000000000000..04978608b7acb8ae9599aaecf7864c5c8bcbcf26 --- /dev/null +++ b/Frontend Angular 4/src/app/layout/plotter/graph3D/graph3D.module.ts @@ -0,0 +1,21 @@ +import { NgModule} from '@angular/core'; +import { CommonModule } from '@angular/common' +import { RouterModule } from '@angular/router'; +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'; + +@NgModule({ + imports: [FormsModule, RouterModule, CommonModule, NgbModule], + declarations: [ + AnimationControlComponent, + Graph3DComponent + ], + entryComponents: [ + AnimationControlComponent + ], + exports: [Graph3DComponent] +}) + +export class Graph3DModule { } diff --git a/Frontend Angular 4/src/app/shared/services/ghci.service.ts b/Frontend Angular 4/src/app/shared/services/ghci.service.ts index 8a24162fc5797be6d7cf3d0d5345faedec6f009d..475461f4bfba396307d9f90dd2d05959aeccb776 100644 --- a/Frontend Angular 4/src/app/shared/services/ghci.service.ts +++ b/Frontend Angular 4/src/app/shared/services/ghci.service.ts @@ -294,10 +294,16 @@ export class GHCIService { this.startPrompt.bind(this); this.startPrompt(); // console.log(x); - }else if (json_server_message.tipo == 'canvas' || json_server_message.tipo == 'animacion' || json_server_message.tipo == 'graph'){ + } else if (json_server_message.tipo == 'canvas' || + json_server_message.tipo == 'animacion' || + json_server_message.tipo == 'graph') { document.getElementById("FigurasBtn").click() this.focusConsole(); this.messages.next(json_server_message); + } else if (json_server_message.tipo == 'canvas3D' || + json_server_message.tipo == 'animacion3D') { + this.focusConsole(); + this.messages.next(json_server_message); } }