Angular
+
TypeScript

Licencia de Creative Commons mario@mariogl.com

Temario

  • Introducción a Angular
  • Entorno de desarrollo
  • Javascript moderno
  • Introducción a TypeScript
  • Primeros pasos en Angular
  • Modelos, componentes y vistas
  • Servicios
  • Formularios
  • Acceso al servidor
  • Enrutamiento y navegación
  • Despliegue a producción

Introducción a Angular

¿Qué es Angular?

  • Framework JS

  • SPA: Single Page Applications

  • TypeScript

  • Código fuente y código compilado

  • ¿Angular 2? ¿6? ¿AngularJS?

Entorno de desarrollo

Entorno de desarrollo

Git

Comandos básicos

  • Clonar un repositorio:

        git clone URL
     

  • Descargar última versión del repositorio:

        git pull origin master

Configuración proxy

git config --global http.proxy http://username:password@host:port

git config --global https.proxy http://username:password@host:port

Node.js y npm

npm

  • Instalar última versión después de instalar Node.js
    (configurar proxy si es necesario)

  • Repositorio de módulos distribuibles

  • Módulos globales y módulos locales

  • La carpeta node_modules

  • El archivo package.json:

    • Registro de dependencias

    • Dependencias de desarrollo y de producción

    • Versiones (SEMVER)

Comandos npm

  • Instalar un paquete globalmente:
        npm install -g paquete

  • Instalar un paquete de producción:
        npm install paquete

  • Instalar un paquete de desarrollo:
        npm install paquete --save-dev

  • Instalar todas las dependencias:
        npm install

  • Instalar las dependencias de producción:
        npm install --production

  • Listar paquetes instalados:

        npm list --depth=0        (locales)
        npm list -g --depth=0   (globales)

Configuración proxy

npm config set proxy http://username:password@host:port

npm config set https-proxy http://username:password@host:port

JavaScript

JavaScript

  • Interpretado, compilado y ejecutado en el navegador

  • Cada navegador programa su propio motor de JS

  • Estandarización: ECMAScript

  • La versión ES6 o ES2015

  • Transpiladores: Babel, TypeScript

Organización del código JavaScript

  • Ejemplo de uso clásico de JS: utilizar un plugin de jQuery en nuestra web, o implementar alguna interacción con el usuario

  • Pocas líneas de código, todas en un mismo archivo

Organización del código JavaScript

(function($) {

    $(document).ready(function() {
        
        // Al hacer clic en una pestaña
        $(".tab a").on("click", function(e) {
            // Anulamos el link
            e.preventDefault();

            // Ocultamos todos los bloques de contenido
            // y mostramos sólo el que se ha elegido
            var content_id = $(this).attr("href");
            $(".tab-content").hide();
            $(content_id).show();

            // Desmarcamos la pestaña que estuviera activa
            // y marcamos la clicada como activa
            $(".tab.active").removeClass("active");
            $(this).closest(".tab").addClass("active");
        })
        
    })

})(jQuery);
<head>
    <meta charset="UTF-8">
    <title>Mi web</title>
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="js/tabs.js"></script>
</head>

24 líneas

Organización del código JavaScript

<head>
    <meta charset="UTF-8">
    <title>Mi web</title>
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="js/ui.js"></script>
</head>
(function($) {
    
        $(document).ready(function() {
            $(document).on('click', '.tab_new', offerGroupSwitchTabs);
            $(document).on('click', '.navigationServices-li', jumpTo);
            $('.load-more_new').on('click', loadMore).each(function() {
                $(this).data('main', $(this).text());
            });
        })
    
        var loadMore = function(e) {
            e.preventDefault();
            var $list = $(this).prev('.promos-list_new');
            var button_text = $(this).data('main');
            var button_alt_text = $(this).data('alt');
            if ($(window).width() > 992) {
                var hidden_classes = ".hidden";
                var $hidden = $list.find(hidden_classes);
                var n_show = 3;
            } else if ($(window).width() > 768) {
                var hidden_classes = ".hidden, .hidden-sm";
                var $hidden = $list.find(hidden_classes);
                var n_show = 2;
            } else {
                var hidden_classes = ".hidden, .hidden-sm, .hidden-xs";
                var $hidden = $list.find(hidden_classes);
                var n_show = 1;
            }
            if ($hidden.length == 0) {
                $list.find(">li:nth-child(2)").addClass('hidden-xs');
                $list.find(">li:nth-child(3)").addClass('hidden-xs hidden-sm');
                $list.find(">li:nth-child(n+4)").addClass('hidden');
                $(this).text(button_text);
            } else {
                $hidden.slice(0, n_show).each(function () {
                    $(this).removeClass(hidden_classes.replace(/[\.,\,]/g, ''));
                });
                if ($list.find(hidden_classes).length == 0) {
                    $(this).text(button_alt_text);
                }
            }
        }
    
        var offerGroupSwitchTabs = function(e) {
            e.preventDefault();
            var $info = $(this).closest('.info_new');
            var target = $(this).attr('href');
            var targetClass = target.replace('#', '.');
            $info.find('.active').removeClass('active');
            $info.find('[href=' + target + ']').addClass('active');
            $(targetClass).addClass('active');
        }
    
        var jumpTo = function(e) {
            e.preventDefault();
            var target = $(this).find('a').attr('href');
            var $target = $(target);
            var targetTop = $target.offset().top;
            $('html, body').animate({
                scrollTop: targetTop - 200
            }, {
                duration: durationOnDistance(targetTop),
                complete: function() {
                    window.location.hash = target;
                }
            });
        }
    
        var durationOnDistance = function(elementTop) {
            var distance = elementTop - $(window).scrollTop();
            var time = distance * 0.5;
            return time;
        }
    
    })(jQuery)
  

75 líneas

Organización del código JavaScript

  • Programar toda la UI de una página

