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:
[js]canvas.width = canvas.width;[/js]
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
[html]<canvas style="background: #fff;"></canvas>[/html]
[js]function clear(ctx) {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}[/js]
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.
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:
Creamos un elemento canvas y comprobamos si cuenta con el método getContext
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");
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.
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:
canvas-event: un framework para interactuar con el canvas.
conceptmapp: una herramienta para crear mapas conceptuales
Ya llevo tiempo sin escribir, y es que en estos días han pasado muchas. Ahora que tengo tiempo libre (ya que estoy desempleado) me puse en la tarea de crear un juego en javascript y HTML5: jsaw5.
En jsaw5 podrán crear, resolver y compartir rompecabezas personalizados con amigos en twitter y facebook. Espero que lo visiten y den sus opiniones, aun debe tener varios errores pero si esperaba a que fuera “perfecto”
En el proceso de creación agregue algunas mejoras a canvas-event-js las cuales espero hacer disponibles en cuanto pueda.
Usando el método find, es posible seleccionar un grupo de objetos y aplicarles un método o manejador de evento. para esto debemos usar un selector como:
tipo: Corresponde con el nombre del método usado para crear el objeto (circle, rect, line…).
id: Un nombre que podemos dar a un objeto con el fin de diferenciarlo de otros del mismo tipo.
Imagine estar creando un buscaminas, el campo esta lleno con varios rectángulos: unos son minas y otros no. Todos los rectángulos tienen el mismo color, pero solo los rectángulos mina explotan y terminan el juego, mientras los demás aumentan el puntaje del jugador.
Nota Al igual que en css, el símbolo # indica que mina y safe son id.
for (var i = 0; i < 5; i++) { ce.rect(i*10, 0, 10).setId("mina"); }
for (var i = 0; i < 5; i++) { ce.rect(i*10; 10; 10).setId("safe"); }
// selector tipo: todos los rectángulos, tanto #mina como #safe ce.find("rect").attr("fill", "gray");
Uno de los elementos HTML5 que sin duda ofrece mayores posibilidades es el elemento canvas, gracias a este es posible crear y manipular imágenes directamente en el navegador, pero a la hora de crear algo mas que imágenes estáticas nos tropezamos con la falta de métodos para el manejo de eventos, aun así encontramos aplicaciones web que permiten la interacción por medio del teclado y el ratón.
¿Como logran esta interacción?, si vemos en el código de estas aplicaciones, todas siguen mas o menos el mismo patrón:
Agregar evento mousemove al elemento canvas
comparar coordenadas del cursor con las de Objetos dibujados
Seleccionar objeto sobre el cual se encuentra el cursor
Al ocurrir un evento, ejecutarlo sobre el Objeto seleccionado
Redibujar el canvas
No es algo difícil, pero podría ser mucho mas fácil.
Con esto en mente y luego de robar algunas ideas y algo de código de otros proyectos como procesingjs, jQuery, jquery-hotkeys y canto-js, nació canvas-event, una librería que se encarga del manejo de los eventos, facilitando el desarrollo de aplicaciones interactivas en el elemento canvas; ademas cuenta con objetos predefinidos como círculos, rectángulos, rutas e imágenes entre otros.
Algunos ejemplos de lo que se puede hacer con canvas-event:
// identificadores de Objetos Cv.image(50, 100, "ball.gif").addId("pelota").rect(100, 50, 20).draw();
// Recuperar elementos por su Id o tipo; Cv.find('#pelota').attr("alpha", .5).redraw();
Cv.find('rect').click(function(){ alert( "Hola, soy un rectangulo" ); });
// Eventos live Cv.mouseover( "#pelota", function(e){ alert( "Soy una pelota" ); });
// Este Objeto también tendrá el evento anterior Cv.circle(175, 75, 20).addId('pelota');
Ademas, podemos definir nuestras propias figuras extendiendo el objeto Shape:
var Triangle = Cevent.Shape.extend({ // inicializador init: function( x, y, size ){ this.size = size || 5; this._super( x, y ); },
// ctx es el context en el que se debe dibujar draw: function( ctx ) {
ctx.save();
// aplicamos estilo y trasformaciones this.applyStyle( ctx ); this.setTransform( ctx );
// definimos el contexto en el cual dibujaremos // para poder usar todos los métodos svg definidos en Cevent // como M (move) c (cubicBlazier) etc Cevent.beginPath( ctx ) .M( this.x, this.y ) .h( 1 * this.size ) .v( 1 * this.size ) .z();
if ( this.fill ) { ctx.fill(); }
if ( this.stroke ) { ctx.stroke(); }
ctx.restore(); } });
// registramos el nuevo objeto Cevent.registre( "triangle", Triangle );
// ahora podemos hacer uso del nuevo objeto var Cv = Cevent( "canvas-id" );
Por el momento falta documentación pero se incluyen varios ejemplos de su uso, si tienen alguna duda y/o sugerencia por favor déjenla en los comentarios o en la pagina del proyecto en google code.
Aun cuando los navegadores modernos soportan el nuevo atributo placeholder (firefox 3.7+, safari 4.0+, chrome 4.0+), debemos seguir usando javascript para navegadores mas antiguos; por esto decidí buscar algún plugin para jQuery que me facilitara el trabajo, pero muy pocos soportaban inputs tipo password y los que lo hacían tenían comportamientos extraños en IE (como raro no creen), así que tome el mejor que encontré y le hice algunas modificaciones.