Category: javascript

  • Dividir correctamente un string en caracteres. No con string.split(“”)

    Dividir correctamente un string en caracteres. No con string.split(“”)

    Dividir un string en caracteres parece una tarea sencilla, y lo es. mientras un carácter sea solo un carácter.

    Como así?

    En unicode existen caracteres que se combinan con otros, ejemplo de estos son los caracteres de acento. De esta forma a simple vista un carácter puede parecer un solo símbolo pero estar formado por dos o mas.

    Por ejemplo la letra “a” con tilde puede ser un solo carácter (u+00e1), pero puede darse el caso que sea una letra a + una tilde (a+’) que son dos caracteres (u+0061 y u+0301 respectivamente).

    Esto es un problema, en especial para una aplicación que necesite acceder a cada uno de los caracteres de una palabra como en los crucigramas, ahorcado, sopas de letras, etc.

    Por ejemplo en mi juego de sopa de letras a veces las palabras en la cuadricula quedaban en la posición incorrecta. El problema, algunas palabras usaban mas espacio debido a los caracteres de combinación (eje. “mamá” ocupando 5 cuadros = m | a | m | a | ‘ |).

    Que puede salir mal

    Para conocer el largo de una cadena de texto normalmente usamos la propiedad length… error, ésta solo da resultados correctos si cada carácter en el texto esta formado por un solo codepoint.

    alert("mamá".length)

    Gracias a un enlace en MDN (Mozilla Developer Network) encontre esta solución.  para obtener el largo correcto del string contamos los caracteres que no son marcas de combinación. a continuación la función (con algunas modificaciones).

    // regexp = rangos de caracteres correspondientes a marcas de combinación
    rCombiningMarks = /[u0300-u036Fu1DC0-u1DFFu20D0-u20FFuFE20-uFE2Fu0483-u0489u0591-u05BD]/g;

    function stringLength(string) {
    // iniciar un contador de caracteres en 0
    var length = 0;

    // por cada caracter en string
    for (var i = 0, l = string.length; i < l; i++) {
    // si no es una marca de combinación
    if (! rCombiningMarks.test(string.charAt(i)) )
    // incrementar el contador de caracteres
    length += 1
    }

    return length;
    }

    Probamos nuestra función.

    alert(stringLength("mamá"));

    Como dividir un string?

    Podemos usar un método similar al anterior para dividir un string:
    // regexp = rangos de caracteres correspondientes a marcas de combinación
    rCombiningMarks = /[u0300-u036Fu1DC0-u1DFFu20D0-u20FFuFE20-uFE2Fu0483-u0489u0591-u05BD]/g;

    function splitString(string) {
    // iniciar un array de caracteres
    var chars = [],
    lastChar;

    // por cada caracter en string
    for (var i = 0, l = string.length; i < l; i++) {
    // si no es una marca de cominación
    if (! rCombiningMarks.test(string.charAt(i)) ) {
    // Agregar al array de caracteres
    chars.push(string.charAt(i));
    }
    // de lo contrario
    else {
    // Concatenar con ultimo caracter en el array
    var lastChar = chars[chars.length - 1];
    chars[chars.length - 1] = lastChar + string.charAt(i);
    }
    }

    return chars;
    }

    // TEST
    alert("con string.split: "+("mamá".split("").join(" | ")));
    alert("con splitString: " + splitString("mama").join(" | "));

    Conclusión

    Aun cuando javascript nos provee varios métodos útiles para el manejo de strings, números, arrays y objetos, estos no siempre nos darán los resultados deseados. debemos probar nuestro código para estar seguros que se comporta de la forma correcta.

    Algún otro método/función nativa de javascript de la que no hay que confiar. Déjalo en los comentarios.

  • Canvas desde cero: primeros pasos

    Canvas desde cero: primeros pasos

    El elemento canvas es una gran herramienta para crear juego, animaciones y manipular imágenes, aun así no todos los navegadores soportan esta etiqueta, por tanto, es necesario contar con alternativas para no dejar de lado a los usuarios de dichos navegadores.

    En esta primera parte veremos dos de estas alternativas así como algunas particularidades de la etiqueta canvas.

    Compatibilidad

    En la actualidad los únicos navegador que no cuentan con soporte para el elemento canvas son Internet Explorer 6, 7 y 8; no obstante existen soluciones (polyfills) que emulan su funcionalidad, entre los que se destacan:

    • excanvas: utiliza VML, una tecnología propietaria de Microsoft similar al svg y no necesita de plugins, pero carece de algunos métodos (getImageData, toDataURL…).
    • flashcanvas: utiliza flash (duh), es mas rápido que excanvas (a mi parecer) y soporta mas características, pero hay que comprar una licencia para poder desarrollar aplicaciones de comerciales.

    La etiqueta canvas

    El elemento canvas cuenta con una etiqueta de apertura y una de cierre, pero a diferencia de otras etiquetas, su contenido solo es visible en navegadores antiguos (ya que estos ignoran las etiquetas desconocidas) lo cual nos permite mostrar un contenido alternativo a los usuarios de dichos navegadores.

    <canvas height="150" id="canvas" width="300">
    <!-- contenido a mostrar si el navegador no soporta canvas -->
    <img src="/images/imagen-estatica.jpg" />
    </canvas>

    Otro hecho a destacar es que sus medidas se declaran mediante los atributos width/height y no a través css. al usar css se escala el elemento, así, si el canvas mide 300×150 y cambiamos sus medidas por 600×300 los pixeles “medirán el doble” y la imagen se verá borrosa.

    Por ejemplo, los siguientes cuadros se dibujaron en la mismas posición (10, 10) y tienen las mismas medidas (30×30) pero el canvas de la derecha fue escalado 6x usando css.

    Note el borde borroso el la segunda imagen 

    Detectar soporte

    Antes de empezar a usar el canvas necesitamos saber si el navegador siquiera soporta dicho elemento, para esto:

    1. Creamos un elemento canvas y comprobamos si cuenta con el método getContext
    2. De lo contrario verificamos que exista un Polyfill
    if (! document.createElement("canvas").getContext || ! window.G_vmlCanvasManager )
    alert("Actualize su navegador");

    Accediendo desde javascript

    Para poder acceder al elemento desde javascript hay esperar que el DOM este listo, para esto puedes utilizar la función ready de jQuery o colocar el script justo antes de </body>.

    A continuación obtenemos una referencia al contexto de dibujo del canvas utilizando el método getContext:

    var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d");

    Ahora si podemos empezar a dibujar:

    ctx.fillStyle = "red";
    ctx.fillRect(50, 50, 30, 20);

    Utiliza un navegador moderno para poder ver el ejemplo

    TIPS

    Antes de poder acceder al contexto del canvas en IE<9 (usando excanvas/FlashCanvas) debemos inicializarlo, para esto, en lugar de usar el método getContext podemos usar la siguiente función:

    function getContext(canvas) {
    if (! canvas.getContext && window.GV_ContextCanvas) {
    G_vmlCanvasManager.init(canvas);
    } else {
    throw new Error("El navegador no soporta el elemento canvas");
    }

    return canvas.getContext("2d");
    }

    Conclusión

    Finalizando esta primera parte tenemos todo listo para empezar a trabajar con el canvas. con suerte ahora podrás mostrar contenido alternativo para usuarios con navegadores antiguos, detectar el soporte del elemento canvas ya sea de forma nativa o mediante un polyfill y obtener el contexto de dibujo.

    No te pierdas la siguiente parte en la que veremos el sistema de coordenadas y como dibujar formas básicas.

    Si te gusto el tutorias compartelo en twitter o subscribete y te avisare cuando esté disponible la siguiente parte.

  • Canvas desde cero

    Canvas desde cero

    Si llevas tiempo con ganas de aprender a usar el canvas o quieres refrescar tus conocimientos,
    no puedes perderte esta serie de tutoriales que arranca el día de hoy, donde no solo se explicara
    como usar x función sino que desarrollaremos programas reales donde podrás aplicar lo aprendido.

    y quien es usted para decirme que hacer

    Soy un tipo al que le gusta la programación, en especial todo lo relacionado con la web (javascript *¬*)
    y desde que conocí el elemento canvas quede fascinado con la idea de poder dibujar en navegador.
    si bien no soy un experto y aun sigo aprendiendo, ya llevo tiempo trabajando con este elemento
    y he aprendido mucho gracias a la comunidad y esta es mi forma de contribuir en algo.
    algunos de los trabajos que he hecho:

    P.D.: Si ven que me estoy colgando en la actualización del blog no duden en jalarme las orejas en twitter XD.

  • Rehacer – Deshacer en javascript

    Rehacer – Deshacer en javascript

    En este tutorial intentaré explicar la forma de implementar la funcionalidad de deshacer y rehacer, una característica muy usada en los programas de escritorio y que muchas aplicaciones web no tienen (y hace mucha falta ya que errar es de humanos).
    Descargar código
    La idea consiste en tener objetos que representen las acciones (mover, eliminar, resaltar…), los cuales deben guardar el estado anterior del objeto afectado.

    ChangeColorCommand = function(obj, color) {
    
    this.obj = obj;
    this.new_color = color;

    // guardar estado anterior
    this.prev_color = obj.style.backgroundColor;
    }

    ChangeColorCommand.prototype.execute = function() {
    this.obj.style.backgroundColor = this.new_color;
    }

    ChangeColorCommand.prototype.undo = function() {
    this.obj.style.backgroundColor = this.prev_color;
    }

    Cada objeto cuenta con dos métodos

    • execute: ejecuta la acción (dah)
    • undo: deshace la acción valiéndose de los datos guardados previamente en el constructor.

    Las acciones son administradas por un objeto que mantiene dos pilas de acciones: las que se pueden deshacer y las que se pueden rehacer:

    • cuando ejecuta una acción, la guarda en undo_stack y borra toda acción que se podía rehacer
    • cuando se deshace algo, saca el ultimo objeto de la pila undo_stack, ejecuta el método undo y guarda la acción en la pila redo_stack.
    CommandManager = function(max_undo) {
    
    // máxima cantidad de acciones guardadas
    max_undo = max_undo || 30;

    // pilas de acciones
    this.undo_stack = [];
    this.redo_stack = [];

    // ejecutar comando cmd
    this.executeCommand = function(cmd){
    cmd.execute();

    // si se sobrepasa cantidad de acciones
    // eliminar primer elemento
    if (this.undo_stack.length &amp;gt;= max_undo) {
    this.undo_stack.shift();
    }
    this.undo_stack.push(cmd);
    this.redo_stack = [];
    }

    // deshacer acción
    this.undoCommand = function() {
    var cmd = this.undo_stack.pop();

    // si existe acción
    if ( cmd ) {
    cmd.undo();
    this.redo_stack.push(cmd);
    }
    }
    }

    Para realizar una acción creamos una instancia del objeto apropiado y la pasamos al CommandManager (previamente creado).

    var UndoRedo = new CommandManager(),
    
    box = document.getElementById("box");

    // cambiar color a rojo
    UndoRedo.executeCommand(new ChangeColorCommand(box, "red"));

    // cambiar color a verde
    UndoRedo.executeCommand(new ChangeColorCommand(box, "green"));

    // cambiar de verde a rojo
    UndoRedo.undoCommand();

    // cambiar de rojo a blanco
    UndoRedo.undoCommand();

    Ahora solo resta crear mas acciones (mover, negrita, itálica…) dependiendo de la aplicación que estemos desarrollando.

    Eso es todo, espero les haya servido; si tienen alguna duda o critica no duden en dejarla en los comentarios.

  • Beta 2 de canvas-event disponible

    Ya esta disponible la beta 2 de canvas-event, esta revisión cuenta con algunas mejoras y corrección de errores como:

    1. Posibilidad de adicionar una función a varios eventos simultáneamente
    2. Las figuras dibujadas dentro de un manejador de eventos ahora si se visualizan
    3. Los Objetos Line ahora también pueden ser arrastrados
    4. Los bordes redondeados ahora también funcionan en Opera
    Espero que les sea tan útil como lo ha sido para mi.