(function() {
    var width = window.innerWidth; 
    var height = window.innerHeight; 
    var timerID = 0;
    var c = document.getElementById('canvas')
    var ctx = c.getContext('2d');
    c.width = width;
    c.height = height;


        var speed = 10;
        var size = 8;
        var boids = [];
        var totalBoids = 150;
        
        var init = function(){
        
            for (var i = 0; i < totalBoids; i++) {
            
                boids.push({
                    x: Math.random() * width,
                    y: Math.random() * height,
                    v: {
                        x: Math.random() * 2 - 1,
                        y: Math.random() * 2 - 1
                    },
                    c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                });
            }
            setInterval(update, 40);	
        }
        
        var calculateDistance = function(v1, v2){
            x = Math.abs(v1.x - v2.x);
            y = Math.abs(v1.y - v2.y);
            
            return Math.sqrt((x * x) + (y * y));
        }
        
        var checkWallCollisions = function(index){
            if (boids[index].x > width) {
                boids[index].x = 0;
            }
            else 
                if (boids[index].x < 0) {
                    boids[index].x = width;
                }
            
            if (boids[index].y > height) {
                boids[index].y = 0;
            }
            else 
                if (boids[index].y < 0) {
                    boids[index].y = height;
                }
        }
        
        var addForce = function(index, force){
        
            boids[index].v.x += force.x;
            boids[index].v.y += force.y;
            
            magnitude = calculateDistance({
                x: 0,
                y: 0
            }, {
                x: boids[index].v.x,
                y: boids[index].v.y
            });
            
            boids[index].v.x = boids[index].v.x / magnitude;
            boids[index].v.y = boids[index].v.y / magnitude;
        }
        
        //This should be in multiple functions, but this will
        //save tons of looping - Gross!
        var applyForces = function(index){
            percievedCenter = {
                x: 0,
                y: 0
            };
            flockCenter = {
                x: 0,
                y: 0
            };
            percievedVelocity = {
                x: 0,
                y: 0
            };
            count = 0;
            for (var i = 0; i < boids.length; i++) {
                if (i != index) {
                
                    //Allignment
                    dist = calculateDistance(boids[index], boids[i]);
                    
                    //console.log(dist);
                    if (dist > 0 && dist < 50) {
                        count++;
                        
                        //Alignment
                        percievedCenter.x += boids[i].x;
                        percievedCenter.y += boids[i].y;
                        
                        //Cohesion
                        percievedVelocity.x += boids[i].v.x;
                        percievedVelocity.y += boids[i].v.y;
                        //Seperation
                        if (calculateDistance(boids[i], boids[index]) < 12) {
                            flockCenter.x -= (boids[i].x - boids[index].x);
                            flockCenter.y -= (boids[i].y - boids[index].y);
                        }
                    }
                }
            }
            if (count > 0) {
                percievedCenter.x = percievedCenter.x / count;
                percievedCenter.y = percievedCenter.y / count;
                
                percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                
                percievedVelocity.x = percievedVelocity.x / count;
                percievedVelocity.y = percievedVelocity.y / count;
                
                flockCenter.x /= count;
                flockCenter.y /= count;
            }
            
            addForce(index, percievedCenter);
            
            addForce(index, percievedVelocity);
            
            addForce(index, flockCenter);
        }
        
        var update = function(){
        
            for (var i = 0; i < boids.length; i++) {
            
                //Draw boid
                
                ctx.beginPath();
                ctx.strokeStyle = boids[i].c;

                ctx.lineWidth = size;
                ctx.moveTo(boids[i].x, boids[i].y);
                boids[i].x += boids[i].v.x * speed;
                boids[i].y += boids[i].v.y * speed;
                applyForces(i);
                ctx.lineTo(boids[i].x, boids[i].y);
                ctx.stroke();
                ctx.fill();
                
                checkWallCollisions(i);	
                
            }
        }
        
        //Gui uses this to clear the canvas
        var clearCanvas = function(){
            ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
            ctx.beginPath();
            ctx.rect(0, 0, width, height);
            ctx.closePath();
            ctx.fill();
        }
        
        init();
    })();

    (function() {
        var width = window.innerWidth; 
        var height = window.innerHeight; 
        var timerID = 0;
        var c = document.getElementById('canvas')
        var ctx = c.getContext('2d');
        c.width = width;
        c.height = height;
    
    
            var speed = 10;
            var size = 8;
            var boids = [];
            var totalBoids = 150;
            
            var init = function(){
            
                for (var i = 0; i < totalBoids; i++) {
                
                    boids.push({
                        x: Math.random() * width,
                        y: Math.random() * height,
                        v: {
                            x: Math.random() * 2 - 1,
                            y: Math.random() * 2 - 1
                        },
                        c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                    });
                }
                setInterval(update, 40);	
            }
            
            var calculateDistance = function(v1, v2){
                x = Math.abs(v1.x - v2.x);
                y = Math.abs(v1.y - v2.y);
                
                return Math.sqrt((x * x) + (y * y));
            }
            
            var checkWallCollisions = function(index){
                if (boids[index].x > width) {
                    boids[index].x = 0;
                }
                else 
                    if (boids[index].x < 0) {
                        boids[index].x = width;
                    }
                
                if (boids[index].y > height) {
                    boids[index].y = 0;
                }
                else 
                    if (boids[index].y < 0) {
                        boids[index].y = height;
                    }
            }
            
            var addForce = function(index, force){
            
                boids[index].v.x += force.x;
                boids[index].v.y += force.y;
                
                magnitude = calculateDistance({
                    x: 0,
                    y: 0
                }, {
                    x: boids[index].v.x,
                    y: boids[index].v.y
                });
                
                boids[index].v.x = boids[index].v.x / magnitude;
                boids[index].v.y = boids[index].v.y / magnitude;
            }
            
            //This should be in multiple functions, but this will
            //save tons of looping - Gross!
            var applyForces = function(index){
                percievedCenter = {
                    x: 0,
                    y: 0
                };
                flockCenter = {
                    x: 0,
                    y: 0
                };
                percievedVelocity = {
                    x: 0,
                    y: 0
                };
                count = 0;
                for (var i = 0; i < boids.length; i++) {
                    if (i != index) {
                    
                        //Allignment
                        dist = calculateDistance(boids[index], boids[i]);
                        
                        //console.log(dist);
                        if (dist > 0 && dist < 50) {
                            count++;
                            
                            //Alignment
                            percievedCenter.x += boids[i].x;
                            percievedCenter.y += boids[i].y;
                            
                            //Cohesion
                            percievedVelocity.x += boids[i].v.x;
                            percievedVelocity.y += boids[i].v.y;
                            //Seperation
                            if (calculateDistance(boids[i], boids[index]) < 12) {
                                flockCenter.x -= (boids[i].x - boids[index].x);
                                flockCenter.y -= (boids[i].y - boids[index].y);
                            }
                        }
                    }
                }
                if (count > 0) {
                    percievedCenter.x = percievedCenter.x / count;
                    percievedCenter.y = percievedCenter.y / count;
                    
                    percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                    percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                    
                    percievedVelocity.x = percievedVelocity.x / count;
                    percievedVelocity.y = percievedVelocity.y / count;
                    
                    flockCenter.x /= count;
                    flockCenter.y /= count;
                }
                
                addForce(index, percievedCenter);
                
                addForce(index, percievedVelocity);
                
                addForce(index, flockCenter);
            }
            
            var update = function(){
            
                for (var i = 0; i < boids.length; i++) {
                
                    //Draw boid
                    
                    ctx.beginPath();
                    ctx.strokeStyle = boids[i].c;
    
                    ctx.lineWidth = size;
                    ctx.moveTo(boids[i].x, boids[i].y);
                    boids[i].x += boids[i].v.x * speed;
                    boids[i].y += boids[i].v.y * speed;
                    applyForces(i);
                    ctx.lineTo(boids[i].x, boids[i].y);
                    ctx.stroke();
                    ctx.fill();
                    
                    checkWallCollisions(i);	
                    
                }
            }
            
            //Gui uses this to clear the canvas
            var clearCanvas = function(){
                ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                ctx.beginPath();
                ctx.rect(0, 0, width, height);
                ctx.closePath();
                ctx.fill();
            }
            
            init();
        })();

        (function() {
            var width = window.innerWidth; 
            var height = window.innerHeight; 
            var timerID = 0;
            var c = document.getElementById('canvas')
            var ctx = c.getContext('2d');
            c.width = width;
            c.height = height;
        
        
                var speed = 10;
                var size = 8;
                var boids = [];
                var totalBoids = 150;
                
                var init = function(){
                
                    for (var i = 0; i < totalBoids; i++) {
                    
                        boids.push({
                            x: Math.random() * width,
                            y: Math.random() * height,
                            v: {
                                x: Math.random() * 2 - 1,
                                y: Math.random() * 2 - 1
                            },
                            c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                        });
                    }
                    setInterval(update, 40);	
                }
                
                var calculateDistance = function(v1, v2){
                    x = Math.abs(v1.x - v2.x);
                    y = Math.abs(v1.y - v2.y);
                    
                    return Math.sqrt((x * x) + (y * y));
                }
                
                var checkWallCollisions = function(index){
                    if (boids[index].x > width) {
                        boids[index].x = 0;
                    }
                    else 
                        if (boids[index].x < 0) {
                            boids[index].x = width;
                        }
                    
                    if (boids[index].y > height) {
                        boids[index].y = 0;
                    }
                    else 
                        if (boids[index].y < 0) {
                            boids[index].y = height;
                        }
                }
                
                var addForce = function(index, force){
                
                    boids[index].v.x += force.x;
                    boids[index].v.y += force.y;
                    
                    magnitude = calculateDistance({
                        x: 0,
                        y: 0
                    }, {
                        x: boids[index].v.x,
                        y: boids[index].v.y
                    });
                    
                    boids[index].v.x = boids[index].v.x / magnitude;
                    boids[index].v.y = boids[index].v.y / magnitude;
                }
                
                //This should be in multiple functions, but this will
                //save tons of looping - Gross!
                var applyForces = function(index){
                    percievedCenter = {
                        x: 0,
                        y: 0
                    };
                    flockCenter = {
                        x: 0,
                        y: 0
                    };
                    percievedVelocity = {
                        x: 0,
                        y: 0
                    };
                    count = 0;
                    for (var i = 0; i < boids.length; i++) {
                        if (i != index) {
                        
                            //Allignment
                            dist = calculateDistance(boids[index], boids[i]);
                            
                            //console.log(dist);
                            if (dist > 0 && dist < 50) {
                                count++;
                                
                                //Alignment
                                percievedCenter.x += boids[i].x;
                                percievedCenter.y += boids[i].y;
                                
                                //Cohesion
                                percievedVelocity.x += boids[i].v.x;
                                percievedVelocity.y += boids[i].v.y;
                                //Seperation
                                if (calculateDistance(boids[i], boids[index]) < 12) {
                                    flockCenter.x -= (boids[i].x - boids[index].x);
                                    flockCenter.y -= (boids[i].y - boids[index].y);
                                }
                            }
                        }
                    }
                    if (count > 0) {
                        percievedCenter.x = percievedCenter.x / count;
                        percievedCenter.y = percievedCenter.y / count;
                        
                        percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                        percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                        
                        percievedVelocity.x = percievedVelocity.x / count;
                        percievedVelocity.y = percievedVelocity.y / count;
                        
                        flockCenter.x /= count;
                        flockCenter.y /= count;
                    }
                    
                    addForce(index, percievedCenter);
                    
                    addForce(index, percievedVelocity);
                    
                    addForce(index, flockCenter);
                }
                
                var update = function(){
                
                    for (var i = 0; i < boids.length; i++) {
                    
                        //Draw boid
                        
                        ctx.beginPath();
                        ctx.strokeStyle = boids[i].c;
        
                        ctx.lineWidth = size;
                        ctx.moveTo(boids[i].x, boids[i].y);
                        boids[i].x += boids[i].v.x * speed;
                        boids[i].y += boids[i].v.y * speed;
                        applyForces(i);
                        ctx.lineTo(boids[i].x, boids[i].y);
                        ctx.stroke();
                        ctx.fill();
                        
                        checkWallCollisions(i);	
                        
                    }
                }
                
                //Gui uses this to clear the canvas
                var clearCanvas = function(){
                    ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                    ctx.beginPath();
                    ctx.rect(0, 0, width, height);
                    ctx.closePath();
                    ctx.fill();
                }
                
                init();
            })();

            (function() {
                var width = window.innerWidth; 
                var height = window.innerHeight; 
                var timerID = 0;
                var c = document.getElementById('canvas')
                var ctx = c.getContext('2d');
                c.width = width;
                c.height = height;
            
            
                    var speed = 10;
                    var size = 8;
                    var boids = [];
                    var totalBoids = 150;
                    
                    var init = function(){
                    
                        for (var i = 0; i < totalBoids; i++) {
                        
                            boids.push({
                                x: Math.random() * width,
                                y: Math.random() * height,
                                v: {
                                    x: Math.random() * 2 - 1,
                                    y: Math.random() * 2 - 1
                                },
                                c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                            });
                        }
                        setInterval(update, 40);	
                    }
                    
                    var calculateDistance = function(v1, v2){
                        x = Math.abs(v1.x - v2.x);
                        y = Math.abs(v1.y - v2.y);
                        
                        return Math.sqrt((x * x) + (y * y));
                    }
                    
                    var checkWallCollisions = function(index){
                        if (boids[index].x > width) {
                            boids[index].x = 0;
                        }
                        else 
                            if (boids[index].x < 0) {
                                boids[index].x = width;
                            }
                        
                        if (boids[index].y > height) {
                            boids[index].y = 0;
                        }
                        else 
                            if (boids[index].y < 0) {
                                boids[index].y = height;
                            }
                    }
                    
                    var addForce = function(index, force){
                    
                        boids[index].v.x += force.x;
                        boids[index].v.y += force.y;
                        
                        magnitude = calculateDistance({
                            x: 0,
                            y: 0
                        }, {
                            x: boids[index].v.x,
                            y: boids[index].v.y
                        });
                        
                        boids[index].v.x = boids[index].v.x / magnitude;
                        boids[index].v.y = boids[index].v.y / magnitude;
                    }
                    
                    //This should be in multiple functions, but this will
                    //save tons of looping - Gross!
                    var applyForces = function(index){
                        percievedCenter = {
                            x: 0,
                            y: 0
                        };
                        flockCenter = {
                            x: 0,
                            y: 0
                        };
                        percievedVelocity = {
                            x: 0,
                            y: 0
                        };
                        count = 0;
                        for (var i = 0; i < boids.length; i++) {
                            if (i != index) {
                            
                                //Allignment
                                dist = calculateDistance(boids[index], boids[i]);
                                
                                //console.log(dist);
                                if (dist > 0 && dist < 50) {
                                    count++;
                                    
                                    //Alignment
                                    percievedCenter.x += boids[i].x;
                                    percievedCenter.y += boids[i].y;
                                    
                                    //Cohesion
                                    percievedVelocity.x += boids[i].v.x;
                                    percievedVelocity.y += boids[i].v.y;
                                    //Seperation
                                    if (calculateDistance(boids[i], boids[index]) < 12) {
                                        flockCenter.x -= (boids[i].x - boids[index].x);
                                        flockCenter.y -= (boids[i].y - boids[index].y);
                                    }
                                }
                            }
                        }
                        if (count > 0) {
                            percievedCenter.x = percievedCenter.x / count;
                            percievedCenter.y = percievedCenter.y / count;
                            
                            percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                            percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                            
                            percievedVelocity.x = percievedVelocity.x / count;
                            percievedVelocity.y = percievedVelocity.y / count;
                            
                            flockCenter.x /= count;
                            flockCenter.y /= count;
                        }
                        
                        addForce(index, percievedCenter);
                        
                        addForce(index, percievedVelocity);
                        
                        addForce(index, flockCenter);
                    }
                    
                    var update = function(){
                    
                        for (var i = 0; i < boids.length; i++) {
                        
                            //Draw boid
                            
                            ctx.beginPath();
                            ctx.strokeStyle = boids[i].c;
            
                            ctx.lineWidth = size;
                            ctx.moveTo(boids[i].x, boids[i].y);
                            boids[i].x += boids[i].v.x * speed;
                            boids[i].y += boids[i].v.y * speed;
                            applyForces(i);
                            ctx.lineTo(boids[i].x, boids[i].y);
                            ctx.stroke();
                            ctx.fill();
                            
                            checkWallCollisions(i);	
                            
                        }
                    }
                    
                    //Gui uses this to clear the canvas
                    var clearCanvas = function(){
                        ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                        ctx.beginPath();
                        ctx.rect(0, 0, width, height);
                        ctx.closePath();
                        ctx.fill();
                    }
                    
                    init();
                })();


                (function() {
                    var width = window.innerWidth; 
                    var height = window.innerHeight; 
                    var timerID = 0;
                    var c = document.getElementById('canvas')
                    var ctx = c.getContext('2d');
                    c.width = width;
                    c.height = height;
                
                
                        var speed = 10;
                        var size = 8;
                        var boids = [];
                        var totalBoids = 150;
                        
                        var init = function(){
                        
                            for (var i = 0; i < totalBoids; i++) {
                            
                                boids.push({
                                    x: Math.random() * width,
                                    y: Math.random() * height,
                                    v: {
                                        x: Math.random() * 2 - 1,
                                        y: Math.random() * 2 - 1
                                    },
                                    c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                                });
                            }
                            setInterval(update, 40);	
                        }
                        
                        var calculateDistance = function(v1, v2){
                            x = Math.abs(v1.x - v2.x);
                            y = Math.abs(v1.y - v2.y);
                            
                            return Math.sqrt((x * x) + (y * y));
                        }
                        
                        var checkWallCollisions = function(index){
                            if (boids[index].x > width) {
                                boids[index].x = 0;
                            }
                            else 
                                if (boids[index].x < 0) {
                                    boids[index].x = width;
                                }
                            
                            if (boids[index].y > height) {
                                boids[index].y = 0;
                            }
                            else 
                                if (boids[index].y < 0) {
                                    boids[index].y = height;
                                }
                        }
                        
                        var addForce = function(index, force){
                        
                            boids[index].v.x += force.x;
                            boids[index].v.y += force.y;
                            
                            magnitude = calculateDistance({
                                x: 0,
                                y: 0
                            }, {
                                x: boids[index].v.x,
                                y: boids[index].v.y
                            });
                            
                            boids[index].v.x = boids[index].v.x / magnitude;
                            boids[index].v.y = boids[index].v.y / magnitude;
                        }
                        
                        //This should be in multiple functions, but this will
                        //save tons of looping - Gross!
                        var applyForces = function(index){
                            percievedCenter = {
                                x: 0,
                                y: 0
                            };
                            flockCenter = {
                                x: 0,
                                y: 0
                            };
                            percievedVelocity = {
                                x: 0,
                                y: 0
                            };
                            count = 0;
                            for (var i = 0; i < boids.length; i++) {
                                if (i != index) {
                                
                                    //Allignment
                                    dist = calculateDistance(boids[index], boids[i]);
                                    
                                    //console.log(dist);
                                    if (dist > 0 && dist < 50) {
                                        count++;
                                        
                                        //Alignment
                                        percievedCenter.x += boids[i].x;
                                        percievedCenter.y += boids[i].y;
                                        
                                        //Cohesion
                                        percievedVelocity.x += boids[i].v.x;
                                        percievedVelocity.y += boids[i].v.y;
                                        //Seperation
                                        if (calculateDistance(boids[i], boids[index]) < 12) {
                                            flockCenter.x -= (boids[i].x - boids[index].x);
                                            flockCenter.y -= (boids[i].y - boids[index].y);
                                        }
                                    }
                                }
                            }
                            if (count > 0) {
                                percievedCenter.x = percievedCenter.x / count;
                                percievedCenter.y = percievedCenter.y / count;
                                
                                percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                                percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                                
                                percievedVelocity.x = percievedVelocity.x / count;
                                percievedVelocity.y = percievedVelocity.y / count;
                                
                                flockCenter.x /= count;
                                flockCenter.y /= count;
                            }
                            
                            addForce(index, percievedCenter);
                            
                            addForce(index, percievedVelocity);
                            
                            addForce(index, flockCenter);
                        }
                        
                        var update = function(){
                        
                            for (var i = 0; i < boids.length; i++) {
                            
                                //Draw boid
                                
                                ctx.beginPath();
                                ctx.strokeStyle = boids[i].c;
                
                                ctx.lineWidth = size;
                                ctx.moveTo(boids[i].x, boids[i].y);
                                boids[i].x += boids[i].v.x * speed;
                                boids[i].y += boids[i].v.y * speed;
                                applyForces(i);
                                ctx.lineTo(boids[i].x, boids[i].y);
                                ctx.stroke();
                                ctx.fill();
                                
                                checkWallCollisions(i);	
                                
                            }
                        }
                        
                        //Gui uses this to clear the canvas
                        var clearCanvas = function(){
                            ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                            ctx.beginPath();
                            ctx.rect(0, 0, width, height);
                            ctx.closePath();
                            ctx.fill();
                        }
                        
                        init();
                    })();

                    (function() {
                        var width = window.innerWidth; 
                        var height = window.innerHeight; 
                        var timerID = 0;
                        var c = document.getElementById('canvas')
                        var ctx = c.getContext('2d');
                        c.width = width;
                        c.height = height;
                    
                    
                            var speed = 10;
                            var size = 8;
                            var boids = [];
                            var totalBoids = 150;
                            
                            var init = function(){
                            
                                for (var i = 0; i < totalBoids; i++) {
                                
                                    boids.push({
                                        x: Math.random() * width,
                                        y: Math.random() * height,
                                        v: {
                                            x: Math.random() * 2 - 1,
                                            y: Math.random() * 2 - 1
                                        },
                                        c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                                    });
                                }
                                setInterval(update, 40);	
                            }
                            
                            var calculateDistance = function(v1, v2){
                                x = Math.abs(v1.x - v2.x);
                                y = Math.abs(v1.y - v2.y);
                                
                                return Math.sqrt((x * x) + (y * y));
                            }
                            
                            var checkWallCollisions = function(index){
                                if (boids[index].x > width) {
                                    boids[index].x = 0;
                                }
                                else 
                                    if (boids[index].x < 0) {
                                        boids[index].x = width;
                                    }
                                
                                if (boids[index].y > height) {
                                    boids[index].y = 0;
                                }
                                else 
                                    if (boids[index].y < 0) {
                                        boids[index].y = height;
                                    }
                            }
                            
                            var addForce = function(index, force){
                            
                                boids[index].v.x += force.x;
                                boids[index].v.y += force.y;
                                
                                magnitude = calculateDistance({
                                    x: 0,
                                    y: 0
                                }, {
                                    x: boids[index].v.x,
                                    y: boids[index].v.y
                                });
                                
                                boids[index].v.x = boids[index].v.x / magnitude;
                                boids[index].v.y = boids[index].v.y / magnitude;
                            }
                            
                            //This should be in multiple functions, but this will
                            //save tons of looping - Gross!
                            var applyForces = function(index){
                                percievedCenter = {
                                    x: 0,
                                    y: 0
                                };
                                flockCenter = {
                                    x: 0,
                                    y: 0
                                };
                                percievedVelocity = {
                                    x: 0,
                                    y: 0
                                };
                                count = 0;
                                for (var i = 0; i < boids.length; i++) {
                                    if (i != index) {
                                    
                                        //Allignment
                                        dist = calculateDistance(boids[index], boids[i]);
                                        
                                        //console.log(dist);
                                        if (dist > 0 && dist < 50) {
                                            count++;
                                            
                                            //Alignment
                                            percievedCenter.x += boids[i].x;
                                            percievedCenter.y += boids[i].y;
                                            
                                            //Cohesion
                                            percievedVelocity.x += boids[i].v.x;
                                            percievedVelocity.y += boids[i].v.y;
                                            //Seperation
                                            if (calculateDistance(boids[i], boids[index]) < 12) {
                                                flockCenter.x -= (boids[i].x - boids[index].x);
                                                flockCenter.y -= (boids[i].y - boids[index].y);
                                            }
                                        }
                                    }
                                }
                                if (count > 0) {
                                    percievedCenter.x = percievedCenter.x / count;
                                    percievedCenter.y = percievedCenter.y / count;
                                    
                                    percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                                    percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                                    
                                    percievedVelocity.x = percievedVelocity.x / count;
                                    percievedVelocity.y = percievedVelocity.y / count;
                                    
                                    flockCenter.x /= count;
                                    flockCenter.y /= count;
                                }
                                
                                addForce(index, percievedCenter);
                                
                                addForce(index, percievedVelocity);
                                
                                addForce(index, flockCenter);
                            }
                            
                            var update = function(){
                            
                                for (var i = 0; i < boids.length; i++) {
                                
                                    //Draw boid
                                    
                                    ctx.beginPath();
                                    ctx.strokeStyle = boids[i].c;
                    
                                    ctx.lineWidth = size;
                                    ctx.moveTo(boids[i].x, boids[i].y);
                                    boids[i].x += boids[i].v.x * speed;
                                    boids[i].y += boids[i].v.y * speed;
                                    applyForces(i);
                                    ctx.lineTo(boids[i].x, boids[i].y);
                                    ctx.stroke();
                                    ctx.fill();
                                    
                                    checkWallCollisions(i);	
                                    
                                }
                            }
                            
                            //Gui uses this to clear the canvas
                            var clearCanvas = function(){
                                ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                                ctx.beginPath();
                                ctx.rect(0, 0, width, height);
                                ctx.closePath();
                                ctx.fill();
                            }
                            
                            init();
                        })();
                    
                        (function() {
                            var width = window.innerWidth; 
                            var height = window.innerHeight; 
                            var timerID = 0;
                            var c = document.getElementById('canvas')
                            var ctx = c.getContext('2d');
                            c.width = width;
                            c.height = height;
                        
                        
                                var speed = 10;
                                var size = 8;
                                var boids = [];
                                var totalBoids = 150;
                                
                                var init = function(){
                                
                                    for (var i = 0; i < totalBoids; i++) {
                                    
                                        boids.push({
                                            x: Math.random() * width,
                                            y: Math.random() * height,
                                            v: {
                                                x: Math.random() * 2 - 1,
                                                y: Math.random() * 2 - 1
                                            },
                                            c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                                        });
                                    }
                                    setInterval(update, 40);	
                                }
                                
                                var calculateDistance = function(v1, v2){
                                    x = Math.abs(v1.x - v2.x);
                                    y = Math.abs(v1.y - v2.y);
                                    
                                    return Math.sqrt((x * x) + (y * y));
                                }
                                
                                var checkWallCollisions = function(index){
                                    if (boids[index].x > width) {
                                        boids[index].x = 0;
                                    }
                                    else 
                                        if (boids[index].x < 0) {
                                            boids[index].x = width;
                                        }
                                    
                                    if (boids[index].y > height) {
                                        boids[index].y = 0;
                                    }
                                    else 
                                        if (boids[index].y < 0) {
                                            boids[index].y = height;
                                        }
                                }
                                
                                var addForce = function(index, force){
                                
                                    boids[index].v.x += force.x;
                                    boids[index].v.y += force.y;
                                    
                                    magnitude = calculateDistance({
                                        x: 0,
                                        y: 0
                                    }, {
                                        x: boids[index].v.x,
                                        y: boids[index].v.y
                                    });
                                    
                                    boids[index].v.x = boids[index].v.x / magnitude;
                                    boids[index].v.y = boids[index].v.y / magnitude;
                                }
                                
                                //This should be in multiple functions, but this will
                                //save tons of looping - Gross!
                                var applyForces = function(index){
                                    percievedCenter = {
                                        x: 0,
                                        y: 0
                                    };
                                    flockCenter = {
                                        x: 0,
                                        y: 0
                                    };
                                    percievedVelocity = {
                                        x: 0,
                                        y: 0
                                    };
                                    count = 0;
                                    for (var i = 0; i < boids.length; i++) {
                                        if (i != index) {
                                        
                                            //Allignment
                                            dist = calculateDistance(boids[index], boids[i]);
                                            
                                            //console.log(dist);
                                            if (dist > 0 && dist < 50) {
                                                count++;
                                                
                                                //Alignment
                                                percievedCenter.x += boids[i].x;
                                                percievedCenter.y += boids[i].y;
                                                
                                                //Cohesion
                                                percievedVelocity.x += boids[i].v.x;
                                                percievedVelocity.y += boids[i].v.y;
                                                //Seperation
                                                if (calculateDistance(boids[i], boids[index]) < 12) {
                                                    flockCenter.x -= (boids[i].x - boids[index].x);
                                                    flockCenter.y -= (boids[i].y - boids[index].y);
                                                }
                                            }
                                        }
                                    }
                                    if (count > 0) {
                                        percievedCenter.x = percievedCenter.x / count;
                                        percievedCenter.y = percievedCenter.y / count;
                                        
                                        percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                                        percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                                        
                                        percievedVelocity.x = percievedVelocity.x / count;
                                        percievedVelocity.y = percievedVelocity.y / count;
                                        
                                        flockCenter.x /= count;
                                        flockCenter.y /= count;
                                    }
                                    
                                    addForce(index, percievedCenter);
                                    
                                    addForce(index, percievedVelocity);
                                    
                                    addForce(index, flockCenter);
                                }
                                
                                var update = function(){
                                
                                    for (var i = 0; i < boids.length; i++) {
                                    
                                        //Draw boid
                                        
                                        ctx.beginPath();
                                        ctx.strokeStyle = boids[i].c;
                        
                                        ctx.lineWidth = size;
                                        ctx.moveTo(boids[i].x, boids[i].y);
                                        boids[i].x += boids[i].v.x * speed;
                                        boids[i].y += boids[i].v.y * speed;
                                        applyForces(i);
                                        ctx.lineTo(boids[i].x, boids[i].y);
                                        ctx.stroke();
                                        ctx.fill();
                                        
                                        checkWallCollisions(i);	
                                        
                                    }
                                }
                                
                                //Gui uses this to clear the canvas
                                var clearCanvas = function(){
                                    ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                                    ctx.beginPath();
                                    ctx.rect(0, 0, width, height);
                                    ctx.closePath();
                                    ctx.fill();
                                }
                                
                                init();
                            })();
                    
                            (function() {
                                var width = window.innerWidth; 
                                var height = window.innerHeight; 
                                var timerID = 0;
                                var c = document.getElementById('canvas')
                                var ctx = c.getContext('2d');
                                c.width = width;
                                c.height = height;
                            
                            
                                    var speed = 10;
                                    var size = 8;
                                    var boids = [];
                                    var totalBoids = 150;
                                    
                                    var init = function(){
                                    
                                        for (var i = 0; i < totalBoids; i++) {
                                        
                                            boids.push({
                                                x: Math.random() * width,
                                                y: Math.random() * height,
                                                v: {
                                                    x: Math.random() * 2 - 1,
                                                    y: Math.random() * 2 - 1
                                                },
                                                c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                                            });
                                        }
                                        setInterval(update, 40);	
                                    }
                                    
                                    var calculateDistance = function(v1, v2){
                                        x = Math.abs(v1.x - v2.x);
                                        y = Math.abs(v1.y - v2.y);
                                        
                                        return Math.sqrt((x * x) + (y * y));
                                    }
                                    
                                    var checkWallCollisions = function(index){
                                        if (boids[index].x > width) {
                                            boids[index].x = 0;
                                        }
                                        else 
                                            if (boids[index].x < 0) {
                                                boids[index].x = width;
                                            }
                                        
                                        if (boids[index].y > height) {
                                            boids[index].y = 0;
                                        }
                                        else 
                                            if (boids[index].y < 0) {
                                                boids[index].y = height;
                                            }
                                    }
                                    
                                    var addForce = function(index, force){
                                    
                                        boids[index].v.x += force.x;
                                        boids[index].v.y += force.y;
                                        
                                        magnitude = calculateDistance({
                                            x: 0,
                                            y: 0
                                        }, {
                                            x: boids[index].v.x,
                                            y: boids[index].v.y
                                        });
                                        
                                        boids[index].v.x = boids[index].v.x / magnitude;
                                        boids[index].v.y = boids[index].v.y / magnitude;
                                    }
                                    
                                    //This should be in multiple functions, but this will
                                    //save tons of looping - Gross!
                                    var applyForces = function(index){
                                        percievedCenter = {
                                            x: 0,
                                            y: 0
                                        };
                                        flockCenter = {
                                            x: 0,
                                            y: 0
                                        };
                                        percievedVelocity = {
                                            x: 0,
                                            y: 0
                                        };
                                        count = 0;
                                        for (var i = 0; i < boids.length; i++) {
                                            if (i != index) {
                                            
                                                //Allignment
                                                dist = calculateDistance(boids[index], boids[i]);
                                                
                                                //console.log(dist);
                                                if (dist > 0 && dist < 50) {
                                                    count++;
                                                    
                                                    //Alignment
                                                    percievedCenter.x += boids[i].x;
                                                    percievedCenter.y += boids[i].y;
                                                    
                                                    //Cohesion
                                                    percievedVelocity.x += boids[i].v.x;
                                                    percievedVelocity.y += boids[i].v.y;
                                                    //Seperation
                                                    if (calculateDistance(boids[i], boids[index]) < 12) {
                                                        flockCenter.x -= (boids[i].x - boids[index].x);
                                                        flockCenter.y -= (boids[i].y - boids[index].y);
                                                    }
                                                }
                                            }
                                        }
                                        if (count > 0) {
                                            percievedCenter.x = percievedCenter.x / count;
                                            percievedCenter.y = percievedCenter.y / count;
                                            
                                            percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                                            percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                                            
                                            percievedVelocity.x = percievedVelocity.x / count;
                                            percievedVelocity.y = percievedVelocity.y / count;
                                            
                                            flockCenter.x /= count;
                                            flockCenter.y /= count;
                                        }
                                        
                                        addForce(index, percievedCenter);
                                        
                                        addForce(index, percievedVelocity);
                                        
                                        addForce(index, flockCenter);
                                    }
                                    
                                    var update = function(){
                                    
                                        for (var i = 0; i < boids.length; i++) {
                                        
                                            //Draw boid
                                            
                                            ctx.beginPath();
                                            ctx.strokeStyle = boids[i].c;
                            
                                            ctx.lineWidth = size;
                                            ctx.moveTo(boids[i].x, boids[i].y);
                                            boids[i].x += boids[i].v.x * speed;
                                            boids[i].y += boids[i].v.y * speed;
                                            applyForces(i);
                                            ctx.lineTo(boids[i].x, boids[i].y);
                                            ctx.stroke();
                                            ctx.fill();
                                            
                                            checkWallCollisions(i);	
                                            
                                        }
                                    }
                                    
                                    //Gui uses this to clear the canvas
                                    var clearCanvas = function(){
                                        ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
                                        ctx.beginPath();
                                        ctx.rect(0, 0, width, height);
                                        ctx.closePath();
                                        ctx.fill();
                                    }
                                    
                                    init();
                                })();
                    
                                (function() {
                                    var width = window.innerWidth; 
                                    var height = window.innerHeight; 
                                    var timerID = 0;
                                    var c = document.getElementById('canvas')
                                    var ctx = c.getContext('2d');
                                    c.width = width;
                                    c.height = height;
                                
                                
                                        var speed = 10;
                                        var size = 8;
                                        var boids = [];
                                        var totalBoids = 150;
                                        
                                        var init = function(){
                                        
                                            for (var i = 0; i < totalBoids; i++) {
                                            
                                                boids.push({
                                                    x: Math.random() * width,
                                                    y: Math.random() * height,
                                                    v: {
                                                        x: Math.random() * 2 - 1,
                                                        y: Math.random() * 2 - 1
                                                    },
                                                    c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                                                });
                                            }
                                            setInterval(update, 40);	
                                        }
                                        
                                        var calculateDistance = function(v1, v2){
                                            x = Math.abs(v1.x - v2.x);
                                            y = Math.abs(v1.y - v2.y);
                                            
                                            return Math.sqrt((x * x) + (y * y));
                                        }
                                        
                                        var checkWallCollisions = function(index){
                                            if (boids[index].x > width) {
                                                boids[index].x = 0;
                                            }
                                            else 
                                                if (boids[index].x < 0) {
                                                    boids[index].x = width;
                                                }
                                            
                                            if (boids[index].y > height) {
                                                boids[index].y = 0;
                                            }
                                            else 
                                                if (boids[index].y < 0) {
                                                    boids[index].y = height;
                                                }
                                        }
                                        
                                        var addForce = function(index, force){
                                        
                                            boids[index].v.x += force.x;
                                            boids[index].v.y += force.y;
                                            
                                            magnitude = calculateDistance({
                                                x: 0,
                                                y: 0
                                            }, {
                                                x: boids[index].v.x,
                                                y: boids[index].v.y
                                            });
                                            
                                            boids[index].v.x = boids[index].v.x / magnitude;
                                            boids[index].v.y = boids[index].v.y / magnitude;
                                        }
                                        
                                        //This should be in multiple functions, but this will
                                        //save tons of looping - Gross!
                                        var applyForces = function(index){
                                            percievedCenter = {
                                                x: 0,
                                                y: 0
                                            };
                                            flockCenter = {
                                                x: 0,
                                                y: 0
                                            };
                                            percievedVelocity = {
                                                x: 0,
                                                y: 0
                                            };
                                            count = 0;
                                            for (var i = 0; i < boids.length; i++) {
                                                if (i != index) {
                                                
                                                    //Allignment
                                                    dist = calculateDistance(boids[index], boids[i]);
                                                    
                                                    //console.log(dist);
                                                    if (dist > 0 && dist < 50) {
                                                        count++;
                                                        
                                                        //Alignment
                                                        percievedCenter.x += boids[i].x;
                                                        percievedCenter.y += boids[i].y;
                                                        
                                                        //Cohesion
                                                        percievedVelocity.x += boids[i].v.x;
                                                        percievedVelocity.y += boids[i].v.y;
                                                        //Seperation
                                                        if (calculateDistance(boids[i], boids[index]) < 12) {
                                                            flockCenter.x -= (boids[i].x - boids[index].x);
                                                            flockCenter.y -= (boids[i].y - boids[index].y);
                                                        }
                                                    }
                                                }
                                            }
            if (count > 0) {
                percievedCenter.x = percievedCenter.x / count;
                percievedCenter.y = percievedCenter.y / count;
                
                percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
                percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
                
                percievedVelocity.x = percievedVelocity.x / count;
                percievedVelocity.y = percievedVelocity.y / count;
                
                flockCenter.x /= count;
                flockCenter.y /= count;
            }
            
            addForce(index, percievedCenter);
            
            addForce(index, percievedVelocity);
            
            addForce(index, flockCenter);
        }
        
        var update = function(){
        
            for (var i = 0; i < boids.length; i++) {
            
                //Draw boid
                
                ctx.beginPath();
                ctx.strokeStyle = boids[i].c;

                ctx.lineWidth = size;
                ctx.moveTo(boids[i].x, boids[i].y);
                boids[i].x += boids[i].v.x * speed;
                boids[i].y += boids[i].v.y * speed;
                applyForces(i);
                ctx.lineTo(boids[i].x, boids[i].y);
                ctx.stroke();
                ctx.fill();
                
                checkWallCollisions(i);	
                
            }
        }
        
        //Gui uses this to clear the canvas
        var clearCanvas = function(){
            ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
            ctx.beginPath();
            ctx.rect(0, 0, width, height);
            ctx.closePath();
            ctx.fill();
        }
        
        init();
    })();


    (function() {
        var width = window.innerWidth; 
        var height = window.innerHeight; 
        var timerID = 0;
        var c = document.getElementById('canvas')
        var ctx = c.getContext('2d');
        c.width = width;
        c.height = height;
    
    
            var speed = 10;
            var size = 8;
            var boids = [];
            var totalBoids = 150;
            
            var init = function(){
            
                for (var i = 0; i < totalBoids; i++) {
                
                    boids.push({
                        x: Math.random() * width,
                        y: Math.random() * height,
                        v: {
                            x: Math.random() * 2 - 1,
                            y: Math.random() * 2 - 1
                        },
                        c: 'rgba(' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ',' + Math.floor(Math.random() * 255) + ', 1.0)'
                    });
                }
                setInterval(update, 40);	
            }
            
            var calculateDistance = function(v1, v2){
                x = Math.abs(v1.x - v2.x);
                y = Math.abs(v1.y - v2.y);
                
                return Math.sqrt((x * x) + (y * y));
            }
            
            var checkWallCollisions = function(index){
                if (boids[index].x > width) {
                    boids[index].x = 0;
                }
        else 
            if (boids[index].x < 0) {
                boids[index].x = width;
            }
        
        if (boids[index].y > height) {
            boids[index].y = 0;
        }
        else 
            if (boids[index].y < 0) {
                boids[index].y = height;
            }
    }
    
    var addForce = function(index, force){
    
        boids[index].v.x += force.x;
        boids[index].v.y += force.y;
        
        magnitude = calculateDistance({
            x: 0,
            y: 0
        }, {
            x: boids[index].v.x,
            y: boids[index].v.y
        });
        
        boids[index].v.x = boids[index].v.x / magnitude;
        boids[index].v.y = boids[index].v.y / magnitude;
    }
    
    //This should be in multiple functions, but this will
    //save tons of looping - Gross!
    var applyForces = function(index){
        percievedCenter = {
            x: 0,
            y: 0
        };
        flockCenter = {
            x: 0,
            y: 0
        };
        percievedVelocity = {
            x: 0,
            y: 0
        };
        count = 0;
        for (var i = 0; i < boids.length; i++) {
            if (i != index) {
            
                //Allignment
                dist = calculateDistance(boids[index], boids[i]);
                
                //console.log(dist);
                if (dist > 0 && dist < 50) {
                    count++;
                    
                    //Alignment
                    percievedCenter.x += boids[i].x;
                    percievedCenter.y += boids[i].y;
                    
                    //Cohesion
                    percievedVelocity.x += boids[i].v.x;
                    percievedVelocity.y += boids[i].v.y;
                    //Seperation
                    if (calculateDistance(boids[i], boids[index]) < 12) {
                        flockCenter.x -= (boids[i].x - boids[index].x);
                        flockCenter.y -= (boids[i].y - boids[index].y);
                    }
                }
            }
        }
        if (count > 0) {
            percievedCenter.x = percievedCenter.x / count;
            percievedCenter.y = percievedCenter.y / count;
            
            percievedCenter.x = (percievedCenter.x - boids[index].x) / 400;
            percievedCenter.y = (percievedCenter.y - boids[index].y) / 400;
            
            percievedVelocity.x = percievedVelocity.x / count;
            percievedVelocity.y = percievedVelocity.y / count;
            
            flockCenter.x /= count;
            flockCenter.y /= count;
        }
        
        addForce(index, percievedCenter);
        
        addForce(index, percievedVelocity);
        
        addForce(index, flockCenter);
    }
    
    var update = function(){
    
        for (var i = 0; i < boids.length; i++) {
        
            //Draw boid
            
            ctx.beginPath();
            ctx.strokeStyle = boids[i].c;

            ctx.lineWidth = size;
            ctx.moveTo(boids[i].x, boids[i].y);
            boids[i].x += boids[i].v.x * speed;
            boids[i].y += boids[i].v.y * speed;
            applyForces(i);
            ctx.lineTo(boids[i].x, boids[i].y);
            ctx.stroke();
            ctx.fill();
            
            checkWallCollisions(i);	
            
        }
    }
    
    //Gui uses this to clear the canvas
    var clearCanvas = function(){
        ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
        ctx.beginPath();
        ctx.rect(0, 0, width, height);
        ctx.closePath();
        ctx.fill();
    }
    
    init();
})();

