Skip to content
Snippets Groups Projects
Select Git revision
  • aa6c7b6c4b8ed6441b75eb56e28571be3bc08f8d
  • master default
  • dja
  • dja_various_fixes
  • dja_differentiate_same_user_connections
  • dja_fix_bugs
  • dja_guest
  • dja_guests
  • dja_sign_out_without_race_conditions
  • dja_subgroups
  • dua_subgroups
  • dja_groups_2
  • dja_groups
  • dja_heroku_11_7_2024
  • dja_share_files
  • dja_execute_files_aux_2
  • dja_execute_files_aux
  • dja_execute_files
  • dja_files_page
  • dja-create-main-button
  • feature/aristas-metadata-vertices
  • v2.0
  • v1.0
23 results

graph2D.component.ts

Blame
  • user avatar
    Diego Rey authored
    aa6c7b6c
    History
    graph2D.component.ts 24.83 KiB
    import { Component } from '@angular/core';
    import { GHCIService } from '../../../shared/services/ghci.service';
    import functionPlot from 'function-plot';
    import { Animation, toJSON, triggerDownload } from './graph2D.helper';
    
    @Component({
        moduleId: module.id,
        selector: 'graph2D-component',
        templateUrl: './graph2D.component.html',
        host: {
    
        }
    })
    export class Graph2DComponent {
    
        private ghciServiceSub: any;
    
        private instance: null;
    
        animation: Animation = {
            data: [],
            timer: null,
            currentFrame: 0,
            speed: 1000,
            playing: false,
            init: false
        };
    
        public constructor(private ghciService: GHCIService) {
            this.ghciServiceSub = ghciService.messages.subscribe(
                canvas => {
                    // Stop Animation
                    if (this.animation.init) {
                        this.stopAnimation();
                    }
                    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 + "}";
        
                            var obj = JSON.parse(d);
                            //Para las funciones 
                            if (obj.conj.sets.fdom == "function(x)") {
                                var nom = jsonCanvas.funs[0].dom;
                                var elemento = this.recursionfuncion(jsonCanvas.funs[0].sets, nom);
                                obj.conj.sets.fdom = function (x) { return eval(elemento) }
                            }
                            if (obj.conj.sets.fcod == "function(x)") {
                                var nom = jsonCanvas.funs[0].cod;
                                var elemento = this.recursionfuncion(jsonCanvas.funs[0].sets, nom);
                                obj.conj.sets.fcod = function (x) { return (eval(elemento)) }
                            }
                            //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;
                                }
        
                            }
                            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 colores = ['pink', 'red', 'blue', 'orange', 'green']
                            var num = this.getRandomArbitrary(0, 4);
                            var color = colores[num];
        
                            var tipoGraf;
                            if (obj.conj.baseDom != 'R'){
                                tipoGraf = 'scatter';
                            }else{
                                tipoGraf = 'polyline';
                            }
                            this.instance = functionPlot({
                                target: '#graph2D-container',
                                width: 620,
                                height: 450,
                                conj:obj.conj,
                                data: [{
                                    sampler: 'builtIn',
                                    fn: function(scope) {
                                      return fun(scope.x)
                                    },
                                    graphType: tipoGraf,
                                    color: color
                                }],
                                plugins: [
                                    functionPlot.plugins.zoomBox()
                                ]
                            })
                            break; 
                        }
                        case 'canvas': {
                            var shapesData = JSON.parse(canvas.resultado);
                            var shapesDataNormalized = this.normalizeShapesData(shapesData);
                            this.instance = null;
                            this.instance = functionPlot({
                                target: '#graph2D-container',
                                width: 800,
                                height: 700,
                                xAxis: {
                                    label: 'x - axis',
                                    scale: 'linear',
                                    domain: {
                                        initial: [-10, 10],
                                        type: 'discrete'
                                    }
                                },
                                data: shapesDataNormalized,
                                plugins: [
                                    functionPlot.plugins.zoomBox()
                                ]
                            })
                            break; 
                        }
                        case 'animacion': {                        
                            var animationData = canvas.resultado.map(res => JSON.parse(res));
                            for (var frame of animationData) {
                                this.animation.data.push(this.normalizeShapesData(frame));
                            }
                            this.runAnimation();
                            this.animation.init = true;
                            break; 
                        }
                    }
                },
                error => {
                }
            )
        }
    
        /**
         * Angular lifecycle hook.
         * called after Angular has fully initialized a component's view.
         */
        ngAfterViewInit() {
            if (!this.instance) {
                this.instance = functionPlot({
                    target: '#graph2D-container',
                    width: 800,
                    height: 700,
                    xAxis: {
                        label: 'x - axis',
                        scale: 'linear',
                        domain: {
                            initial: [-10, 10],
                            type: 'discrete'
                        }
                    },
                    data: []
                })
            }
        }
    
        /**
         * Angular lifecycle hook.
         * called when a directive, pipe, or service is destroyed.
         */
        ngOnDestroy() {
            if (this.ghciServiceSub) {
              this.ghciServiceSub.unsubscribe();
            }
        }
    
        /**
         * @name updateFrame
         * @desc update data for Function Plot and redraw the graph
         */
        public updateFrame = function(d) {
            if (this.instance) {
                this.instance.options.data = d;
                this.instance.draw();
            } else {
                this.instance = functionPlot({
                    target: '#graph2D-container',
                    width: 800,
                    height: 700,
                    xAxis: {
                        label: 'x - axis',
                        scale: 'linear',
                        domain: {
                            initial: [-10, 10],
                            type: 'discrete'
                        }
                    },
                    data: d,
                    plugins: [
                        functionPlot.plugins.zoomBox()
                    ]
                })
            }
            // Update Frame
            this.animation.currentFrame = (this.animation.currentFrame + 1) % this.animation.data.length;
        }
        /**
         * @name runAnimation
         * @desc Run Shapes Animation
         */
        public runAnimation = function() {
            var $this = this;
            if ($this.animation.timer !== null) return;
            $this.updateFrame($this.animation.data[$this.animation.currentFrame]);
            $this.animation.timer = setInterval(function(){
                $this.updateFrame($this.animation.data[$this.animation.currentFrame]);
            }, $this.animation.speed);
            $this.animation.playing = true;
        }
        /**
         * @name pauseAnimation
         * @desc Pause Shapes Animation
         */
        public pauseAnimation = function() {
            var $this = this;
            clearInterval($this.animation.timer);
            $this.animation.timer = null;
            $this.animation.playing = false;
        }
        /**
         * @name stopAnimation
         * @desc Stop Shapes Animation
         */
        public stopAnimation = function() {
            var $this = this;
            clearInterval($this.animation.timer);
            $this.animation.data = [];
            $this.animation.timer = null;
            $this.animation.currentFrame = 0;
            $this.animation.speed = 1000;
            $this.animation.playing = false;
            $this.animation.init = false;
            this.instance.removeAllGraphs();
        }
    
        /**
         * @name zoomOut
         * @desc Zoom Out Button Control
         */
        public zoomOut = function () {
            this.instance.zoomOut();
        }
        /**
         * @name zoomIn
         * @desc Zoom In Button Control 
         */
        public zoomIn = function () {
            this.instance.zoomIn();
        }
        /**
         * @name recenterPlot
         * @desc center the plot and it returns to the initial state.
         */
        public recenterPlot = function () {
            this.instance.recenter();
        }
        /**
         * @name cleanPlot
         * @desc remove all the graph from the instance.
         */
        public cleanPlot = function () {
            if (this.animation.playing) {
                this.stopAnimation();
            } else {
                this.instance.removeAllGraphs();
            }
        }
    
        /**
         * @name exportPlot
         * @desc Download Plot as an SVG image.
         */
        public exportPlot = function() {
            // Objects
            var svg = document.querySelector('svg');
            var canvas = document.createElement("canvas");
    
            // Set dimensions of the image
            var svgSize = svg.getBoundingClientRect();
            canvas.width = svgSize.width;
            canvas.height = svgSize.height;
    
            // Convert SVG DOM structure to xml
            var ctx = canvas.getContext('2d');
            var data = new XMLSerializer().serializeToString(svg);
    
            // URL Object used to parse, construct, normalise, and encode URLs.
            var DOMURL = window.URL || (<any>window).webkitURL || window;
    
            var img = new Image();
            var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
            var url = DOMURL.createObjectURL(svgBlob);
    
            img.onload = function () {
                ctx.drawImage(img, 0, 0);
                DOMURL.revokeObjectURL(url);
    
                var imgURI = canvas
                    .toDataURL('image/png')
                    .replace('image/png', 'image/octet-stream');
    
                triggerDownload(imgURI);
            };
            img.src = url;
        }
    
    
        /**
         * @name normalizeRectData
         * @desc Normalize Rectangle data for Function Plot Library 
         * @param {Object} rectData Data of Rectangle to be normalized
         * @returns {Object}
         */
        public normalizeRectData = function ($rectData) {
            var $rectNormalized:any = {};
            var $shape:any = {};
            $shape.w = $rectData.w;
            $shape.h = $rectData.h;
            $shape.x = $rectData.x;
            $shape.y = $rectData.y;
            $rectData.color && ($shape.fill = $rectData.color);
            $rectData.rot !== 'undefined' && ($shape.rotation = $rectData.rot);
    
            $rectNormalized.shape = $shape;
            $rectNormalized.graphType = 'shape';
            $rectNormalized.shapeType = 'rect';
        
            return $rectNormalized;
        }
        /**
         * @name normalizeCircleData
         * @desc Normalize Circle data for Function Plot Library 
         * @param {Object} circleData Data of Circle to be normalized
         * @returns {Object}
         */
        public normalizeCircleData = function ($circleData) {
            var $circleNormalized:any = {};
            var $shape:any = {};
            $shape.r = $circleData.r;
            $shape.x = $circleData.x;
            $shape.y = $circleData.y;
            $circleData.color && ($shape.fill = $circleData.color);
            $circleData.rot !== 'undefined' && ($shape.rotation = $circleData.rot);
    
            $circleNormalized.shape = $shape;
            $circleNormalized.graphType = 'shape';
            $circleNormalized.shapeType = 'circle';
        
            return $circleNormalized;
        }
        /**
         * @name normalizeTextData
         * @desc Normalize Text data for Function Plot Library 
         * @param {Object} textData Data of Text to be normalized
         * @returns {Object}
         */
        public normalizeTextData = function ($textData) {
            var $textNormalized:any = {};
            var $shape:any = {};
            $shape.text = $textData.text;
            $shape.size = $textData.size;
            $shape.x = $textData.x;
            $shape.y = $textData.y;
            $textData.color && ($shape.fill = $textData.color);
            $textData.rot !== 'undefined' && ($shape.rotation = $textData.rot);
    
            $textNormalized.shape = $shape;
            $textNormalized.graphType = 'shape';
            $textNormalized.shapeType = 'text';
        
            return $textNormalized;
        }
        /**
         * @name normalizeLineData
         * @desc Normalize Line data for Function Plot Library 
         * @param {Object} lineData Data of Line to be normalized
         * @returns {Object}
         */
        // public normalizeLineData = function ($lineData) {
        //     var $lineNormalized:any = {};
        //     var $points = []
        //     for (var p of $lineData.pts) {
        //         $points.push([p[0],p[1]]);
        //     }
        //     $lineNormalized.points = $points;
        //     $lineNormalized.color = $lineData.color;
        //     $lineNormalized.rotation = $lineData.rot;
        //     $lineNormalized.fnType = 'points';
        //     $lineNormalized.polylineType = 'line';
        //     $lineNormalized.graphType = 'polyline';
        
        //     return $lineNormalized;
        // }
        /**
         * @name normalizePolygonData
         * @desc Normalize Polygon data for Function Plot Library 
         * @param {Object} textData Data of Polygon to be normalized
         * @returns {Object}
         */
        // public normalizePolygonData = function ($textData) {
        //     var $PoligonNormalized:any = {};
        //     var $shape:any = {};
        //     $shape.text = $textData.text;
        //     $shape.size = $textData.size;
        //     $shape.x = $textData.x;
        //     $shape.y = $textData.y;
        //     $textData.color && ($shape.fill = $textData.color);
        //     $textData.rot !== 'undefined' && ($shape.rotation = $textData.rot);
    
        //     $textNormalized.shape = $shape;
        //     $textNormalized.graphType = 'shape';
        //     $textNormalized.shapeType = 'text';
        
        //     return $textNormalized;
        // }
    
        /**
         * @name normalizeShapesData
         * @desc Normalize Shapes data for Function Plot Library 
         * @param {Array} shapesData Data of Shapes to be normalized 
         * @returns {Array}
         */
        public normalizeShapesData = function (shapesData) {
            var normalized:Array<Object> = [];
            for (var shape of shapesData) {
                switch(shape.kind) { 
                    case 'rect': { 
                        normalized.push(this.normalizeRectData(shape)); 
                        break; 
                    } 
                    case 'circle': { 
                        normalized.push(this.normalizeCircleData(shape)); 
                        break; 
                    } 
                    case 'text': { 
                        normalized.push(this.normalizeTextData(shape)); 
                        break; 
                    }
                    // case 'line': { 
                    //     normalized.push(this.normalizeLineData(shape)); 
                    //     break; 
                    // }
                    // case 'polygon': { 
                    //     normalized.push(this.normalizePolygonData(shape)); 
                    //     break; 
                    // } 
                } 
            }
            return normalized;
        }
    
    
    
        getRandomArbitrary = function (min, max) {
            return Math.round(Math.random() * (max - min) + min);
        }
    
        generarFuncion = function (graph) {
            var funcionString = '';
            var grafica;
            for (var fun of graph.funs) {
                funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + this.generarExpresion(fun.bdy) + '}\n' + funcionString;
    
                if (fun.fun == graph.graph) {
                    funcionString += 'return ' + fun.fun + '(' + fun.args.join() + ');\n'
                    grafica = fun;
                }
            }
            funcionString = '(' + grafica.args.join() + ',delta,hayPunto)=>{\n' + funcionString + '}';
    
            return funcionString;
        }
    
        generarExpresion = function (exp) {
            var expresion = '';
            if (exp.kind == 'cnd') {
                expresion = ' (' + this.generarExpresion(exp.cond) + '?' + this.generarExpresion(exp.exp1) + ':' + this.generarExpresion(exp.exp2) + ') ';
            } else if (exp.kind == 'bop') {
                if (exp.op == '==') {
                    expresion = ' Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) < delta && hayPunto() ';
                } else if (exp.op == '/=') {
                    expresion = ' Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) > delta ||  Math.abs((' + this.generarExpresion(exp.exp1) + ') - (' + this.generarExpresion(exp.exp2) + ')) < delta && !hayPunto()  ';
                } else if (exp.op == '^') {
                    expresion = ' Math.pow(' + this.generarExpresion(exp.exp1) + ',' + this.generarExpresion(exp.exp2) + ') ';
                } else {
                    expresion = ' (' + this.generarExpresion(exp.exp1) + ')' + exp.op + '(' + this.generarExpresion(exp.exp2) + ') ';
                }
            } else if (exp.kind == 'uop') {
                expresion = ' ' + exp.op + ' ' + this.generarExpresion(exp.exp) + ' ';
            } else if (exp.kind == 'app') {
    			
    			if (exp.fun == 'cos') {
    				exp.fun = 'Math.cos'
    			} else if (exp.fun == 'sin') {
    				exp.fun = 'Math.sin'
    			} else if (exp.fun == 'round') {
    				exp.fun = 'Math.round'
    			}
    			expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarExpresion(e)).join() + ') ';
    
            } else if (exp.kind == 'tup') {
                expresion = ' (' + exp.exps.map(e => this.generarExpresion(e)).join() + ') ';
            } else if (exp.kind == 'lit') {
                expresion = ' ' + exp.val + ' ';
            } else if (exp.kind == 'var') {
                expresion = ' ' + exp.var + ' ';
            } else {
                expresion = ' undefined ';
            }
    
            return expresion;
        }
    
        //Nuevo 20-07-2018
    
    
        obtenerConjunto = function (grf) {
    
            var setf = '\"sets\": {';
            var dominio = '{\"conj\": {';
            if (grf.dom == 'R') {
                dominio += "\"radio\": 0.3, \"baseDom\": \"R\", \"dom\": \"R\"";
                setf += "\"fdom\": \"R\",";
            } else if (grf.dom == 'Z') {
                dominio += "\"radio\": 2, \"baseDom\": \"Z\", \"dom\": \"Z\"";
                setf += "\"fdom\": \"Z\",";
            } else if (grf.dom == 'N') {
                dominio += "\"radio\":2, \"baseDom\": \"N\", \"dom\": \"N\"";
                setf += "\"fdom\": \"N\",";
            } else {
                var nom = grf.dom;
                if (Array.isArray(grf.sets[0][nom])) {
                    var arreglo = grf.sets[0][nom];
                    var arreglo2 = [];
                    for (var item of arreglo) {
                        arreglo2.push("\"" + item + "\"");
                    }
                    dominio += "\"radio\":2, \"baseDom\": \"N\", \"dom\": \"Numer\"";
                    setf += "\"fdom\": [" + arreglo2 + "], ";
                } else {
    
                    dominio += this.recursivoDom(grf.sets, nom);
                    setf += "\"fdom\":\"function(x)\",";
                }
            }
            dominio += ", ";
            if (grf.cod == 'R') {
                dominio += "\"baseCod\": \"R\", \"cod\": \"R\" ,";
                setf += "\"fcod\": \"R\"";
            } else if (grf.cod == 'Z') {
                dominio += "\"baseCod\": \"Z\", \"cod\": \"Z\" ,";
                setf += "\"fcod\": \"Z\"";
            } else if (grf.cod == 'N') {
                dominio += "\"baseCod\": \"N\", \"cod\": \"N\" ,";
                setf += "\"fcod\": \"N\"";
            } else {
                var nom = grf.cod;
                if (Array.isArray(grf.sets[0][nom])) {
                    var arreglo = grf.sets[0][nom];
                    var arreglo2 = [];
                    for (var item of arreglo) {
                        arreglo2.push("\"" + item + "\"");
                    }
                    dominio += "\"baseCod\": \"N\", \"cod\": \"Numer\" ,";
                    setf += '\"fcod\":[' + arreglo2 + ']';
                } else {
                    dominio += this.recursivoCod(grf.sets, nom);
                    setf += "\"fcod\": \"function(x)\"";
                }
            }
            return dominio + setf + "}}";
        }
    
        recursionfuncion = function (func, nombre) {
            var fun = func[0][nombre].set;
            var resul = "";
            if (fun == 'R' || fun == 'Z' || fun == 'N') {
                resul += this.generarF(func[0][nombre].cond);
            } else {
                resul += this.generarF(func[0][nombre].cond) + " && " + this.recursionfuncion(func, fun);
    
            }
            return resul;
        }
    
        recursivoDom = function (sets, nom) {
            var domin = "";
            if (sets[0][nom].set == 'R') {
                domin += "\"radio\": 0.3, \"baseDom\": \"R\", \"dom\": \"Func\"";
            } else if (sets[0][nom].set == 'Z') {
                domin += "\"radio\": 2, \"baseDom\": \"Z\", \"dom\": \"Func\"";
            } else if (sets[0][nom].set == 'N') {
                domin += "\"radio\": 2, \"baseDom\": \"N\", \"dom\": \"Func\"";
            } else {
                var nombre = sets[0][nom].set;
                domin = this.recursivoDom(sets, nombre);
            }
            return domin;
        }
    
    
        recursivoCod = function (sets, nom) {
            var coodo = "";
            if (sets[0][nom].set == 'R') {
                coodo += "\"baseCod\": \"R\", \"cod\": \"Func\",";
            } else if (sets[0][nom].set == 'Z') {
                coodo += "\"baseCod\": \"Z\", \"cod\": \"Func\",";
            } else if (sets[0][nom].set == 'N') {
                coodo += "\"baseCod\": \"N\", \"cod\": \"Func\",";
            } else {
                var nombre = sets[0][nom].set;
                coodo += this.recursivoDom(sets, nombre);
            }
            return coodo;
        }
    
        generarF = function (exp) {
            var expresion = '';
            if (exp.kind == 'cond') {
                expresion = ' (' + this.generarF(exp.cond) + '?' + this.generarF(exp.exp1) + ':' + this.generarF(exp.exp2) + ') ';
            } else if (exp.kind == 'bop') {
                if (exp.op == '==') {
                    expresion = ' Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0 ';
                } else if (exp.op == '/=') {
                    expresion = ' Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0 ||  Math.abs((' + this.generarF(exp.exp1) + ') - (' + this.generarF(exp.exp2) + ')) == 0  ';
                } else if (exp.op == '^') {
                    expresion = ' Math.pow(' + this.generarF(exp.exp1) + ',' + this.generarF(exp.exp2) + ') ';
                } else {
                    expresion = ' (' + this.generarF(exp.exp1) + ')' + exp.op + '(' + this.generarF(exp.exp2) + ') ';
                }
            } else if (exp.kind == 'uop') {
                expresion = ' ' + exp.op + ' ' + this.generarF(exp.exp) + ' ';
            } else if (exp.kind == 'app') {
                if (exp.fun == 'cos') {
                    exp.fun = 'Math.cos'
                } else if (exp.fun == 'sin') {
                    exp.fun = 'Math.sin'
                } else if (exp.fun == 'round') {
                    exp.fun = 'Math.round'
                }
                expresion = ' ' + exp.fun + '(' + exp.args.map(e => this.generarF(e)).join() + ') ';
            } else if (exp.kind == 'tup') {
                expresion = ' (' + exp.exps.map(e => this.generarF(e)).join() + ') ';
            } else if (exp.kind == 'lit') {
                expresion = ' ' + exp.val + ' ';
            } else if (exp.kind == 'var') {
                expresion = ' ' + exp.var + ' ';
            } else {
                expresion = ' undefined ';
            }
    
            return expresion;
        }
    
        generarFun = function (graph) {
            var funcionString = '';
            var grafica;
            for (var fun of graph.funs) {
                funcionString = 'var ' + fun.fun + ' = function(' + fun.args.join() + '){\n return ' + this.generarF(fun.bdy) + '}\n' + funcionString;
    
                if (fun.fun == graph.graph) {
                    funcionString += 'return ' + fun.fun + '(' + fun.args.join() + ');\n'
                    grafica = fun;
                }
            }
            funcionString = '(' + grafica.args.join() + ')=>{\n' + funcionString + '}';
    
            return funcionString;
        }
    
    
    
    }