jueves, 29 de marzo de 2012

Cristalab

Cristalab


Validar formularios de forma nativa con HTML5

Posted: 29 Mar 2012 01:46 AM PDT

La validación de formularios del lado del cliente ha sido un problema que siempre se ha solucionado con la utilización de Javascript, ya sea con código propio o de terceros. Esto es debido a que en el pasado era siquiera impensable el tener una solución con HTML puro, pero con la llegada del conjunto de especificaciones y tecnologías que componen el actual HTML5, ahora esto es posible, aunque con la clara desventaja de que todavía no es soportado por la mayoría de los navegadores y quienes los soportan tienen su forma particular de ejecutarse, sin embargo es importante tenerlo presente, ya que en el futuro próximo será de una utilidad invaluable.

[nota:a1ae15b1f7] para los ejemplos expuestos en este artículo, se ha utilizado Google Chrome versión 18 por ser el navegador que más funcionalidad de HTML5 ha implementado a la fecha.[/nota:a1ae15b1f7]


El atributo «required»


Al incluir el atributo required dentro de un elemento <input>, automáticamente se hace obligatorio su llenado y al ser un atributo tipo booleano, solo se requiere su presencia sin más.

Código :

<input type="text" name="nombre" required>



En el momento en que se encuentra un error de validación se ejecuta la acción por defecto del navegador, normalmente aparece un pequeño globo emergente (tooltip) conteniendo un texto de advertencia. Añadiendo el atributo title en la etiqueta <input>, se puede extender la información mostrada.

Código :

<input type="text" name="nombre" title="Se necesita un nombre" required>




El atributo «pattern» y los tipos de <input>


Como se mencionó anteriormente, con required sólo se necesita de cualquier valor en el elemento <input> para ser válido, pero utilizando el atributo pattern en conjunto, se logra que se verifique no solo la presencia de un valor, sino que este valor debe contener un formato, una longitud o un tipo de dato especifico. Esto último se logra definiendo un patrón con expresiones regulares.

Código :

<input type="text" pattern="^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" name="email" required>



Con el patrón anterior se valida un formato valido de correo electrónico (mail@example.com), pero en la práctica esto resulta un tanto absurdo, ya que definiendo un tipo email en la etiqueta <input>, el navegador por sí mismo hace la validación del tipo en cuestión.

Código :

<input type="email" name="email" required>



Es lo mismo con el resto de los tipos de <input>: search, url, tel, email, password, date pickers, number, checkbox, radio y file. Por lo tanto el potencial del atributo pattern recae en ser más específico en el tipo de formato y longitud que se requiere. Por ejemplo, supongamos que se necesita que el usuario ingrese una dirección valida de IPV4, lo hacemos de la siguiente manera:

Código :

<input type="text" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" title="0.0.0.0" name="ipv4">

Cuatro bloques de uno a tres dígitos divididos por puntos, es la notación punto-decimal de una dirección válida de IPV4.


La pseudo clase :invalid de CSS3


Básicamente la pseudo clase :invalid representa cualquier campo inválido que sea resultado de una validación (valga la redundancia), lo opuesto ocurre con su contraparte: :valid. Esto facilita que si un campo contiene un valor inválido pueda adoptar una apariencia acorde, de esta forma ayudando al usuario a identificar los campos que necesitan ser verificados.

Código :

  input:invalid {     border: 1px solid red;   }    /* Estilo por defecto */   input:valid {     border: 1px solid green;   } 


Un aspecto que es importante resaltar, es que por defecto todos los campos son válidos – como es de esperarse –, pero si un campo es requerido, entonces ocurre lo contrario, este por defecto será invalidado.


Código :

  /* Estilo por defecto */   input:required:invalid {     border: 1px solid red;   }    input:required:valid {     border: 1px solid green;   } 



Conclusión


Esta es una más de las grandes bondades que trae consigo HTML5, sin embargo la validación de formularios de manera nativa aun se encuentra en una etapa temprana de desarrollo, especialmente con lo que respecta a la manera de notificar la existencia de un campo no válido, ya que no existen etiquetas CSS para personalizar el estilo del tooltip, al menos en caso de Google Chrome.

Escrito por Jonathan Javier { Twitter: @jonasanx }

Referencias


Enviar comentario

Leer JSON con Javascript y PHP

Posted: 08 Mar 2012 12:03 AM PST

En estos días he estado trabajando con la API de Vimeo para un par de proyectos, pero me encontré en la necesidad de tener que hacer el llamado directamente a un archivo JSON y entonces me puse a investigar qué es eso de JSON.

[nota:d876898b21] Anexo ejemplos directos del parseo de JSON con el ejemplo de la API de Vimeo, sin embargo, este tutorial no está enfocado a revisar el uso de la API.[/nota:d876898b21]

¿Qué es JSON?


Es el acrónimo de JavaScript Object Notation. Si conoces XML, se podría decir que es una alternativa a un sistema de envío y recepción de datos.

El "parseo" o "parsear" es leer o administrar una base de datos o conjunto de texto.

La estructura o sintaxis es de la siguiente manera:

Código :

{ "objeto" : valor } 

El siguiente ejemplo de estructura está tomado de la API de Vimeo algo recortada:

Código :

[{   "title":"titulo",   "description":"Lorem Ipsum Dolor sit Amet", }] 


Parseo con Javascript


La manera más fácil de pasear un JSON con javascript es a través de jQuery + Ajax con la función $.getJSON que es equivalente a:

Código :

$.ajax({   url: url,   dataType: 'json',   data: data,   success: callback });

El cual se utiliza de la siguiente manera:

Código :

$.getJSON( url [, data] [, success(data, textStatus, jqXHR)] ) 

El siguiente código lo apliqué para extraer título y descripción de una petición a la API de Vimeo

Código :

$.getJSON('http://www.vimeo.com/api/v2/video/31894179.json?callback=?', {format: "json"}, function(data) {  $("h1").html(data[0].title);  $("p").html(data[0].description);  }); 

Básicamente estoy accediendo con la función $.getJSON a la url que me proporciona la documentación de la API de Vimeo para obtener un JSON (aquí), defino qué formato estoy usando, y ejecuto una función a partir del mismo.

Dentro de ésta, con la función .html, "extraigo" el campo del título y descripción y se los "pongo" a la etiqueta <h1></h1> y <p></p>. Existe el selector data[0] porque solamente estoy obteniendo la primera parte del JSON, si tuviera por ejemplo varios videos, le agregaría 0, 1, 2 respectivamente para seleccionar las otras partes.

Parseo con PHP


Para realizar el parseo antes que nada necesitamos saber si la estructura JSON está dentro del archivo a ejecutar o afuera. Si está afuera puedes utilizar cURL para leer el archivo.

Necesitamos también de una función llamada json_decode, esta sirve para convertir un string JSON a una variable que funciona en PHP.

El siguiente ejemplo sirvió para llamar título y descripción de un video utilizando la API de Vimeo.

Código :

//Url donde esta nuestro JSON $req = 'http://vimeo.com/api/oembed.json?url=http://vimeo.com/31894179';  //Iniciamos cURL junto con la URL $cVimeo = curl_init($req);  //Agregamos opciones necesarias para leer curl_setopt($cVimeo,CURLOPT_RETURNTRANSFER, TRUE);  // Capturamos la URL $gVimeo = curl_exec($cVimeo);  //Descodificamos para leer $getVimeo = json_decode($gVimeo,true);  //Asociamos los campos del JSON a variables $titulo = $getVimeo['title']; $descripcion = $getVimeo['description']; $thumbnail = $getVimeo['thumbnail_url'];

Cada vez que llamamos a la variable $getVimeo estamos leyendo el archivo JSON, como ya está descodificado gracias a la función json_decode es posible buscar los campos "title" y "description". Ya después es cuestión de llamarlas o agregarlas a nuestro HTML con un echo o lo que quieras.

Ya sabes la base y con un ejemplo bastante simple. El parseo es igual en cualquier otro JSON, quizás solo varíe en el número de secciones que tenga el JSON. Google es tu mejor amigo.

Cualquier duda quedo a sus órdenes, puedes dejarme un comentario o preguntarme vía twitter @kinduff

Enviar comentario

miércoles, 28 de marzo de 2012

Cristalab

Cristalab

Cristalab


Sistemas y herramientas para visualizar y extraer datos de Twitter