1711 líneas

Organización del código JavaScript

  • ¿2000 líneas en un solo archivo?

Ventajas

Inconvenientes

  • Difícil de leer/entender
  • Difícil de mantener
  • Poca reusabilidad
  • Difícil encontrar código no usado
  • Colisiones de nombres
  • Una sola petición HTTP

Organización del código JavaScript

  • Optimización: dividir el código en varios archivos/módulos

<head>
    <meta charset="UTF-8">
    <title>Mi web</title>
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="js/modules/tabs.js"></script>
    <script src="js/modules/banners.js"></script>
    <script src="js/modules/lightbox.js"></script>   
    <script src="js/modules/scroll.js"></script>
    <script src="js/modules/carousel.js"></script>     
    <script src="js/modules/slideshow.js"></script>
    <script src="js/modules/gallery.js"></script>
    <script src="js/modules/navigation.js"></script>
</head>

Organización del código JavaScript

Ventajas

Inconvenientes

  • Difícil encontrar código no usado (menos difícil que antes)
  • Colisiones de nombres
  • Muchas peticiones HTTP
  • El orden importa: dependencias
  • Legible e inteligible
  • Fácil de mantener
  • Reutilizable
  • Cargamos sólo lo que necesitamos
<head>
    <meta charset="UTF-8">
    <title>Mi web</title>
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="js/modules/tabs.js"></script>
    <script src="js/modules/banners.js"></script>
    <script src="js/modules/lightbox.js"></script>   
    <script src="js/modules/scroll.js"></script>
    <script src="js/modules/carousel.js"></script>     
    <script src="js/modules/slideshow.js"></script>
    <script src="js/modules/gallery.js"></script>
    <script src="js/modules/navigation.js"></script>
