Commit 4dc37e1e authored by jose.ignacio.fagian's avatar jose.ignacio.fagian

Merge branch 'feature/integration-graph-2d-3d' of...

Merge branch 'feature/integration-graph-2d-3d' of https://gitlab.fing.edu.uy/matefun/Frontend into feature/integration-graph-2d-3d

# Conflicts:
#	Frontend Angular 4/package.json
#	Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.ts
parents c8df5c9b c39e6782
Pipeline #3028 failed with stages
in 32 seconds
This diff is collapsed.
......@@ -4139,8 +4139,8 @@
"dev": true
},
"function-plot": {
"version": "git://github.com/diego-rey/function-plot.git#d60f8903c392702a32ad42097e7b6575af05cb6a",
"from": "git://github.com/diego-rey/function-plot.git#feature/integration-domain-shape",
"version": "git://github.com/diego-rey/function-plot.git#ecc44bb412db00356cb3dda42ea4c981eaad7bd6",
"from": "git://github.com/diego-rey/function-plot.git#feature/integration-multigraf-shape",
"requires": {
"array-range": "^1.0.1",
"built-in-math-eval": "^0.3.0",
......
......@@ -24,7 +24,7 @@
"core-js": "^2.4.1",
"d3": "^4.12.2",
"font-awesome": "^4.7.0",
"function-plot": "git://github.com/diego-rey/function-plot.git#feature/mutigraf",
"function-plot": "git://github.com/diego-rey/function-plot.git#feature/integration-multigraf-shape",
"graph3D": "git://github.com/ifagian/graph3D#master",
"ionicons": "^3.0.0",
"jq-console": "^2.13.2",
......
......@@ -12,6 +12,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NotificacionModule } from '../../notificacion/notificacion.module';
import { Graph2DModule } from '../plotter/graph2D/graph2D.module';
import { Graph3DModule } from '../plotter/graph3D/graph3D.module';
import { ClosePopoverOnOutsideClickDirective } from '../../shared/utils/closePopoverDirective';
@NgModule({
imports: [
......@@ -30,7 +32,12 @@ import { Graph3DModule } from '../plotter/graph3D/graph3D.module';
ConfirmComponent,
SeleccionarDirectorioComp
],
declarations: [MateFunComponent,ConfirmComponent,SeleccionarDirectorioComp],
declarations: [
MateFunComponent,
ConfirmComponent,
SeleccionarDirectorioComp,
ClosePopoverOnOutsideClickDirective
],
exports: [MateFunComponent]
})
......
<!-- Buttons Controls -->
<div class="buttons-control">
<button ngbPopover="Zoom +"
class="btn btn-sm btn-secondary btn-zoom-increase"
data-placement="bottom"
triggers="mouseenter:mouseleave"
(click)=zoomIn() >
<i class="fa fa-plus"></i>
</button>
<button ngbPopover="Zoom -"
class="btn btn-sm btn-secondary btn-zoom-decrease"
data-placement="bottom"
triggers="mouseenter:mouseleave"
(click)=zoomOut() >
<i class="fa fa-minus"></i>
</button>
<button ngbPopover="Centrar"
class="btn btn-sm btn-secondary btn-zoom-center"
data-placement="bottom"
triggers="mouseenter:mouseleave"
(click)="recenterPlot()" >
<i class="fa fa-arrows"></i>
</button>
<button ngbPopover="Borrar"
class="btn btn-sm btn-secondary btn-trash"
data-placement="bottom"
triggers="mouseenter:mouseleave"
(click)="cleanPlot()" >
<i class="fa fa-trash"></i>
</button>
<button ngbPopover="Descargar PNG"
class="btn btn-sm btn-secondary btn-download"
data-placement="bottom"
triggers="mouseenter:mouseleave"
(click)=exportPlot() >
<i class="fa fa-download"></i>
</button>
<button id="settings"
class="btn btn-sm btn-secondary btn-setting"
placement="bottom"
closePopoverOnOutsideClick
[ngbPopover]=popoverCanvas
popoverTitle="Configuración"
#popover="ngbPopover"
tiggers="click">
<i class="fa fa-gear"></i>
</button>
</div>
<div class="card">
<div class="card-block contenedor-canvas" >
<button ngbPopover="Zoom +" triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 165px; margin-top: -55px" (click)=zoomIn() ><i class="fa fa-plus"></i></button>
<button ngbPopover="Zoom -" triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 132px; margin-top: -55px" (click)=zoomOut() ><i class="fa fa-minus"></i></button>
<button ngbPopover="Centrar" triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style=" float:right; margin-right: 99px; margin-top: -55px" (click)="recenterPlot()" ><i class="fa fa-arrows"></i></button>
<button ngbPopover="Borrar" triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style=" float:right; margin-right: 66px; margin-top: -55px" (click)="cleanPlot()" ><i class="fa fa-trash"></i></button>
<button ngbPopover="Descargar PNG" triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 33px; margin-top: -55px" (click)=exportPlot() ><i class="fa fa-download"></i></button>
<a id="download-plot" class="download-plot" href="#" download="Plot.svg" style="display: none">Download Canvas</a>
<!-- Download Link -->
<a id="download-plot" class="download-plot" href="#" download="Plot.svg" style="display: none">
Download Canvas
</a>
<button class="btn btn-sm btn-secondary" data-placement="bottom" *ngIf="!animation.playing && animation.data.length>0" style=" float:left; margin-top: -5px; margin-right: 5px" (click)="runAnimation()" ><i class="fa fa-play"></i></button>
<button class="btn btn-sm btn-secondary" data-placement="bottom" *ngIf="animation.playing && animation.data.length>0" style=" float:left; margin-top: -5px; margin-right: 5px" (click)="pauseAnimation()" ><i class="fa fa-pause"></i></button>
<!-- Settings Popover Content -->
<ng-template #popoverCanvas>
<div class="form-group settings-popover-content">
<div class="chart-controls setting-section">
<label>
<input
type="checkbox"
name="grid"
class="form-control form-control-sm"
[checked]= settings.grid
(click)="toggleGrid()">
Grilla
</label>
<label>
<input
type="checkbox"
name="axis"
class="form-control form-control-sm"
[checked]= settings.axis
(click)="toggleAxis()">
Ejes
</label>
<label>
<input
type="checkbox"
name="tip"
class="form-control form-control-sm"
[checked]= settings.tip
(click)="toggleTip()">
Tip
</label>
<label [class.disabled]="funciones.length === 0">
<input
type="checkbox"
[attr.disabled]="funciones.length === 0 ? '' : null"
[checked]=animation.boton
(click)="multiGraf(value)">
Multi gráfica
</label>
</div>
<hr>
<div class="zoom-control setting-section">
<div [class.disabled]="funciones.length === 0" style="display: flex;">
<span style="margin-right: 8px; align-self: center;">
Zoom
</span>
<input
type="number"
class="form-control form-control-sm"
[attr.disabled]="funciones.length === 0 ? '' : null"
[(ngModel)]="animation.zoo"
[max]="1000000"
[min]="8"
(change)="setZoom()"
style="width: 70px;"
/>
</div>
</div>
<hr>
<div class="animation-controls setting-section"
[class.disabled]="animation.data.length === 0">
<label>Velocidad de animación:</label>
<div>
<button class="btn btn-sm btn-secondary"
[attr.disabled]="animation.data.length === 0 ? '' : null"
(click)='decreaseSpeed()'>
<i class="fa fa-minus"></i>
</button>
<button class="btn btn-sm btn-secondary"
[attr.disabled]="animation.data.length === 0 ? '' : null"
(click)='restoreSpeed()'>
<span>1x</span>
</button>
<button class="btn btn-sm btn-secondary"
[attr.disabled]="animation.data.length === 0 ? '' : null"
(click)='increaseSpeed()'>
<i class="fa fa-plus"></i>
</button>
<span class="speed-value">
{{animation.speedX | number:'1.1'}}x
</span>
</div>
</div>
</div>
</ng-template>
<!-- Animation -->
<div class="animation" *ngIf="animation.data.length>0">
<button class="btn btn-sm btn-secondary btn-play"
data-placement="bottom"
*ngIf="!animation.playing"
(click)="runAnimation()" >
<i class="fa fa-play"></i>
</button>
<button class="btn btn-sm btn-secondary btn-pause"
data-placement="bottom"
*ngIf="animation.playing"
(click)="pauseAnimation()" >
<i class="fa fa-pause"></i>
</button>
<ngb-progressbar style="float: left; width: 90%" *ngIf="animation.data.length>0" type="info" [value]="((animation.currentFrame+1)/animation.data.length)*100"></ngb-progressbar>
<ngb-progressbar
class="progressbar"
type="info"
[value]="((animation.currentFrame+1)/animation.data.length)*100">
</ngb-progressbar>
</div>
<div id="graph2D-container" style="height: 100%; width: 100%;">
<!-- Graph Container -->
<div #graph2DContainer id="graph2D-container">
</div>
</div>
</div>
\ No newline at end of file
// Buttons Control
.buttons-control {
.btn-zoom-increase, .btn-zoom-decrease, .btn-zoom-center, .btn-trash, .btn-download, .btn-setting {
float: right;
margin-top: -34px;
}
.btn-zoom-increase {
margin-right: 165px;
}
.btn-zoom-decrease {
margin-right: 132px;
}
.btn-zoom-center {
margin-right: 99px;
}
.btn-trash {
margin-right: 66px;
}
.btn-download {
margin-right: 33px;
}
}
// Settings Popover
.settings-popover-content {
width: 12em;
label {
display: block;
&.disabled {
color: #ccc;
}
}
input[type="checkbox"] {
width: 15px;
display: inline-block;
}
.setting-section {
margin-bottom: 1em;
}
.animation-controls {
.speed-value {
margin-left: 0.5em;
font-weight: 900;
font-size: 1.2em;
vertical-align: middle;
}
&.disabled {
color: #ccc;
i.fa, span {
color: #ccc;
}
}
}
.zoom-control {
&>.disabled {
color: #ccc;
}
}
}
// Animation
.animation {
.btn-play, .btn-pause {
float:left;
margin-top: -5px;
margin-right: 5px;
}
.progressbar {
float: left;
width: 90%;
}
}
#graph2D-container {
height: 100%;
width: 100%;
}
import { Component } from '@angular/core';
import { Component, ViewChild, ElementRef } from '@angular/core';
import { GHCIService } from '../../../shared/services/ghci.service';
import functionPlot from 'function-plot';
import { Animation, toJSON, triggerDownload } from './graph2D.helper';
import { Animation, Setting, toJSON, triggerDownload } from './graph2D.helper';
@Component({
moduleId: module.id,
selector: 'graph2D-component',
templateUrl: './graph2D.component.html',
styleUrls: ['./graph2D.component.scss'],
host: {
'(window:resize)': 'onResize($event)'
}
})
export class Graph2DComponent {
// Ghci Service
private ghciServiceSub: any;
private instance: null;
// Chart Container - DOM Element
@ViewChild('graph2DContainer')
private graph2DRef: ElementRef;
private funciones= [];
// Chart Instance
private instance: any;
private boton = true;
// Settings
settings: Setting = {
axis: true,
grid: true,
tip: true
}
private funciones= [];
private id = 0;
private conjunto= [];
// Animation state
animation: Animation = {
data: [],
timer: null,
currentFrame: 0,
speed: 1000,
speedX: 1.0,
playing: false,
init: false
init: false,
boton: true,
zoo: 2000
};
//Nuevo
public setZoom = () => {
this.animation.zoo = this.animation.zoo ;
}
public multiGraf = () => {
this.animation.boton = !this.animation.boton;
}
public constructor(private ghciService: GHCIService) {
this.ghciServiceSub = ghciService.messages.subscribe(
canvas => {
......@@ -44,7 +68,6 @@ export class Graph2DComponent {
switch(canvas.tipo) {
case 'graph': {
var jsonCanvas = JSON.parse(canvas.resultado);
let fun = eval(this.generarFuncion(jsonCanvas));
var conjs = this.obtenerConjunto(jsonCanvas.funs[0]);
var d = conjs + "}"; //Leo
......@@ -61,26 +84,31 @@ export class Graph2DComponent {
var elemento2 = this.recursionfuncion(jsonCanvas.funs[0].sets, nom);
obj.conj.sets.fcod = function (x) { return (eval(elemento2)) }
}
var funcionGenerada = this.generarFuncion(jsonCanvas);
console.log(obj)
//para Enumerados
if (obj.conj.dom == 'Numer') {
var cantElementos = obj.conj.sets.fdom.length;
var j = 0;
for (var fun of obj.conj.sets.fdom) {
//var newstr = nuevo2.replace(fun, j);
j = j + 1;
for (var f of obj.conj.sets.fdom) {
var expresionDom = new RegExp('( '+f+' )', 'g');
funcionGenerada = funcionGenerada.replace(expresionDom, j.toString());
j += 1;
}
}
if (obj.conj.cod == 'Numer') {
var cantElementos = obj.conj.sets.fcod.length;
var j = 0;
for (var fun of obj.conj.sets.fcod) {
//var newstr = nuevo2.replace(fun, j);
j = j + 1;
var j2 = 0;
for (var f2 of obj.conj.sets.fcod) {
var expresionCod = new RegExp(f2, 'g');
funcionGenerada = funcionGenerada.replace(expresionCod, j2.toString());
j2 += 1;
}
}
let fun = eval(funcionGenerada);
var colores = ['pink', 'red', 'blue', 'orange', 'green']
var num = this.getRandomArbitrary(0, 4);
var color = colores[num];
......@@ -92,7 +120,7 @@ export class Graph2DComponent {
tipoGraf = 'polyline';
}
if(this.boton){
if(this.animation.boton && obj.conj.cod != 'Numer' && obj.conj.dom != 'Numer'){
if(this.conjunto.length == 1){
this.id = 1;
this.conjunto.unshift({radio: 2, dom:this.conjunto[0].baseDom, cod:this.conjunto[0].baseCod, baseCod:this.conjunto[0].baseCod, baseDom:this.conjunto[0].baseDom, sets:{fdom:this.conjunto[0].baseDom,fcod:this.conjunto[0].baseCod}});
......@@ -138,13 +166,21 @@ export class Graph2DComponent {
color: color
});
}
let bounding = this.getBounding();
this.instance = functionPlot({
target: '#graph2D-container',
width: 620,
height: 450,
width: bounding.width,
height: bounding.height,
tip: { color: 'green' },
xAxis: { label: 'x - axis',
scale: 'linear',
domain: { initial: [-4, 4],
type: 'discrete' },
yAxis: { domain: [-4, 4] }
},
conj:this.conjunto,
data: this.funciones,
zoom:1000,
zoom:this.animation.zoo,
plugins: [
functionPlot.plugins.zoomBox()
]
......@@ -154,11 +190,13 @@ export class Graph2DComponent {
case 'canvas': {
var shapesData = JSON.parse(canvas.resultado);
var shapesDataNormalized = this.normalizeShapesData(shapesData);
this.instance = null;
let bounding = this.getBounding();
this.cleanPlot();
this.instance = functionPlot({
target: '#graph2D-container',
width: 800,
height: 700,
width: bounding.width,
height: bounding.height,
grid: true,
xAxis: {
label: 'x - axis',
scale: 'linear',
......@@ -174,7 +212,8 @@ export class Graph2DComponent {
})
break;
}
case 'animacion': {
case 'animacion': {
this.cleanPlot();
var animationData = canvas.resultado.map(res => JSON.parse(res));
for (var frame of animationData) {
this.animation.data.push(this.normalizeShapesData(frame));
......@@ -196,10 +235,12 @@ export class Graph2DComponent {
*/
ngAfterViewInit() {
if (!this.instance) {
let bounding = this.getBounding();
this.instance = functionPlot({
target: '#graph2D-container',
width: 800,
height: 700,
width: bounding.width,
height: bounding.height,
grid: true,
xAxis: {
label: 'x - axis',
scale: 'linear',
......@@ -223,6 +264,28 @@ export class Graph2DComponent {
}
}
/**
* On Resize Event.
*/
onResize(event){
let instance = this.instance;
let bounding = this.getBounding();
if (bounding.width > 0) {
instance.options.width = bounding.width;
instance.options.height = bounding.height;
instance.build();
}
}
/**
* @name getBounding
* @desc get the measures of the container of the graph
*/
private getBounding = function() {
const {width, height} = this.graph2DRef.nativeElement.getBoundingClientRect();
return {width, height}
}
/**
* @name updateFrame
* @desc update data for Function Plot and redraw the graph
......@@ -232,10 +295,11 @@ export class Graph2DComponent {
this.instance.options.data = d;
this.instance.draw();
} else {
let bounding = this.getBounding();
this.instance = functionPlot({
target: '#graph2D-container',
width: 800,
height: 700,
width: bounding.width,
height: bounding.height,
xAxis: {
label: 'x - axis',
scale: 'linear',
......@@ -244,10 +308,7 @@ export class Graph2DComponent {
type: 'discrete'
}
},
data: d,
plugins: [
functionPlot.plugins.zoomBox()
]
data: d
})
}
// Update Frame
......@@ -292,6 +353,71 @@ export class Graph2DComponent {
this.instance.removeAllGraphs();
}
/**
* @name decreaseSpeed
* @desc Decrease Speed Animation
*/
public decreaseSpeed = function() {
if (this.animation.speedX > 0.19) {
this.animation.speed *= 1.1;
this.animation.speedX -= 0.1;
this.pauseAnimation();
this.runAnimation();
}
}
/**
* @name restoreSpeed
* @desc Increase Speed Animation
*/
public restoreSpeed = function() {
this.animation.speed = 1000;
this.animation.speedX = 1;
this.pauseAnimation();
this.runAnimation();
}
/**
* @name increaseSpeed
* @desc Increase Speed Animation
*/
public increaseSpeed = function() {
if (this.animation.speedX < 10) {
this.animation.speed *= 0.9;
this.animation.speedX += 0.1;
this.pauseAnimation();
this.runAnimation();
}
}
/**
* @name toggleGrid
* @desc Show and Hide Grid
*/
public toggleGrid = function () {