Posted: 28 Mar 2012 01:45 AM PDT

En Twitter se publican muchas cosas, desde las opiniones sobre la polémica política del momento hasta actualizaciones con relación a la vida íntima. Según [1] la taza de publicación de tweets, durante la transmisión del super tazón, fue de 10.000 tweets por segundo.

Y por qué habría de resultar esto interesante?


Cuánto nos tardaría leer sólo lo publicado en 1 segundo (10.000 tweets), y cuánto nos tardaríamos en encontrar información de interés entre esos 10.000 tweets?

Sí, muchísimo tiempo!

Ahora imaginemos que no sólo queremos los 10.000 tweets, si no que deseamos tener una idea general de lo que se está comentando…leerías todo? y como encontrarías la relación de los tweets entre sí?

La Extracción de información es una tarea que consiste en:

  • de gran cantidad (hablo de gigas o teras) de información (en formato texto)
  • extraer una lista con información que sea de interés.


A partir de esas listas de eventos, ítems o información, se pueden hacer otros tipos de procesamientos más interesantes, por ejemplo, análisis de sentimientos para intentar determinar la opinión general sobre cierto tema en particular.


Corpus


A la gran cantidad de información se le llama corpus, un corpus es simplemente una colección de texto, por ejemplo podríamos guardar todos los tweets publicados durante el super tazón, y a esa colección de tweets la podríamos llamar "corpus de tweets publicados durante el super tazón".

Voy a intentar aclarar un poco más en qué consiste la extracción de información. Supongamos que hemos recolectado un corpus sobre videojuegos, que está compuesto de artículos de revistas sobre videojuegos, entradas de blog, de foros etc..

Ahora queremos generar, a partir de ese corpus, una lista con la siguiente información:

NombreVideoJuego - Compañía - FechaDeSalida


Supongamos que en nuestro corpus existe una frase que diga algo como:

:

" Square Enix ya está trabajando en Final Fantasy X"


La extracción agregaría el siguiente registro a nuestra lista:


  • NombreVideoJuego: "Final Fantasy X"
  • Compañía:"Square Enix"
  • FechaDeSalida: "null"


El resultado final, debería ser una tabla llena con todos los videojuegos y la respectiva compañía desarrolladora. Sin embargo, existen retos, muchos retos. Uno de ellos, por ejemplo, consiste en que alguien puede escribir "Final Fantasy X" o puede referirse al mismo juego escribiendo "FFX". De hecho, si hablamos de juegos, a los gamers les encanta usar acrónimos, y podríamos tener casos en los que dos juegos diferentes tengan acrónimos iguales.


Experimento


Algunas semanas atrás, leí una entrada sobre Extracción y Visualización de Información en Twitter [2], aunque el experimento resultaba bastante sencillo, y la extracción es bastante ingenua, me pareció un reto interesante para el fin de semana.

Corrí mi implementación sobre algunos trends de Colombia, y sobre tweets relacionados con Cristalab, aquí les dejo algunas imágenes.

[nota:45df40fbde]click en las imagenes para agrandar[/nota:45df40fbde]

El tema en la imagen es "cartoons", y se ven las ramificaciones sobre los diferentes cartoons:


El tema en la imagen es "qué aman las mujeres":


El tema principal en la imagen es "la liberación de secuestrados en colombia":


Sobre los "tweets de cristalab en marzo":




Básicamente, la imagen es un árbol donde cada nodo representa una palabra, dos palabras se relacionan entre sí si existieron tweets en los cuales las cuales las palabras se usaron.

Los nodos adyacentes a cada palabra representan tweets que incluyeron los términos de la raíz hasta el nodo.

Las "estrellas" en el árbol representan los temas más populares.


Intentaré explicar algunos de los pasos y la idea en general:



En resumen:

  1. capturar tweets
  2. limpiar tweets

    • Corrección de cadenas
    • Quitar Símbolos, caracteres extraños
    • POS tagger de los tweets
    • Reconocimiento de nombres

  3. limpieza final
  4. Conteo y frecuencia de palabras
  5. representación en grafo



Selección de Tweets


El primer paso es construir el corpus que necesitamos, y para eso podemos usar el API de Twitter. En el API de twitter podemos hacer búsquedas de tweets con respecto a un radio geográfico o también por palabras.

Sobre el corpus generado hay que dejar claro que es un corpus lleno de basura.
Sí! basura, necesitamos limpiarlo, de muchas formas. Pueden haber tweets que no nos sirvan o que simplemente tengan errores de escritura.


Pre-procesamiento


Cosas que usualmente se hacen en el pre-procesamiento o limpieza:


  • transformar palabras como: 'muuuuuuuuuuuuuuuy' a 'muy'.
  • encontrar posibles errores de escritura, por ejemplo: 'encontrar' 'necontrar'..
  • quitar URLS, emails y símbolos que consideremos extraños.


Similitud de Cadenas


Este tipo de limpieza implica por ejemplo medir similitud de cadenas. La similitud consiste en si tienes dos strings A y B, identificar qué tan parecidos o diferentes son.

Sólo el tema de similitud de cadenas puede ser un tutorial completo. En general existen diferentes estrategias para medir la similitud de cadenas, entre los más conocidos están Jaro, Jaro-Winkler, Soundex y Levenstein.

La más conocida es Levenstein, pero a nivel personal no me agrada mucho por dos razones, primero la comparación de cadenas no es normalizada, es decir, el número que arroja depende del largo de las cadenas. Mientras Jaro y Jaro-Winkler son normalizadas, sin importar el largo, si las cadenas son completamente iguales, el resultado es 1.

Una de mis favoritas es Soundex, que mide la similitud entre cadenas en base a la fonética, por ejemplo las palabras "rupert" y "robert" serían muy parecidas, dado que fonéticamente son similares. De hecho el pre-procesamiento usualmente incluye también NLP, dependiendo de lo que deseamos realizar.

Lo que ocurre usualmente es que deseamos anotar nuestros datos con información extra. En este caso el resultado final será un grafo conectando las palabras clave, así que necesitaba incluir en la limpieza una forma de evitar ramificaciones adicionales por ejemplo:

Si los tweets extraídos hablaban sobre el tema "liberación de secuestrados", tendremos tweets donde se mencionará: "liberacion", "liberaran", "liberaron", "liberarian", dado que el español es un idioma con bastantes declinaciones, terminaríamos con un árbol con muchas ramas, todas refiriéndose en esencia al mismo verbo "liberar". Otro ejemplo podría ser con los plurales y singulares. Una forma de evitar este tipo de problemas es usando un POS-tagger.



POS Tagger


POS-tagger (Part of Speech Tagger) es una herramienta cuya entrada es texto, y la salida es texto anotado. A cada palabra le va asignada su función dentro de la oración. Por ejemplo si la oración es:

:

'Juan visita Alemania'

Entonces la salida será algo como:


  • Juan - Sustantivo
  • Visita -Verbo Transitivo - tiempo: presente- Infinitivo: Visitar
  • Alemania - Sustantivo


Existen POS-taggers ya entrenados para ciertos idiomas, entre ellos el español. Dependiendo de la herramienta podría arrojarnos información adicional, por ejemplo si el sustantivo es plural o singular.

El pos-tagger también nos ayuda a limpiar palabras que no tengan significado por sí mismas. Por ejemplo, podemos limpiar posteriormente todas las palabras que sean preposiciones.

StopWords


Existen palabras que no tienen significado por sí mismas y otras que sí lo tienen pero que resultan muy comunes. Estas palabras se llaman stopwords. En la visualización del grafo quería evitar este tipo de palabras, ya que resultan ser basura (no en todos los casos lo son). Existen utilidades que ya traen una lista de Stopwords para español. Por ejemplo la librería nltk en python ya trae una lista de stopwords para español.

Reconocimiento de Entidades


Es también una herramienta a partir de la cual se reconocen nombres propios, lugares y fechas. No es un diccionario, eso quiere decir que no es una lista definida de nombres, es una herramienta entrenada usando técnicas de inteligencia artificial para reconocer nombres propios.

Existen herramientas especializadas para la detección de nombres en dominios particulares. El reconocimiento de nombres propios se resume en 2 tareas:

  • Reconocer nombres propios dentro de texto
  • Desambiguación de nombres.