</head>

Organización del código JavaScript

  • Dependencias: es difícil asegurar el orden, y no es posible tener dependencias circulares

<head>
    <meta charset="UTF-8">
    <title>Mi web</title>
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="js/modules/tabs.js"></script>
    <script src="js/modules/banners.js"></script>
    <script src="js/modules/lightbox.js"></script>   
    <script src="js/modules/scroll.js"></script>
    <script src="js/modules/carousel.js"></script>     
    <script src="js/modules/slideshow.js"></script>
    <script src="js/modules/gallery.js"></script>
    <script src="js/modules/navigation.js"></script>
</head>

Organización del código JavaScript: módulos

  • Module loaders: ellos gestionan las dependencias y cargan los módulos (RequireJS, SystemJS)

Ventajas

Inconvenientes

  • Difícil encontrar código no usado (menos difícil que antes)
  • Muchas peticiones HTTP
  • Legible e inteligible
  • Fácil de mantener
  • Reutilizable
  • Cargamos sólo lo que necesitamos
  • Gestión automática de dependencias
  • Encapsulación

Organización del código JavaScript: módulos

  • Module bundlers: además de lo anterior, generan un solo código encadenado y minificado (browserify, webpack)

Ventajas

  • Legible e inteligible
  • Fácil de mantener
  • Reutilizable
  • Cargamos sólo lo que necesitamos
  • Gestión automática de dependencias
  • Encapsulación
  • Una o muy pocas conexiones HTTP
  • Eliminación de código no usado (tree shaking)

