viernes, 14 de febrero de 2014

Tablet nueva, juegos rotos.

Hace pocos días llego por fin mi tableta (una gallaxy tab 2) y como podrán imaginar lo primero que hice fue probar los juegos que he desarrollado y para mi sorpresa varios de ellos no funcionaban correctamente; en algunos se veía un segundo canvas con la misma imagen y en otros el contenido previo no se borraba. Al parecer es un problema ya viejo con clearRect que afecta a android 4.1.

Lo primero que se me ocurrió para solucionar el problema fue el viejo truco de re-definir el tamaño del canvas:
canvas.width = canvas.width;
Ahora si que funcionaban, pero algunas acciones como el arrastrar eran realmente lentas (especialmente al arrastrar y soltar); el problema con este método es que ademas de borrar el contenido del canvas, también restablece su estado (fillStyle, clearStyle, scale, translate, shadowColor....) lo que al parecer influye en el rendimiento (al menos en el gallaxy tab - único dispositivo que tengo para hacer pruebas).

Otra de las soluciones sugeridas para eliminar el problema del canvas duplicado que encontré era el quitar el estilo overflow: hidden de todos los elementos padres del canvas, aunque el problema desapareció al igual que en el método anterior el rendimiento era pésimo.

Solución

Hasta el momento la solución con los mejores resultados es la de usar un color solido como fondo para el canvas y al momento de borrar el contenido usar fillRect en lugar de clearRect
<canvas style="background: #fff;"></canvas>
function clear(ctx) {
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
El aumento en rendimiento es considerable, sobre todo en juegos que requieren arrastrar y soltar (como el solitario). Aun así esta no es una solución definitiva ya que al usar un color solido no es posible apilar canvas para crear capas.

¿Conoces alguna mejor solución? déjala en los comentarios.

jueves, 5 de diciembre de 2013

Easy QR Code: Mi primera extensión para chrome


tltr: Hice una extensión para chrome que genera códigos QR con tan solo dos clics (descarguen aquí). Si les gusta compartan/comenten en twitter/facebook (quiero ser famoso *¬*).

Los códigos QR son una forma de almacenar información en un código de barras en dos dimensiones, y son una muy buena forma de copiar enlaces y texto a nuestros dispositivos móviles en lugar de tener que copiarlos a mano.

En la tienda de extensiones de chrome no encontré ninguna que cumpliera mis necesidades (rápido y simple de usar), mucha de las "extensiones" son simples enlaces a paginas y requieren muchos pasos:
  1. Copiar texto/enlace
  2. Clic para abrir la "Extensión"
  3. Pegar texto en un formulario
  4. Clic para generar el código
Demasiado extenuante para un simple código, en mi extensión ideal solo se necesita:
  1. Clic derecho sobre texto/enlace
  2. Seleccionar generar código
Listo. adicionalmente el código debe generarse rápidamente. con estas especificaciones y armado con una librería para generar códigos QR y la documentación del API de extensiones de chrome y dos cojones nació mi primera extensión para google chrome: Easy QR Code.

A continuación el enlace a la extensión y un corto vídeo de su funcionamiento.


jueves, 17 de octubre de 2013

Mi obsesión con el anime


Los que me conocen saben que estoy interesado en una variedad de cosas, pero suelo distraerme con facilidad, y lo que mas me distrae (o ¿en lo que mas me concentro?) es el anime.

De tiempo en tiempo me engancho tanto con alguna serie que termino buscando de todo sobre ésta: Fondos de pantalla, openings/endings, AMV, posters motivacionales (tengo alrededor de 20.000 en mi pc) y noticias entre otros. El problema es que no se de ningún sitio que contenga todo este material, todo lo recolecto de diferentes lugares como foros, youtube, google images... y esto me quita mucho tiempo.

Alguien dirá que la solución es muy simple: que deje de buscar pendejadas y me ponga a trabajar. Pero el anime es una forma de distraerme del día a día, ademas el contenido de estos (historia/humor/personajes...) es mucho mas rico que el de muchas películas y programas de televisión, incluso hay algunos que dejan enseñanzas sobre la vida y esas cosas u_u.

Si saben de algún un sitio donde se pueda encontrar este contenido concentrado, con animes/manga clasificados por géneros (gore, echi, shounen...) Dejen el link en los comentarios.

miércoles, 16 de octubre de 2013

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-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F\u0483-\u0489\u0591-\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-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F\u0483-\u0489\u0591-\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.




martes, 3 de septiembre de 2013

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 300x150 y cambiamos sus medidas por 600x300 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 (30x30) 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.




viernes, 23 de agosto de 2013

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.




jueves, 26 de abril de 2012

Creando un blog con django - parte 4

Después de una eternidad sin escribir y casi abandonar el tema de django, hoy por fin retomo el asunto. Hasta el momento tenemos los post clasificado por tags, pero un blog sin comentarios no es nada, así que hoy veremos como crear el formulario de comentarios.

En django existen dos formas de crear un formulario, una es crear cada campo manualmente y la otra es crearlos automáticamente basados en el modelo de datos.

Ya que casi siempre los formulario se usan para agregar/editar una tabla en una BD, y los campos del formulario reflejan los campos de la tabla, seria un desperdicio de tiempo crearlos manualmente.

Dejemos de hablar y empecemos a escribir código, editemos el archivo forms.py en el directorio de nuestra aplicación:
from django.forms import ModelForm #1
from blog.models import Comment #2

class CommentForm(ModelForm): #3
    """Formulario de comentarios"""
    class Meta: #4
        model = Comment #5
        exclude = ("post","deleted") #6

Hora de explicar lo que hemos hecho:
  1. Importamos ModelForm, la base para los formularios basados en modelos de datos.
  2. Importamos el modelo para el que se creará el formulario
  3. Creamos una subclase de ModelForm.
  4. En la clase Meta especificamos como crear el formulario
  5. model: modelo en el que se basa el formulario.
  6. exclude: campos a excluir, en este ejemplo post lo asignamos según el articulo desde el que se envió el comentario y deleted lo decidimos en la pagina de administración si es un comentario insultante. Si son muchos los campos a excluir podemos hacer lo contrario y especificar los que se deben incluir.
    Ahora podemos incluir el formulario en la vista single:
    # Archivo views.py
    from blog.models import Post, Tag, Comment
    from blog.forms import CommentForm
    ...
    # la función recibe el numero capturado
    def single(request, id=0):
        # recuperar post según id
        post = Post.objects.get(id=int(id))
        # Crear formulario
        form = CommentForm()
    
        return render_to_response("single.html", locals())
    
    Para crear el formulario se instancia el objeto adecuado y en la vista se usa esta instancia para mostrar el formulario:
    {# plantilla single.html #}
    {% extends 'base.html' %}
    
    {% block main_content %}
        {% include 'include/article.html' %}
        {# necesitamos crear el tag form #}
        &lt;form action="" method="form"&gt;
            {{ form }}
        &lt;/form&gt;
    {% endblock %}
    
    Con esto veremos el formulario en nuestro blog, lo llenamos y enviamos...
    Wow un error. Django requiere que incluyamos protección contra ataques csrf, este tipo de ataque permite que alguien engañe a un usuario registrado para enviar datos a nuestro sitio usando un formulario en otra pagina web. Afortunadamente django tiene todo lo necesario para protegernos con unas cuantas lineas de código.
    # Archivo views.py
    from blog.models import Post, Tag, Comment
    from blog.forms import CommentForm
    # importamos el decorador
    from django.views.decorators.csrf import csrf_protect
    # importamos render
    from django.shortcuts import render
    
    ...
    # aplicamos el decorador función que recibe datos de formulario
    @csrf_protect
    def single(request, id=0):
        # recuperar post según id
        post = Post.objects.get(id=int(id))
        form = CommentForm()
        
        # usamos render en lugar de render_to_response
        return render(request, "single.html", locals())
    
    Ahora incluimos el tag {% csrf_token %} dentro del formulario en la plantilla single.html. Esto crea un elemento input oculto con un token único que se verifica al enviar datos al servidor, si este no coincide, se produce un error 403 (prohibido) y tenemos una app algo mas segura.

    Ok, ya podemos enviar datos del formulario al servidor, hora debemos validarlos y guardarlos en la BD.
    # Archivo views.py
    @csrf_protect
    def single(request, id=0):
        # recuperar post según id
        post = Post.objects.get(id=int(id))
        # recuperar comentarios de este post
        comments = Comment.objects.filter(post=post)
    
        # Si la petición es POST es porque enviaron el formulario
        if request.method == "POST":
            # Creamos una instancia del modelo Comment asignado el post actual
            comment = Comment(post=post)
            # Creamos una instancia del formulario con los datos recibidos
            form = CommentForm(request.POST, instance=comment)
            
            # Validamos los datos
            if form.is_valid():
                # Guardamos el comentario en la BD
                form.save()
                # Enviamos al usuario de nuevo al post
                return HttpResponseRedirect("/post/{0}".format(slug))
        
        # De lo contrario creamos un formulario vacío
        else:
            form = CommentForm()
        
        return render(request, "single.html", locals())
    
    Podemos notar algunas cosas:
    1. Validamos el formulario con el método is_valid que no definimos. ¿como es esto posible?; Al crear el modelo Comment especificamos el tipo de datos admitidos, el formulario "sabe" que si esto datos no corresponden, el formulario contiene errores.
    2. Para guardar los datos usamos form.save y no comment.save. Esto se debe a que hay datos que no están incluidos en el formulario (post) pero si en la instancia comment y viceversa, por esto pasamos comment al formulario en el momento de crearlo.
    Solo resta mostrar los comentarios, editamos la plantilla single.html:
    {# plantilla single.html #}
    {% extends 'base.html' %}
    
    {% block main_content %}
        {% include 'include/article.html' %}
        {% for comment in comments %}
          &lt;div class="comment"&gt;
              &lt;div class="user"&gt;{{ comment.name }} dijo:&lt;/div&gt;
              &lt;div class="body"&gt;{{ comment.body }}&lt;/div&gt;
              &lt;small&gt;{{ comment.date|date:"d-m-Y" }}&lt;/small&gt;
          &lt;/div&gt;
        {% endfor %}
        {# necesitamos crear el tag form #}
        &lt;form action="" method="form"&gt;
            {{ form }}
        &lt;/form&gt;
    {% endblock %}
    
    Con esto solo falta crear el sitio de administración para agregar post y moderar los comentarios y tendremos un blog terminado. Estén pendientes por la ultima parte de esta serie que seguro saldrá antes que se acabe el mundo este 21 de diciembre XD.
     
    © 2009 NovatoZ. All Rights Reserved | Powered by Blogger
    Design by psdvibe | Bloggerized By LawnyDesignz