La desambiguación se refiere por ejemplo a que pueden existir múltiples formas de nombrar a una misma entidad. Si habláramos de "Barack Obama", en los tweets se pueden referir al mismo personaje de muchas formas: "Obama", "B. Obama", "Barack O.", "El presidente de estados unidos"...

La segunda tarea puede ser muy complicada, sin embargo la primera es relativamente un problema resuelto.

Lo que hice para este extractor ingenuo fue simplemente usar una herramienta ya entrenada para reconocimiento de nombres pero no para la desambiguación. Quería mantener dentro de las palabras claves dibujadas dentro del grafo, aquellos nombres propios y lugares que tuvieran cierta frecuencia dentro del corpus de tweets.


Limpieza final


La última limpieza consiste en reemplazar todas las conjugaciones de verbos por infinitivos y todos los plurales por singulares. Si esta limpieza se hace antes, el reconocimiento de nombres y el POS tagger no funcionarán adecuadamente.

Estando el corpus ya limpio, se procede a crear una tabla de frecuencias, es decir, vamos a contar cuántas veces está cada palabra dentro del corpus, de esas palabras seleccionaremos aquellas que tengan una frecuencia más alta, y a partir de ellas, vamos a empezar a crear el grafo.


Representación del grafo


Para la visualización se usó la herramienta gource [3]. Básicamente los que hice fue iterar sobre la lista de tweets. Sobre cada tweet preguntaba en orden descendente con respecto a la frecuencia si la palabra se encontraba dentro del tweet.

Supongamos que nuestra lista de frecuencias era algo como:

    palabra - frecuencia
    "secuestro" - 400
    "liberacion" - 300
    "violencia" - 30


Así, si un tweet contiene las palabras "secuestro" y "liberación", existirá una arista conectando "secuestro" y "liberacion" y, finalmente, "liberacion" tendrá una arista a un nodo que será la representación del tweet.


Para terminar


Esto fue sólo un experimento de fin de semana y la extracción de información usualmente tiene muchos retos. El objetivo de este post es simplemente dar a conocer un poco de qué trata la extracción de información y las herramientas disponibles.

La extracción de información es usada para construir un sistema de preguntas y respuestas que son eficaces para un dominio específico y que al parecer, empieza a ser popular pues algunas compañías están pidiendo sus sistemas automáticos de preguntas y respuestas para sus sitios webs.

Adicionalmente dada la cantidad de información que está siendo generada por los usuarios, muchas compañías están interesadas en aplicar procesamiento del lenguaje natural para saber qué quieren sus clientes o qué opinan sus clientes sobre sus productos. Vale mencionar que también lo están implementando las agencias de seguridad.

Muchas cosas quedaron sin mencionar y aquellas que se mencionaron se podrían mencionar a un nivel más profundo, pero este post ya es suficientemente largo y aburrido así que decidí acortar la idea inicial.

Espero les haya gustado.

@dav009


[1] Tweets per second - http://yearinreview.twitter.com/en/tps.html
[2] http://highwire-dtc.co.uk/2011/05/real-time-twitter-topic-clustering-and-data-visualisation/
[3] http://code.google.com/p/gource/

Enviar comentario

Revisar cambios con Debug en Redes Cisco

Posted: 28 Mar 2012 01:10 AM PDT

En este videotutorial vamos a usar el comando Debug en Redes Cisco, para mantener información en todo momento de los cambios que se producen en nuestros dispositivos, como modificaciones y ajustes de configuración del sistema, que se realizarán en respuesta a la introducción de nuestros comandos y que nos ofrecerán información vital del funcionamiento de determinados procesos de envío de actualizaciones de los protocolos de enrutamiento.



Saludos.

Enviar comentario

HTML5 es más que etiquetas

Posted: 07 Mar 2012 09:01 AM PST

HTML5, CSS3 y Javascript son la nueva columna vertebral de la experiencia de usuario en Internet, acortado como "HTML5", similar a lo que en su tiempo fue la "Web 2.0".

"Web 2.0" es un termino desafortunado. Inventado por O'Reilly y desvirtuado por el marketing, nunca significó nada más allá de "AJAX con usabilidad" y terminó como sinonimo de ignorancia tecnologica.

Ahora tenemos "HTML5". HTML5 es la nueva versión semántica del lenguaje de etiquetas con el que se construye internet. Pero la W3C, el consorcio encargado del estándar, también ha tomado HTML5 como el término sombrilla que engloba las nuevas tecnologías del futuro de la web. A diferencia de "web 2.0", esta vez HTML5 tiene un norte definido, un grupo de empresas y fundaciones apoyando y una visión.



"¡¡Pero HTML5 no es CSS3 y Javascript!!"


HTML5 es un lenguaje de modelado de información por etiquetas. CSS3 es un lenguaje de estilos en cascada. Javascript es un lenguaje de programación. Y todos, todos, se engloban alrededor del concepto HTML5.

Flash es una herramienta vectorial, un formato de animación y un contenedor de Actionscript 3, así como el player de varios formatos de video y del sistema de RIAs Flex.

¿Y saben qué? Sigue llamandose Flash todo eso.

La W3C oficialmente aceptó "HTML5" como el concepto sombrilla, al punto que creo un logo principal y una página de marca explicando claramente que HTML5 es HTML y más que HTML.


Los geeks fanaticos no entienden de marcas


La discusión de que HTML5 no es CSS3 que se dio en Cristalab la semana pasada me recuerda la discusión de si "Linux" es "GNU/Linux" o no. La realidad es que a nadie le importa. Sí es importante definir qué cosa es qué al programar, pero cualquier persona inteligente puede diferenciar el uso de HTML5 en cada contexto.

¿Por qué el odio a usar HTML5 como concepto? No lo sé ¿Elitismo? No encuentro el menor sentido en atacar un concepto que ayuda a entender mejor una nueva tecnología y por extensión a vender más, mejor y más avanzados proyectos a los clientes y usuarios.

El artículo de la semana pasada dice que Web Storage, la capacidad de guardar en disco con Javascript, no es HTML5. Y publica esta URL:
http://dev.w3.org/html5/webstorage/
Donde parte de la URL dice HTML5!!

¿Quieren más ejemplos? Entren a:
http://dev.w3.org/html5/

Donde encontrarán Canvas (Bitmaps Javascript), Device (cámaras, microfonos), Websockets (Mensajes realtime), Web Workers (JS multitarea) entre muchos otros ejemplos bajo HTML5.



"HTML5 estará listo en el 2014"


El último y más famoso recurso de los detractores de HTML5 es que "no está listo". ¿Ustedes creen que HTML5 es un software que una empresa "termina"? HTML5 es un spec vivo, cuya implementación depende de los navegadores y del cual gran parte se puede usar ya mismo sin problemas. Eso incluye CSS3. Es posible usar CSS3 en Internet Explorer viejos. Es posible usar HTML5 desde ya.

El draft HTML5 de la W3C no se cerrará hasta dentro de unos años, pero para entonces nuestros navegadores tendrán nuevas tecnologías, porque no es Flash o Visual Basic, es una tecnología viva que crece con su uso.

Sean profesionales, usen HTML5 y no teman llamarle a las cosas por su marca.

Enviar comentario

Enrutamiento estático en Redes Cisco

Posted: 07 Mar 2012 12:21 AM PST

Después de haber estudiado toda la teoría del sistema de direcciones IPv4, por fin aprenderemos el uso del enrutamiento estático para conectar y generar rutas entre diferentes redes a través de los dispositivos intermedios, trabajando sobre una topología simple que usaremos para configurar todos los pasos y seleccionar los comandos correctos para generar nuestro camino bidireccional en cada segmento de la red y testeándolo finalmente para comprobar la conectividad entre ambos extremos.



Saludos.

Enviar comentario

Diseño web para iPhone

Posted: 28 Jul 2009 05:00 PM PDT

El diseño web en iPhone requiere conocimientos de HTML 5, CSS y Javascript especial para usar todo el poder de Safari Mobile. En este tutorial hablamos de cómo crear sitios web optimizados para iPhone y navegadores Webkit como Android.

martes, 27 de marzo de 2012

Cristalab

Cristalab


Crea iconos Buddy en Photoshop

Posted: 27 Mar 2012 06:11 AM PDT