Organización del código JavaScript: módulos

  • ¿Puedo escribir mis módulos como yo quiera? ¿hay un estándar?

  • AMD: Asynchronous Module Definition

  • CommonJS

  • UMD: Universal Module Definition

  • ES6 Modules

define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {

  return {
    hello: function() {
      console.log('hello');
    },
    goodbye: function() {
      console.log('goodbye');
    }
  };
});
var myModuleA = require('myModuleA');

function myModuleB() {
  this.hello = function() {
    return 'hello!';
  }

  this.goodbye = function() {
    return 'goodbye!';
  }
}

module.exports = myModuleB;
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
      // AMD
    define(['myModule', 'myOtherModule'], factory);
  } else if (typeof exports === 'object') {
      // CommonJS
    module.exports = factory(require('myModule'), require('myOtherModule'));
  } else {
    // Browser globals (Note: root is window)
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
}(this, function (myModule, myOtherModule) {
  // Methods
  function notHelloOrGoodbye(){}; // A private method
  function hello(){}; // A public method because it's returned (see below)
  function goodbye(){}; // A public method because it's returned (see below)

  // Exposed public methods
  return {
      hello: hello,
      goodbye: goodbye
  }
}));
import { method1 } from './moduleA.js';

method1("hello");

export let method2 = function() {
    console.log("Method 2");
}

Organización del código JavaScript: módulos

  • ¿AMD, CommonJS, UMD, ES6?

  • Compatibilidad de los módulos ES6 en navegadores

  • ¡Webpack!

  • TypeScript usa la sintaxis ES6

  • TS -> ES5 -> webpack -> bundle -> browser =

Angular CLI

ES6

  • let y const

  • Template literals

  • for ... of

  • Funciones

    • Parámetros opcionales

    • Función arrow:

      (parámetros) => expresión_devuelta;

ES6

  • Operador spread

    • Parámetros en funciones

    • Enviar varios parámetros a partir de un array

    • push y unshift

    • Intercalar un array dentro de otro

    • Copiar un array en otro

    • Copiar un objeto en otro

ES6

  • Clases

    • Propiedades y métodos

    • Getters y setters

    • Propiedades y métodos estáticos

    • Herencia con extends y super()

ES6

  • Módulos

    • import

      import { literal } from 'ruta_modulo';
      import literal from 'ruta_modulo';
      import * as literal from 'ruta_modulo';
      import 'ruta_modulo';
    • export
      export let a = 3;
      export let class Clase {
          ...
      }
      export default {
          key: value
      }

Programación funcional con arrays

  • Métodos:

    • map

    • filter

    • reduce

    • find

  • Encadenamiento