En este videotutorial trabajaremos en la creación de un Buddy Icon en Photoshop, practicando con múltiples variaciones para enriquecer el diseño de uno de los elementos más ampliamente utilizados para referenciar a personas en la Web.



Saludos.

Enviar comentario

Centrar menú de ancho variable con CSS

Posted: 26 Mar 2012 11:46 PM PDT

Este tutorial explica cómo centrar menús CSS horizontales de ancho variable basados en listas.

Nivel: Básico.

El menú en con listas


Si existe un elemento común a cualquier proyecto web ese es el menú de navegación. Lo que me empuja a escribir este pequeño tutorial es que, según mi breve experiencia docente, todo maquetador web sabe como crear menús de navegación usando listas y CSS, pero la mayoría no saben cómo alinearlos al centro.

Crear el menú es muy sencillo. Primero creamos la estructura:

Código :

  <nav>         <ul>             <li><a href="#">Sección</a></li>             <li><a href="#">Otra sección</a></li>             <li><a href="#">La tercera sección</a></li>             <li><a href="#">Última sección</a></li>         </ul> </nav> 


Después mediante CSS eliminamos los estilos de lista, y hacemos que los <li> floten a su izquierda:

Código :

 <style>         nav{             height: auto; /*Junto a overflow: hidden; aplicará a nuestro elemento nav el mismo alto que el más alto de sus elementos hijos */              margin: 0 auto; /* Centro el contenedor */             overflow: hidden;             text-align: left;             width: 960px; /* Defino el ancho de mi página */         }         ul{             float: left;             list-style-type: none; /* Elimino los estilos de lista */             padding: 0;          }         li{             float: left; /* Floto los li para que se dispongan horizontalmente */         }         li a{             padding: 10px; /* El padding añadirá separación entre los elementos */         } </style> 


Cómo centrar el menú


Cuando definimos la propiedad float del li a left, no sólo ajustamos la disposición a horizontal, sino que además los estamos alineando a la izquierda y al revés con float:right;. Si conocemos el ancho total de los li podríamos ajustar al centro mediante padding en el ul, pero en la mayoría de CMS, donde el número de elementos de un menú puede variar, esta solución obliga a cambiar el css cada vez que añadamos, modifiquemos o suprimamos elementos. ¿Cómo alineamos nuestro menú al centro si el ancho del mismo es variable? Tan fácil como añadir 4 líneas:

Código :

 <style>         ul{             float: left;             list-style-type: none;             padding: 0;              /* AÑADIMOS */             position: relative;              left: 50%;         }         li{             float: left;             /* AÑADIMOS */             position: relative;              right: 50%;         } </style> 


¿Qué ha pasado?


No. No es brujería.
Primero hemos definido las posiciones del ul y li como relativas. Al indicar la distancia de la izquierda del ul y de la derecha del li estamos colocando nuestros contenedores como muestra la siguiente figura:


Las diferentes capas y sus posiciones

Enviar comentario

Cómo pensar y crear un slider en jQuery

Posted: 07 Mar 2012 12:19 AM PST

Hola amigos, voy a intentar explicar lo mejor que pueda y razonando todas las partes (y ni que decir tiene que desde mis conocimientos que no lucen por ser completos precisamente), cómo crear un slider en jQuery que sea capaz de generar varios sliders en pantalla y que todos funcionen de manera independiente. También intentaré razonar la estructuración inicial, el por qué de los cálculos y demás...

No puedo prometer ni prometo, que el slider no se pueda hacer mejor ni más completo que como yo lo planteo en este tutorial (pues es obvio que sí se puede), por lo que si sabes cómo mejorarlo y estás dispuesto a compartirlo con los demás, estaría encantado de recibir tus consejos. Y si son factibles y no son una chapuza, como muchas de las que se me ocurren a mí, los incluiré encantado nombrándote en el tuto e indicando tu aportación.

Empecemos por ver qué es lo que queremos conseguir y cómo estructurarlo:



1. Estructura interna del slider y de las imágenes



Vamos a visualizar cualquiera de los 2 sliders que encontraréis aquí. Fijaos en el parpadeo y el cambio de textos que suceden cuando se pone el ratón encima de una de las imágenes. Con fijarnos en estos elementos tendremos una idea de todos los elementos que componen el slider.

(Internamente tiene alguno más pero ya los veremos cuando desarrollemos código, pues no son visibles para el usuario)

Bien, visto esto vamos a pensar en la estructura del contenedor. Lo básico sería tener un div contenedor con 4 divs internos que sean las imágenes. Veámoslo:



Ahora vamos a intentar imaginar la estructura de cada div imagen. Este también se habrá de componer de un div contenedor y dentro de éste una imagen o un div con fondo de imagen (nosotros usaremos el div), encima de la imagen un div blanco tranparente que parpadee con los hover del mouse y encima de este un div alineado al pie que contenga: un div negro con transparencia, encima un div con el título y encima de este un div con el mensaje alternativo ó 2º mensaje, este último oculto. Veámoslo:



2. Datos necesarios para generar un slider


El siguiente paso es pensar en los datos que necesitaremos para generar un slider (no hace falta decir que sólo hemos de pensar en los datos que puedan cambiar de un slider a otro y que no se puedan calcular a partir de otros datos).

    1. Ancho del contenedor principal.
    2. Alto de las imágenes (el contenedor principal también medirá esto de alto)
    3. Ancho de las imágenes.
    4. Altura de la caja de textos.
    5. Ruta de la carpeta de las imágenes.
    6. Un array con las imágenes y sus datos.
      • Nombre de la imagen.
      • Url del link.
      • Texto para el título
      • Texto para el subtítulo


¡Hecho!, vamos a generar un objeto javaScript con todos estos datos y vamos a llamarlo losDatosDelSlider.

Código :

losDatosDelSlider = {    'anchoImagen': 733,    'altoImagen': 350,    'anchoTotal': 930,    'alturaCajaTextos': 75,    'carpetaImagenes': 'imgb/',    'imagenes':[       {'url': '1.jpg', 'Link': '1.cristalab.com', 'tit': 'Uno', 'subt': '1'},       {'url': '2.jpg', 'Link': '2.cristalab.com', 'tit': 'Dos', 'subt': '2'},       {'url': '3.jpg', 'Link': '3.cristalab.com', 'tit': 'Tres', 'subt': '3'},       {'url': '4.jpg', 'Link': '4.cristalab.com', 'tit': 'Cuatro', 'subt': '4'}    ]    }


Ahora vamos a crear nuestra función principal e inicializar las variables. Lo primero es preparar la función para que reciba los datos y los pueda introducir en algún elemento del DOM, así que la creamos con la variable datos y con la variable contenedorSlider (esta variable debería ser un string con la id del objeto donde se vaya a crear el slider y con la almohadilla incluida (ej: '#laIdObjetivo') y debería pertenecer a un div por norma general).

Código :