TypeScript

TypeScript

  • Superconjunto de JavaScript

  • Transpila a ES5

  • Tipado

  • Errores en tiempo de compilación

  • tsc

  • tsconfig.json

TypeScript

  • Tipos básicos:

    • number

    • string

    • boolean

    • Array

    • any

    • void

  • Enum

  • Union types

  • Genéricos

TypeScript

  • Funciones

    • Sin flexibilidad en el número de parámetros

    • Parámetros opcionales

  • Clases

    • Propiedades fuera del constructor

    • Visibilidad de los miembros

      • Modificador readonly

    • Propiedades estáticas

    • Interfaces

    • Métodos abstractos

TypeScript

  • Decoradores (@)

Angular

Primeros pasos

  • ng new para generar la app

  • ng serve -o para ejecutarla y verla en el navegador

  • Entornos dev y prod

  • Módulos, componentes y vistas

  • Archivos de configuración

Esqueleto de una pieza en Angular

  • clase =>

  • => clase exportada =>

  • => clase exportada y decorada =>

  • => dependencias

Examinando un componente

  • Metadata

    • selector

    • template / templateUrl

    • styles / styleUrls

Examinando un template

  • Custom elements

  • Data binding

  • Interpolation

  • Property binding

  • Class & style binding

  • Event binding

  • Two-way binding