function crearSlider(datos, contenedorSlider) {    //Bien en teoría al ejecutar la función estamos recibiendo los datos del objeto js que hemos creado más arriba (luego lo haremos en la llamada a la función), así como el nombre de lo que vamos a usar de contenedor.    //Empezamos a definir las variables    var contenedor = $(contenedorSlider),       carpetaImagenes = datos.carpetaImagenes,       anchoImagen = datos.anchoImagen,       altoImagen = datos.altoImagen,       anchoTotal = datos.anchoTotal,       imagenes = datos.imagenes,       totalImagenes = imagenes.length,       boxNegro = datos.alturaCajaTextos,       //Calculo lo que ocupa en pantalla cada imagen que es el ancho del contenedor dividido por el número de imágenes que va a contener (este cálculo nos valdrá para establecer la posición inicial de los divs de imagen)       anchoMedia = anchoTotal/totalImagenes; }



3. Asignando datos y rellenando el contenedor


El siguiente paso es rellenar el contenedor, lo primero que haremos es asignarle una clase y definiremos su ancho y su alto, posteriormente mediante un bucle, lo rellenaremos con tantas imágenes como necesitemos, ¡vamos a ello!

Código :

function crearSlider(datos, contenedorSlider) {        [Código anterior]        //Asignamos el ancho y el alto al contenedor y le añadimos su clase personalizada (esta la configuraremos más tarde en el css)    contenedor.width(anchoTotal).height(altoImagen).addClass('bloqueDisplay');        //Ahora creo el bucle y relleno el contenedor (el bucle entrará una vez por cada imagen definida en el objeto js que hemos creado al principio "losDatosDelSlider", e índice valdrá +1 cada vez que el bucle pase por una imagen, la primera valdrá 0, la segunda 1, la tercera 2...)    for (indice in imagenes) {              //Creo el div imagen dentro de una selección (para agregarle contenido) y le asigno una id personalizada por el índice (imagen0, imagen1, imagen2...)       contenedor.append($('<div class="imagen" id="imagen'+indice+'">')                    //Agrego al div imagen -- un div interno que estará oculto por css y que contendrá el link que se cargará al hacer click sobre la imagen. En la siguiente línea cuando pongo imagenes[indice].Link, estoy cogiendo el link de la imagen que hay en la posición relativa al paso del bucle, es decir en el primer paso estaré recogiendo el link de la imagen que hay en la primera posición, posición 0 (imagenes[0]), en la segunda pasada estaré cogiendo el link de la imágenes que hay en la segunda posición, la posición 1 (imagenes[1]) y así consecutivamente hasta que no haya más imágenes.          .append($('<div class="links">').html(imagenes[indice].Link))                    //Agrego al div imagen -- un div dentro de una selección (para aplicarle una animación) con fondo blanco que va a ocupar toda la imagen y lo hago desaparecer según lo creo. Este div nos hará el efecto del parpadeo de la imagen           .append($('<div class="parpadeo" />').fadeTo(0, 0).dequeue())                    //Agrego al div imagen -- un div dentro de una selección (para agregarle contenidos) que será la caja inferior con los textos          .append($('<div class="cajaTextos" />')                       //Agrego al div cajaTextos -- el div que será el fondo oscuro de los textos             .append('<div class="fondoOscuro" />')                          //Agrego al div cajaTextos -- un div dentro de una selección (para agregarle contenidos), que será el título visible por defecto             .append($('<div class="titular" />').html(imagenes[indice].tit))                          //Agrego al div cajaTextos -- un div dentro de una selección (para agregarle contenidos), que estará oculto y será el título y subtítulo que aparecerán cuando el usuario haga over sobre alguna de las imágenes del slider. lo hago desaparecer según lo creo y le agrego un div para el título, y el subtítulo             .append($('<div class="subtitular" />').fadeTo(0, 0).dequeue()                .append($('<div class="titulo" />').html(imagenes[indice].tit))                .append('<br />'+imagenes[indice].subt)             )          )       )    }     }


¡HOOOORAY!, con eso tenemos el slider relleno, ahora por partes, a cada elemento que lo necesite de los que acabamos de crear le vamos a ir aplicando medidas y así vamos completando el código.

Empezaremos por el primer elemento que se crea en el bucle. El div imagen: si recordamos, cada una de las imágenes del slider tiene una sombra a la izquierda, por lo que le agregaremos la clase sombraIzquierda que configuraremos más adelante. Después definiremos su ancho, su alto, su z-index (capa) y su imagen de background. También definiremos su cualidad left. Como hemos visto el bucle empieza por 0, por lo que para calcular el left, no nos hará más falta que multiplicar la variable anchoMedia por el índice. Veamos el cálculo.



Ahora, veamos cómo queda la línea con los nuevos datos:

Código :

//Línea anterior contenedor.append($('<div class="imagen" id="imagen'+indice+'">')  //Nueva línea contenedor.append($('<div'+    'class="imagen sombraIzquierda"'+    'id="imagen'+indice+'"'+    'style="width:'+anchoImagen+'px;'+       'height:'+altoImagen+'px;'+       'left:'+(anchoMedia*indice)+'px;'+       'z-index:'+indice+';'+       'background: url('+carpetaImagenes+imagenes[indice].url+')" />')


Vamos a configurar el alto de la caja de textos. La medida está definida en las variables iniciales como "boxNegro" el ancho no hace falta definirlo pues será el 100%, así ocupará todo el ancho de la imagen e irá en el css.

Código :

//Línea anterior .append($('<div class="cajaTextos" />')  //Línea nueva .append($('<div class="cajaTextos" style="height:'+boxNegro+'px" />')

Con esto tenemos toda la personalización que necesitamos de momento, el resto de los estilos y medidas irán el el css y así podremos cambiar todos los estilos del slider sin modificar el javaScript. Es hora de ver la primera fusión del código. ¡Veamos lo que llevamos!

Código :

function crearSlider(datos, contenedorSlider) {    var contenedor = $(contenedorSlider),       carpetaImagenes = datos.carpetaImagenes,       anchoImagen = datos.anchoImagen,       altoImagen = datos.altoImagen,       anchoTotal = datos.anchoTotal,       imagenes = datos.imagenes,        totalImagenes = imagenes.length,       boxNegro = datos.alturaCajaTextos,       anchoMedia = anchoTotal/totalImagenes;           contenedor.width(anchoTotal).height(altoImagen).addClass('bloqueDisplay');     for (indice in imagenes) {       contenedor          .append($('<div class="imagen sombraIzquierda"'+             'id="imagen'+indice+'"'+             'style="width:'+anchoImagen+'px;'+                'height:'+altoImagen+'px;'+                'left:'+(anchoMedia*indice)+'px;'+                'z-index:'+indice+';'+                'background: url('+carpetaImagenes+imagenes[indice].url+')" />')          .append($('<div class="links">').html(imagenes[indice].Link))          .append($('<div class="parpadeo" />').fadeTo(0, 0).dequeue())          .append($('<div class="cajaTextos" style="height:'+boxNegro+'px" />')             .append('<div class="fondoOscuro" />')             .append($('<div class="titular" />').html(imagenes[indice].tit))             .append($('<div class="subtitular" />').fadeTo(0, 0).dequeue()                .append($('<div class="titulo" />').html(imagenes[indice].tit))                .append('<br />'+imagenes[indice].subt)             )          )       )    } }


4. Creando los eventos del mouse y calculando las posiciones para los eventos



Poco a poco, poco a poco, vamos llegando al grosso del tuto. Vamos a empezar a configurar los listeners del mouse y a calcular las nuevas posiciones de las imágenes cuando se tengan que mover, el último paso será programar la pequeña función que se va a encargar de ejecutar los movimientos (animaciones) y después crearemos el css. Comenzaremos creando la función reiniciarListeners que se encargará de desvincular los eventos actuales asociados a la clase imagen y volverá a crearlos. También vamos a crear acción del click:

Código :

function reiniciarListeners () {    //Desvinculo todos los eventos que puedan tener las imágenes    $('.imagen').unbind();        //Vinculo el evento click a todos los elementos que tengan la clase imagen.    $('.imagen').click(function () {              //Al hacer click almaceno en la variable url la url destino del objeto clickeado, que está almacenada en su div.links (este div está oculto con la propiedad css display:none, lo configuraremos más adelante)        var url = $(this).find('.links').html();              //Y le paso la nueva url al navegador                window.location.href = '#/'+url;    }); }


Con esto ya tenemos configurado el click de las imágenes y su correspondiente acción, que será abrir una url al hacer click. Ahora vamos a configurar las acciones over y out, es decir lo que ocurre cuando el ratón pasa sobre una de las imágenes y lo que ocurre cuando sale de ella. Por si alguien nunca ha visto cómo asignar en jQuery los eventos over y out en un único selector mediante .hover(), lo vamos a ver rápidamente.

Código :

$(miSelector).hover(    //Definimos la primera de las funciones, la que se ejecutará al hacer over    function () {       //Aquí programamos las cosas que ocurrirán en el over    },    //Definimos la segunda de las funciones, la que se ejecutará al hacer out    function () {       //Aquí programamos las cosas que ocurrirán en el out });


Sencillo ¿no?, pues ahora a programar las acciones que nos calcularán las nuevas posiciones izquierdas de las imágenes en cada evento del ratón. Vamos a parar un par de minutos a pensar lo que sucerá cuando pongamos el ratón sobre una de las imágenes.

      DIV IMAGEN
    • En la imagen seleccionada el div parpadeo parpadeará 1 vez.
    • En la imagen seleccionada el título se desvanecerá.
    • En la imagen seleccionada el subtítulo aparecerá.

      MOVIMIENTOS
    • Todas las imágenes se moverán a excepción de la primera.
    • Si el ratón está sobre la primera de las imágenes todas se moverán a la derecha
    • Si el ratón está sobre la última de las imágenes todas se moverán a la izquierda
    • Si el ratón está sobre cualquier otra imagen, las imágenes anteriores a esta y esta se moverán a la izquierda y las posteriores a la derecha
    • La imagen sobre la que está el ratón mostrará todo su ancho dentro del slider


Sabido esto, y dado que la imagen sobre la que esté el ratón se va a mostar entera en el slider, hemos de asumir que el resto de imágenes ocupará lo que nos quede libre del slider, dividido entre el resto de las imágenes, es decir (anchoTotal-anchoImagen), con esto obtenemos el espacio que nos queda libre para las imágenes que estén fuera del mouse, si esto lo dividimos por el total de imágenes menos 1 (-1 por que la imagen sobre la que está el ratón no hay que contarla, pues ya tiene su espacio asignado dentro del slider que es igual a su ancho), obtendremos el espacio que han de ocupar el resto de las imágenes en su posición cerrada, ((anchoTotal-anchoImagen)/(totalImagenes-1)). Veamos el cálculo:



Vamos a empezar en la función OVER, definiendo los valores que vamos a necesitar. Además de las medidas tendremos que definir el div que parpadeará, el que se desvanecerá y el que aparecerá. Con respecto a las medidas, podríamos obtener alguno de los valores necesitados de nuestro objeto js losDatosDelSlider, pero dado que queremos hacer una función que sea capaz de generar varios sliders y una función que sea capaz de moverlos independientemente, los vamos a extraer directamente del DOM, es decir de los objetos que tengamos instanciados en el navegador.

Código :

//Primero voy a extraer el índice de la imagen dentro de su slider, es decir la posición que ocupa entre las demás imágenes. Para esto primero buscamos todas las imágenes que hay dentro de su contenedor  $($this).parent().find('.imagen')           //Y ahora vamos a buscar la posición de la imagen que está bajo el ratón dentro de la selección que acabamos de hacer. Creamos la selección dentro de un selector y preguntamos por el índice de la imagen en over "this"  $($(this).parent().find('.imagen')).index(this)  //Con esto ya tenemos la posición de la imagen sobre la que estamos. //Vamos a definir el anchoTotal, que extraeremos del padre (.parent()) de la imagen, y el anchoImagen que extraeremos de la propia imagen.  anchoTotal = $(this).parent().width() anchoImagen = $(this).width()  //Lo siguiente es calcular la cantidad de imágenes que hay en el contenedor. //////////// Seguro que hay una manera más fácil de hacer esto, si alguien la pudiera aportar se lo agradecería. //////////// //Ahora vuelvo a crear la selección que he creado al principio de la función, pero esta vez le pregunto el índice de la última imagen que haya dentro del contenedor, y como el índice siempre empieza en 0, le sumo 1 para obtener el total de imágenes.  //SELECCIÓN INICIAL  $(this).parent() //Voy a su elemento superior    .find('.imagen') //Busco cualquier elemento con la clase imagen     //SELECCIÓN DE LA ULTIMA IMAGEN DENTRO DE LA CAJA  $(this).parent() //Voy a su elemento superior    .find('.imagen:last') //Busco el último elemento con la clase imagen     //Y AHORA LO UNO PARA BUSCAR EL ÍNDICE DE LA ULTIMA Y LE SUMO 1  $($(this).parent().find('.imagen'))    .index($(this).parent().find('.imagen:last'))+1  //lo siguiente es calcular el ancho de las imágenes cerradas (podemos ver el cálculo en el último gráfico)  cerrado = (anchoTotal-anchoImagen)/(totalImagenes-1)  //Ahora localizaremos el div títulos que contiene el título y el subtítulo  titulos = $(this).find('div:eq(2)')  //Y por último localizaremos el div que va a parpadear  parp = $(this).find('.parpadeo')


Antes de ver lo anterior unido, voy a explicar que queremos conseguir con las funciones over y out. De estas funciones lo único que necesitamos que hagan es que nos calculen las posiciones x de las imágenes y que monten un array con ellas, después este array se lo pasaremos a la última función que será la que genere los movimientos a partir de este array, así que también definiremos un array vacío. Veamos lo que llevamos de la función OVER:

Código :

function /*OVER*/ () {             var num = $($(this).parent().find('.imagen')).index(this),       anchoTotal = $(this).parent().width(),       anchoImagen = $(this).width(),       totalImagenes = $($(this).parent().find('.imagen'))          .index($(this).parent().find('.imagen:last'))+1,       cerrado = (anchoTotal-anchoImagen)/(totalImagenes-1)       titulos = $(this).find('div:eq(2)'),       parp = $(this).find('.parpadeo'),       arr = []; }


Ahora un poco de animación. Lo primeo que queremos que haga la imagen seleccionada es que parpadee (efecto tipo iluminación, ¡¡¡"CUTRE"!!!, que ya estoy viendo a alguno decir que eso no es iluminación, lo sé, pero no se me ocurre mejor manera más corta de explicarlo con palabras), y que a la vez que se produce el parpadeo, desaparezca el título y aparezca el subtítulo.

Código :

//Hago aparecer el div parpadeo en 0 milisegundos (a partir de ahora ms), al 50% de opacidad (0.5 pues la opacidad va de 0 a 1)  parp.fadeTo(0, 0.5).dequeue();  //En medio segundo 500 ms, lo hago desaparecer, opacidad 0.   parp.fadeTo(500, 0).dequeue();  //Localizo el div título y subtitulo y en 300 ms hago desaparecer el primero, opacidad 0 y hago aparecer el segundo opacidad 1  titulos.find('div:eq(1)').fadeTo(300,0).dequeue(); titulos.find('div:eq(2)').fadeTo(300,1).dequeue();  //Y los índices son 1 y 2 por que en el 0 está el fondo negro semi-opaco


Bueno, ahora sólo nos queda calcular las posiciones de las imágenes y para ello vamos a crear un bucle que pase por encima de cada imagen y con un condicional diferenciaremos si la imagen a mover está posicionada antes que la imagen o es la imagen con over, y si está detrás de la imagen con over. Por qué es esto, bueno por que depende de donde esté posicionada la imagen con respecto a la que tiene over, habrá que calcular su left de manera diferente. Veamos el primer caso, imágenes a la derecha.



Como vemos en el ejemplo, a la posición x de todas las imágenes que hay a la derecha de la seleccionada, hay que sumarle el AnchoImagen y lo que ocupa en pantalla la imagen en posición cerrada multiplicado por su índice-1 que viene a ser lo que vemos en el gráfico Posicion = anchoImagen+(w*(indice-1)). Este cálculo es diferente para la imagen seleccionada, o las que estén posicionadas anteriores a ella. Veamos el segundo caso, imágenes a la izquierda.



Como vemos en este último gráfico el cálculo cambia y es más sencillo, pues para hallar la posición sólo hay que multiplicar lo que ocupa la imagen en posición cerrada por su índice. Hagámoslo.

Código :

//Primero creamos el bucle, vamos a hacer que comience en 1 pues la posición de la primera imagen será siempre 0 y no hay que calcularla ni que moverla, así que: for (i=1; i<totalImagenes; i++) {     }  //Ahora crearemos el condicional, si la variable i del bucle es inferior o igual a la posición de imagen seleccionada, le aplicaremos la primera fórmula de los ejemplos, si no lo es, aplicaremos la segunda. if (i <= num) {    //introducimos en el array el valor resultado de la fórmula. El valor índice de la fórmula será la i del bucle y el valor w será la variable cerrado    arr.push(cerrado*i); }  //Si la imagen está después de la seleccionada aplicaremos la segunda fórmula con la misma asociación de valores que acabamos de nombrar. else {    arr.push(anchoImagen+(cerrado*(i-1))) }  //Veámoslo completo: for (i=1; i<totalImagenes; i++) {    if (i <= num) {arr.push(cerrado*i)}    else {arr.push(anchoImagen+(cerrado*(i-1)))} }


Bueno bueno bueno, con esto ya tenemos toda la función OVER completa. Ahora por cada imagen superior a la primera me ha introducido en el array arr un valor. Como muestra ficticia, por ejemplo podría recibir un array que fuera así: [50, 100, 150]. Con esos 3 valores del array (3 será variable en función del número de imágenes cargadas) posteriormente le indicaremos a la función que se encarga de mover las imágenes a donde ha de mandar cada una. Ya crearemos la función al final, ahora vamos a ver la función OVER completa:

Código :

function /*OVER*/ () {             var num = $($(this).parent().find('.imagen')).index(this),       anchoTotal = $(this).parent().width(),       anchoImagen = $(this).width(),       totalImagenes = $($(this).parent().find('.imagen'))          .index($(this).parent().find('.imagen:last'))+1,       cerrado = (anchoTotal-anchoImagen)/(totalImagenes-1)       titulos = $(this).find('div:eq(2)'),       parp = $(this).find('.parpadeo'),       arr = [];           parp.fadeTo(0, 0.5).dequeue();    parp.fadeTo(500, 0).dequeue();    titulos.find('div:eq(1)').fadeTo(300,0).dequeue();    titulos.find('div:eq(2)').fadeTo(300,1).dequeue();    for (i=1; i<totalImagenes; i++) {       if (i <= num) {arr.push(cerrado*i)}       else {arr.push(anchoImagen+(cerrado*(i-1)))}    } }


Estupendo, ahora vamos a hacer la función out, tardaremos menos pues muchas de las cosas de esta función ya están explicadas con anterioridad. Primero tendremos que definir de nuevo el div títulos de la imagen, el ancho total, el total de imágenes, un nuevo array vacío para acumular las posiciones originales y ocultaremos el subtítulo a la par que mostramos el título. Vamos al lío:

Código :

function /*OUT*/ () {    var titulos = $(this).find('div:eq(2)'),       anchoTotal = $(this).parent().width(),       totalImagenes = $($(this).parent().find('.imagen'))          .index($(this).parent().find('.imagen:last'))+1,       posiciones = [];    titulos.find('div:eq(1)').fadeTo(300, 1).dequeue();    titulos.find('div:eq(2)').fadeTo(300, 0).dequeue(); }


Como todo esto ya está explicado hace un momentín, podemos pasar a la función que rellenará el array, en este caso es mucho más sencillo, pues sólo tiene que calcular las posiciones iniciales, con lo que con una sola fórmula y sin condiciones podemos calcular todas las posiciones. Esta fórmula también está más arriba explicada, en el gráfico del punto 3. Asignando datos y rellenando el contenedor. Vamos a crear el bucle.

Código :

for (i=1; i<totalImagenes; i++) {    posiciones.push((anchoTotal/totalImagenes)*i) }


Fiiiiiiiiiiiuuuunnnn!!!, ya hemos acabado la función out, y a toda leche, como dicen en mi pueblo. Veámosla.

Código :

function /*OUT*/ () {    var titulos = $(this).find('div:eq(2)'),       anchoTotal = $(this).parent().width(),       totalImagenes = $($(this).parent().find('.imagen'))          .index($(this).parent().find('.imagen:last'))+1,       posiciones = [];    titulos.find('div:eq(1)').fadeTo(300, 1).dequeue();    titulos.find('div:eq(2)').fadeTo(300, 0).dequeue();    for (i=1; i<totalImagenes; i++) {       posiciones.push((anchoTotal/totalImagenes)*i)    } }


OK, vamos a ver la función reiniciarListeners(), completa.

Código :

function reiniciarListeners () {    $('.imagen').unbind();        $('.imagen').click(function () {       var url = $(this).find('.links').html();             window.location.href = '#/'+url;    });     $('.imagen').hover(       function /*OVER*/ () {                   var num = $($(this).parent().find('.imagen')).index(this),             anchoTotal = $(this).parent().width(),             anchoImagen = $(this).width(),             totalImagenes = $($(this).parent().find('.imagen'))                .index($(this).parent().find('.imagen:last'))+1,             cerrado = (anchoTotal-anchoImagen)/(totalImagenes-1)             titulos = $(this).find('div:eq(2)'),             parp = $(this).find('.parpadeo'),             arr = [];          parp.fadeTo(0, 0.5).dequeue();          parp.fadeTo(500, 0).dequeue();          titulos.find('div:eq(1)').fadeTo(300,0).dequeue();          titulos.find('div:eq(2)').fadeTo(300,1).dequeue();          for (i=1; i<totalImagenes; i++) {             if (i <= num) {arr.push(cerrado*i)}             else {arr.push(anchoImagen+(cerrado*(i-1)))}          }       },       function /*OUT*/ () {          var titulos = $(this).find('div:eq(2)'),             anchoTotal = $(this).parent().width(),             totalImagenes = $($(this).parent().find('.imagen'))                .index($(this).parent().find('.imagen:last'))+1,             posiciones = [];          titulos.find('div:eq(1)').fadeTo(300, 1).dequeue();          titulos.find('div:eq(2)').fadeTo(300, 0).dequeue();          for (i=1; i<totalImagenes; i++) {             posiciones.push((anchoTotal/totalImagenes)*i)          }    });    }


5. La animación de las imágenes



Bien el último paso, ahora sólo tenemos que crear la ridícula función que lo moverá todo, venga, vamos a echarnos unas risas todos, Ja ja ja, vale... Continuemos. Pensemos la función, necesitamos una FUNCION que SELECCIONE VARIOS elementos del navegador y los REPOSICIONE en función a un ARRAY, estas palabra en mayúscula me suenan a: SELECCIONE (id o clase), VARIOS (bucle), REPOSICIONE (una funcion animate()), ARRAY (el array que obtengo de la función over o out).

Es importante saber que en este tutorial estoy asumiendo que cuando tenga varios sliders en pantalla tendré varios elementos con la misma id, bien como seleccionaré los objetos con un find() desde su padre no habrá problema ya que la id sólo se usará en estos casos, pero NUNCA, JAMÁS, es buena práctica asignar la misma id a más de un objeto. Dicho esto hagamos la función.

Código :

//Lo primero es hacer que la función reciba un array, que serán las posiciones y una id que será la id del slider objetivo. Y para empezar, generaremos la id del contenedor padre function reposicionar (posiciones, slider) {    var contenedor = '#'+slider; }  //Ahora crearemos el bucle que hará las animaciones, una por cada imagen (posiciones.length) excepto la primera que siempre estará en posición left: 0. De manera que comenzamos el bucle en 1 for (i=1; i<posiciones.length; i++) {              }  //Y por último generamos la id de la imagen, var objetivo = '#imagen'+i;  //La buscamos dentro del contenedor objetivo $(contenedor).find(objetivo)  //Y la animamos a la posición que indique el array, dado las posiciones del array empiezan en 0, y nosotros estamos haciendo el bucle desde 1, hay que restarle 1 a i, para establecernos en la posición correcta del array. .animate({left:posiciones[i-1]}, 200).dequeue()


Veámosla completa:

Código :

function reposicionar (posiciones, slider) {    var contenedor = '#'+slider;    for (i=1; i<posiciones.length; i++) {       var objetivo = '#imagen'+i;       $(contenedor).find(objetivo).animate({left:posiciones[i-1]}, 200).dequeue();    } }


¡¡¡PUES HEMOS TERMINADO!!! Ya sólo nos queda ponerlo todo junto y generar las llamadas a la última función desde las funciones OVER y OUT. Vamos a hacer esa llamada.

Código :

//Mudemos nuestros pensamientos al final de la función OVER, para ejecutar la función reposicionar que acabamos de configurar, sólo habría que obtener la id del slider contenedor, pues el array ya lo tendríamos relleno. Vamos a crear la llamada a la funcion, enviado en primer lugar el array y en segundo lugar pasaremos como contenedor el padre de la imagen con over //En el over reposicionar(arr, $(this).parent().attr('id'))  //En el out reposicionar(posiciones, $(this).parent().attr('id'))


6. Repaso breve del código desarrollado



Bien vamos a ver todo lo que hemos hecho juntito y de la mano, a partir de ahora sólo nos quedará generar una hoja de estilos css para el slider

Primero el objeto con los datos, recordad que esto podría ser el resultado de una consulta a una BBDD, un XML, un JSON... sólo habría que cambiar la manera de tratar los datos recibidos, ó convertir los datos recibidos en objetos como este y dejas el slider como está , lo mismo da, que da lo mismo.

Código :

losDatosDelSlider = {    'anchoImagen': 733,    'altoImagen': 350,    'anchoTotal': 930,    'alturaCajaTextos': 75,    'carpetaImagenes': 'imgb/',    'imagenes':[       {'url': '1.jpg', 'Link': '1.cristalab.com', 'tit': 'Uno', 'sub': '1'},       {'url': '2.jpg', 'Link': '2.cristalab.com', 'tit': 'Dos', 'sub': '2'},       {'url': '3.jpg', 'Link': '3.cristalab.com', 'tit': 'Tres', 'sub': '3'},       {'url': '4.jpg', 'Link': '4.cristalab.com', 'tit': 'Cuatro', 'sub': '4'}    ]    }


Ahora la llamada a la función crearSlider(), que genera el slider, le pasaremos el objeto y la id del contenedor del slider. Es imperativo que esta llamada siempre vaya dentro de una función $(document).ready(function () {}) para que se ejecute sólo cuando el DOM esté listo y así no obtengamos resultados indeseados. Las otras funciones pueden ir dentro o fuera.

Código :

crearSlider(losDatosDelSlider, '#contenedorSlider')


Vamos con la función crearSlider(), fijarse que al final he añadido la llamada a reiniciarListeners, por lo que cada vez que se cargue un slider se reiniciarán las escuchas.

Código :

function crearSlider(datos, contenedorSlider) {    var contenedor = $(contenedorSlider),       carpetaImagenes = datos.carpetaImagenes,       anchoImagen = datos.anchoImagen,       altoImagen = datos.altoImagen,       anchoTotal = datos.anchoTotal,       imagenes = datos.imagenes,       totalImagenes = imagenes.length,       boxNegro = datos.alturaCajaTextos,       anchoMedia = anchoTotal/totalImagenes;           contenedor.width(anchoTotal).height(altoImagen).addClass('bloqueDisplay');     for (indice in imagenes) {       contenedor          .append($('<div class="imagen sombraIzquierda"'+             'id="imagen'+indice+'"'+             'style="width:'+anchoImagen+'px;'+                'height:'+altoImagen+'px;'+                'left:'+(anchoMedia*indice)+'px;'+                'z-index:'+indice+';'+                'background: url('+carpetaImagenes+imagenes[indice].url+')" />')          .append($('<div class="links">').html(imagenes[indice].Link))          .append($('<div class="parpadeo" />').fadeTo(0, 0).dequeue())          .append($('<div class="cajaTextos" style="height:'+boxNegro+'px" />')             .append('<div class="fondoOscuro" />')             .append($('<div class="titular" />').html(imagenes[indice].tit))             .append($('<div class="subtitular" />').fadeTo(0, 0).dequeue()                .append($('<div class="titulo" />').html(imagenes[indice].tit))                .append('<br />'+imagenes[indice].subt)             )          )       )    }    reiniciarListeners() }


La llamada a reiniciarListeners(), que eliminará las escuchas y las volverá a crear cada vez que se instancie un slider, fijaos que ya tiene las llamadas a reposicionar() añadidas.

Código :

function reiniciarListeners () {    $('.imagen').unbind();        $('.imagen').click(function () {       var url = $(this).find('.links').html();             window.location.href = '#/'+url;    });     $('.imagen').hover(       function /*OVER*/ () {                   var num = $($(this).parent().find('.imagen')).index(this),             anchoTotal = $(this).parent().width(),             anchoImagen = $(this).width(),             totalImagenes = $($(this).parent().find('.imagen'))                .index($(this).parent().find('.imagen:last'))+1,             cerrado = (anchoTotal-anchoImagen)/(totalImagenes-1)             titulos = $(this).find('div:eq(2)'),             parp = $(this).find('.parpadeo'),             arr = [];                       parp.fadeTo(0, 0.5).dequeue();          parp.fadeTo(500, 0).dequeue();          titulos.find('div:eq(1)').fadeTo(300,0).dequeue();          titulos.find('div:eq(2)').fadeTo(300,1).dequeue();          for (i=1; i<totalImagenes; i++) {             if (i <= num) {arr.push(cerrado*i)}             else {arr.push(anchoImagen+(cerrado*(i-1)))}          }          reposicionar(arr, $(this).parent().attr('id'))       },       function /*OUT*/ () {          var titulos = $(this).find('div:eq(2)'),             anchoTotal = $(this).parent().width(),             totalImagenes = $($(this).parent().find('.imagen'))                .index($(this).parent().find('.imagen:last'))+1,             posiciones = [];          titulos.find('div:eq(1)').fadeTo(300, 1).dequeue();          titulos.find('div:eq(2)').fadeTo(300, 0).dequeue();          for (i=1; i<totalImagenes; i++) {             posiciones.push((anchoTotal/totalImagenes)*i)          }          reposicionar(posiciones, $(this).parent().attr('id'))    });    }


Y por último la función reposicionar que se encargará de los movimientos

Código :

function reposicionar (posiciones, slider) {    var contenedor = '#'+slider;    for (i=1; i<posiciones.length; i++) {       var objetivo = '#imagen'+i;       $(contenedor).find(objetivo).animate({left:posiciones[i-1]}, 200).dequeue();    } }


Espero que en este punto nos hayamos enterado bien de las cosas, porque ya no hay vuelta atrás! Bien, vamos a ver en el navegador qué es lo que hace ahora mismo la función, sin ningún estilo aplicado. El link a continuación ya está cargando 2 sliders Slider sin estilos


7. Aplicación de estilos


¡¡UHUUUUHUUUUUUU!!, esto ya es el fín. Vamos a estilizar el slider a base de css. Yo creo que lo más correcto, y por favor que alguien me corrija si me equivoco, es que el orden a seguir sea de abajo -> arriba, es decir, primero el contenedor principal, después la clase .imagen y después también por orden todo lo que contiene una div imagen. De manera que vamos con los estilos, no me voy a parar a explicarlos.

Código :

#contenedorSlider {    display: block;    overflow: hidden;    position: relative; }  .imagen {    position: absolute; } 


Veamos cómo con estos dos estilos ya parece el slider final Primeros estilos, bien continuemos con los estilos

Código :

#contenedorSlider, .parpadeo {    display: block; }  .imagen, .parpadeo, .subtitular, .titular, .cajaTextos, .fondoOscuro, .titulo {    position: absolute; }  .parpadeo, .fondoOscuro, .titular {    width: 100%;    height: 100%; }  #contenedorSlider {    overflow: hidden;    position: relative;    margin: auto;    top: 35px;    cursor: pointer;    border: 1px solid black; }  .sombraIzquierda {    box-shadow:   -8px -2px 16px #000;    -webkit-box-shadow:   -8px -2px 16px #000;    -moz-box-shadow:   -8px -2px 16px #000; }  .links {    display: none; }  .parpadeo {    background: white; }  .cajaTextos {    bottom: 0;    width: 100%;    border-top: 1px solid black; }  .cajaTextos * {    font-family: "Trebuchet MS", Arial;    font-size: 13px;    color: white;    text-transform: uppercase; }  .fondoOscuro {    background: #000;    opacity: 0.45;    filter: Alpha(opacity=45); }  .titular, .subtitular {    padding-left: 15px; }  .titular {    line-height: 50px; }  .subtitular {    line-height: 15px;    font-size: 45px; }  .titulo {    bottom: 0;    left: 41px; } 


Y con todos los estilos definidos, repasemos el resultado que hemos visto al principio. Sliders finales cargados.

Bueno espero que estéis contentos con el resultado y sobre todo que sea útil para alguien.

Un saludo a todos.

Enviar comentario

Corrección de errores de Rigging en Autodesk Maya

Posted: 06 Mar 2012 04:26 AM PST

Un paso imprescindible para trabajar cómodamente en 3D con nuestros sistemas de Rig de Autodesk Maya es aprender a corregir los errores, que por despiste o mala configuración, hayamos podido colocar en nuestros sistemas, para lo que trabajaremos sobre el conjunto generado el anterior día, resolviendo de forma correcta la posición de los manejadores de animación y ajustando las transformaciones, desconectando canales y reconectándolos posteriormente si fuera preciso.



Saludos.

Enviar comentario

Efectos de sonido en FL Studio

Posted: 09 Aug 2009 05:00 PM PDT

Hay muchos tipos de efectos de sonido en FL Studio (antiguo Fruity Loops). En este tutorial veremos los efectos de audio Delay, Reeverb, Flanger, Phaser, Chorus, Compressor, Clipper, Fast Distortion y Vocoder.