Examinando un template

  • Directivas de atributo

    • ngClass

    • ngStyle

  • Directivas estructurales

    • ngIf

    • ngFor

    • ngSwitch

  • Pipes

    • @Pipe, PipeTransform

Servicios

  • Dependency Injection

  • Injectable()

  • Proveedores

  • Singleton

Formularios

  • [(ngModel)]: Two-way binding

  • ngForm, ngModel y ngSubmit

  • Variables de template con #

  • Validaciones: los diferentes estados

  • Resetear los estados

  • Template driven y Reactive forms

Conexiones con el servidor

  • Asincronía

  • Observables

  • Suscripciones

  • API REST

  • El módulo HttpClientModule

    • Módulo HttpClientModule y servicio HttpClient

    • Métodos del servicio HttpClient:
      get(), post(), put(), patch(), delete()

Navegación por la app

  • El router

  • Las rutas

    • Parámetros: los observables paramMap, queryParamMap y data de ActivatedRoute

    • Página por defecto

    • 404

    • Guards

  • El RouterOutlet

  • Links de navegación: routerLink y routerLinkActive

  • router.navigate()

  • History API

  • El servicio Title

Despliegue a producción

  • Pruebas con ng build

  • ng build:

    • --prod: código optimizado para producción

    • --build-optimizer: más optimización

    • --base-href=: cambia el directorio base

    • --sourcemaps: genera los source maps

Links