HTML5 y Bases de Datos locales

octubre 16, 2010

Otra de las grandes novedades de HTML5 es las nuevas alternativas respecto a la forma de guardar información en el cliente por parte de una web. Hasta ahora, la única alternativa que se tenia desde una web era usar cookies. HTML5 introduce tres nuevas formas, “local” y “session” storage y por otro lado la posibilidad de manejar toda una base de datos relacional que reside en cada cliente. A diferencia del localstorage o sessionstorage, que son mas similares a las cookies, el hecho de manejar una base de datos totalmente funcional es una novedad bastante importante que puede ayudar a nuestras webs a guardar información de una forma mucho mas estructurada.

Como hemos dicho, la base de datos es de tipo relacional, por lo que el lenguaje para “hablar” con ella será enteramente SQL.

Aunque expresamente la W3 desaconseja ligar el estándar a una implementación concreta, en la practica, prácticamente la totalidad de navegadores han usado SQL lite para implementar la gestión de la base de datos.

Como sabemos, no el SQL que entiende todas las bases de datos es igual, existen lo que se denominan “dialectos”, debido a que SQL lite es casi la opción “de-facto” podremos usar el “dialecto” del SQL lite en las sentencias. Aunque, al igual que el estándar desaconsejaba ligarse a una implementación, no es buena idea ligar el código a un dialecto, pues puede ser que en algún momento uno de los navegadores decida utilizar otro “backend” de bases de datos, y haga nuestro código incompatible. Lo ideal es usar, en la medida de lo posible, el SQL mas cercano al estándar.

Pese a todo esto, de momento y hasta que no se plantee una implementación independiente, el estándar de HTML5 respecto al “WebSQL” apunta a que el dialecto a seguir es del SQL lite.

Pasando ya a como usar la base de datos desde javascript, el primer paso es obtener una referencia a la base de datos para poder operar con ella. Para ello usaremos la función openDatabase() donde le pasaremos, el nombre de la base de datos, la versión del esquema y el tamaño estimado.

Una vez tenemos la referencia de la base de datos, vamos a ver que, prácticamente la totalidad de los métodos son asíncronos, por lo que típicamente los argumentos serán callbacks. En este caso Javascript sale a nuestra ayuda, como seguramente sabremos, en Javascript podemos encapsular en una variable la declaración de una función, por lo que la forma mas común de pasar los parámetros a las funciones que operan en la base de datos es incluir la declaración de los propios callbacks, ya que habitualmente, no será muy útil reutilizar dichos callbacks.

Las dos funciones más usadas sin duda van a ser “transaction” y “executeSql”, con la primera crearemos una transacción que se ejecutará contra la base de datos de forma atómica (bueno, esa es la definición de transacción, no?), mientras que con la segunda, como su nombre indica ejecutaremos las propias sentencias sql.

A continuación veremos un simple ejemplo en el que creamos una base de datos de usuarios en el cliente, donde guardamos cosas como su nombre de usuario o password.

<html>
<head>
<script type="text/javascript">
    var db;
    function init() {
        db = openDatabase("DB Prueba", "0.1", "Database Prueba", 200000);
        if (db) {
            // Database opened
			db.transaction( function(tx) {
				tx.executeSql("CREATE TABLE IF NOT EXISTS usuarios(userid integer primary key autoincrement, username text, password text)")
			});
        }

		listUsers();

    }

	function showUsers(users) {
		var place = document.getElementById("usersDiv");
		if (place.getElementsByTagName("ul").length > 0 )
			place.removeChild(place.getElementsByTagName("ul")[0]);
		var list = document.createElement("ul");

		for ( var i = 0; i < users.length; i++) {
			var item = document.createElement("li");
			item.innerHTML += "<b>userId:</b>" + users[i][0] + " <b>userName:</b>"
					+ users[i][1] + " <b>password:</b>" + users[i][2] +
					"<button onclick='removeUser("+ users[i][0]+")'>Remove</button>";
			list.appendChild(item);
		}
		place.appendChild(list);
	}

	function listUsers() {
		db.transaction( function(tx) {
			tx.executeSql("SELECT * FROM usuarios", [],
				function(tx, result){
					var output = [];
					for(var i=0; i < result.rows.length; i++) {
						output.push([result.rows.item(i)['userid'],
								result.rows.item(i)['username'],
								result.rows.item(i)['password']]);
					}

					showUsers(output);

				});
		});
	}

	function addUser(username, password) {
		db.transaction( function(tx) {
			tx.executeSql("INSERT INTO usuarios(username, password) VALUES(?,?)", [username, password]);
		});
		listUsers();
	}

	function removeUser(userId) {
		db.transaction(function(tx) {
			tx.executeSql("DELETE FROM usuarios WHERE userId=?",[userId], listUsers);
		})
	}
</script>
</head>
<body onload="init()">
<div id="usersDiv">
	Usuarios en local
</div>
<div id="newuser">
	Crear nuevo usuario<br/>
	Usuario: <input type="text" id="username"/><br/>
	Password: <input type="password" id="password"/><br/>
	<button onclick="addUser(username.value, password.value)">Add User</button>
</div>
</body>

</html>

Desde luego es una gozada que sea tan sencillo trabajar con una base de datos de una forma tan sencilla 🙂

Además, tenemos que sumarle la gran calidad de las herramientas de depuración que nos aportan los navegadores, en la captura que encabeza la entrada podemos ver la que tiene Safari. Si somos usuarios de chrome veremos que la ventana es idéntica, esto es por que Chrome al igual que Safari se basa en webkit.

Después de leer el post, podemos sacar la conclusión de que es muy sencillo operar con bases de datos en cliente, y es totalmente cierto, pero ahora hay que pensar bien cuando esta opción es la mejor y cuando los datos solo se guardan en el servidor.


Juego de la Vida en un canvas de HTML5

septiembre 13, 2010

Poco a poco HTML5 va tomando forma, lo que hace un tiempo era poco mas que un proyecto de estandar, hoy en día ya es una realidad en la mayoría de los navegadores.

Si usamos Safari, Firefox o Chrome ya somos capaces de disfrutar de la mayoría de las ventajas que el nuevo estandar nos propone.

Una de las grandes mejoras es la habilidad para ponder “pintar” en una zona especialmente diseñada para ello. Dicha zona se conoce como “canvas” y vamos a poder utilizarla como si de cualquier otro contexto gráfico se tratara.

Seguramente pensareis que esto no es tan gran novedad, esto ya se podia hacer antes con cosas como Flash o Applets de Java, pero el canvas de HTML5 va un paso mas adelante.

Sin duda la principal novedad de dicho canvas no es tanto el que nos permita dibujar en el navegador sino que es que es propio navegador quien decide como tratar esa zona. A diferencia de la aproximación de flash o java donde era necesario un plugin en comunicación con el navegador.

Este cambio supone un salto drástico en el rendimiento de este tipo de aplicaciones. Seguro que si habéis usado flash o applets java os habréis dado cuenta lo exigente que era para las cosas que mostraban por pantalla. Sin embargo, con el canvas y una buena implementación por parte del navegador, no solo este rendimiento será mejor, sino que además podremos usar cosas como la acceleración nativa 3D.

Además, la ausencia de la necesidad de plugins facilita enormemente la labor de porting a otras plataformas, si el navegador soporta HTML5, no se necesitará nada mas.

Y para terminar con las ventajas, estamos hablando de un estándar, libre de patentes, no controlado por ninguna empresa y con los requerimientos totalmente abiertos. Cualquiera puede implementar un navegador HTML5 sin tener que pagar nada a nadie.

Se me nota entusiasmado, ¿no? :). Creo que es para estarlo, pues la web es uno de los medios de comunicacion mas importante hoy en día, y el hecho de estandarizar algo tan común en la web como son estas aplicaciones es para estar de enhorabuena.

Pues bien, investigando un poco en como se usa el canvas de HTML5, me vino a la mente lo fácil que sería hacer un simulador del famoso “juego” “Juego de la Vida” de Conway.

El juego de la vida, es como se define en la wikipedia, un juego de 0 jugadores. ¿Un Juego sin jugadores? :), básicamente diseñamos una situación inicial y lo único que hacemos es ver como evoluciona la población de células que forman el juego.

El juego está formado por un conjunto de células, representadas por un punto, si la célula esta viva, se pintará de color verde, y si la célula esta muerta, no se pintará. Según ciertas condiciones dependientes del numero de vecinos, cada célula vivirá, morirá o nacerá en la siguiente generación. La implementación es muy sencilla y al igual que con la entrada anterior sobre Mandelbrot, los resultados son bastante interesantes y sin duda algunos patrones de evolución son bastante vistosos.

Aconsejo echar un vistazo a la entrada de la wikipedia para saber un poco más en que consiste el juego.

Hablando de la implementación, pintar en el canvas de HTML5 es bastante sencillo, básicamente, se reduce a 3 lineas

// ...
var context = canvas.getContext("2d");
context.fillStyle = "rgb(100,0,100)";
context.fillRect(10,10, 100, 100);
// ...

Con esas 3 líneas dibujamos un cuadrado en la posicion 10, 10 del canvas. De hecho una vez que obtenemos el contexto, podemos hacer las típicas operaciones, como dibujar cuadrados, arcos, rutas o imagenes.

Para mas detalles, os aconsejo que visiteis el sitio de desarrolladores de mozilla, donde tienen un fantastico tutorial de lo que se puede hacer con el canvas: https://developer.mozilla.org/en/Canvas_tutorial

Finalmente, os dejo con el código fuente de una implementación sencilla del juego de la vida y que como no puedo incrustar en este post de wordpress, podeis ver aquí

<html>
<head>
	<script type="text/javascript">
		var cellSize=10;
		var hcells = 70;
		var vcells = 40;
		var board;
		var canvas;
		var context; 
		var timerId = undefined;
		
		function drawShapeInBoard()
		{
			// Draw Some shapes in the board
			
			board[10][10] = board[12][10] = board[12][9] = board[14][8] = board[14][7] = board[14][6] = board[16][7] = board[16][6] = board[16][5] = board[16][6] = 1;
			
			board[25][30] = board[26][30] = board[27][30]  = board[28][30] = board[29][30] = board[29][30] = board[30][30] = board[31][30] = board[33][30] = board[34][30] = board[35][30] = board[29][30] = 1;
		}
		
		function initGame() {
			canvas = document.getElementById("gameoflife");
			context = canvas.getContext("2d");		
			canvas.addEventListener("click", onCanvasClick, false);	
			initBoard();
			drawShapeInBoard();
			drawBoard();
		}
		
		function onMouseMove(evt) {
			context.fillStyle = "rgb(200,200,200)"			
			context.fillRect(evt.clientX - canvas.offsetLeft, evt.clientY - canvas.offsetTop, cellSize, cellSize);
		}
		
		function onCanvasClick(evt) {
			var x = evt.clientX - canvas.offsetLeft;
			var y = evt.clientY - canvas.offsetTop;
			var boardX = parseInt(x / cellSize);
			var boardY = parseInt(y / cellSize);
			if ( isAlive(boardX, boardY) ) board[boardX][boardY] = 0
			else board[boardX][boardY] = 1;
			
			drawBoard();
		}
		
		function initBoard() {
			board = [];
			for ( i = 0; i < hcells; i++) {
				board[i] = [];
				for ( j = 0; j < vcells; j++ ) {
					board[i][j] = 0;
				}
			}
		}
		
		function drawBoard() {
			for ( i = 0; i < hcells; i++) {
				for ( j = 0; j < vcells; j++ ) {
					if ( board[i][j] == 0){
						context.fillStyle = "rgb(180,180,180)";
					} else {
						context.fillStyle = "rgb(0,170,0)";
					}					
					context.fillRect(i*cellSize, j*cellSize, cellSize, cellSize);					
				}
			}
		}
		
		function isAlive(x,y) {
			if ( board[x] ) 
				if ( board[x][y] == 1) return true;
			return false;
		}
		
		function numberOfNeighbours(x, y) {
			var count = 0;
			if ( isAlive(x-1, y   ) ) count++;
			if ( isAlive(x-1, y-1 ) ) count++;
			if ( isAlive(x-1, y+1 ) ) count++;
			if ( isAlive(x  , y-1 ) ) count++;
			if ( isAlive(x  , y+1 ) ) count++;
			if ( isAlive(x+1, y-1 ) ) count++;
			if ( isAlive(x+1, y+1 ) ) count++;
			if ( isAlive(x+1, y ) ) count++;
			
			return count;
		}
		
		function nextStep() {
			var newBoard = [];
			for ( i = 0; i < hcells; i++) {
				newBoard[i] = [];
				for ( j = 0; j < vcells; j++ ) {
					var neighbours = numberOfNeighbours(i, j);
					if ( isAlive(i,j) && neighbours < 2) newBoard[i][j] = 0;
					else if ( isAlive(i,j) && neighbours > 3 ) newBoard[i][j] = 0;
					else if ( isAlive(i,j) && (neighbours == 2 || neighbours == 3) ) newBoard[i][j] = 1;
					else if ( !isAlive(i,j) && (neighbours == 3) ) newBoard[i][j] = 1;
					else newBoard[i][j] = 0;
				}
			}
			board = newBoard;
		}
		
		function computeNS() {
			nextStep();
			drawBoard();
		}
		
		function startNS() {
			if ( ! timerId) {
				timerId = setInterval("computeNS()", 150);
				var status = document.getElementById("status");
				status.innerHTML = "<b>Running</b>";
			}
		}
		
		function stopNS() {
			clearInterval(timerId);
			timerId = undefined;
			var status = document.getElementById("status");
			status.innerHTML = "<b>Stopped</b>";
		}
		
		function clearBoard() {
			initBoard();
			drawBoard();
		}
		
	</script>
</head>
<body onload="initGame()">
	<p align="center">
		The Game of Life
	</p>
	<p align="center">
		<canvas id="gameoflife" width="700" height="400" border="1"></canvas>
		<br/>
		<button onclick="computeNS()">Next Step</button>
		<button onclick="startNS()">Start</button>
		<button onclick="stopNS()">Stop</button>
		<button onclick="clearBoard()">Clear</button>
		<br/>
		<span id="status"><b>Stopped</b></span>
	</p>
</body>	
</html>

Un cambio necesario. HTML 5.

septiembre 22, 2009
Estamos viendo nacer uno de los cambios más importantes de los últimos años, la próxima versión de uno de los lenguajes más usados en la actualidad, el HTML 5, está ultimando sus detalles finales.
El actual estándar (4.01) data de 1999 (aunque la última revisión fue en 2001), en estos casi 10 años, han pasado muchísimas cosas en lo que se refiere a las páginas web, la evolución del lenguaje que se responsabiliza de mostrar los contenidos al usuario necesitaba un cambio para adaptarse a estos nuevos tiempos.
Pese a que durante este tiempo el estándar HTML no se ha movido, lo cierto es que han surgido muchas tecnologías que ayudaban a paliar esta inmovilidad, como pueden ser los CSS, o incluso el mismo Flash.
Con cosas como Flash, se han cubierto las necesidades que las nuevas tecnologías demandaban.
Para entender la película al completo, falta incorporar a los actores principales, los navegadores, las aplicaciones que son los encargados de mostrar el HTML y todo su contenido adicional.
Aunque originalmente, los navegadores mostraban contenido bastante estático, hoy en día son plataformas lanzadoras de aplicaciones, como vemos, los movimientos de las grandes empresas se dirigen a encapsular cada vez mas aplicaciones en el navegador, ejemplos los hay en gran número, gmail, google docs, office online, flickr, solo son unos pocos casos.
El futuro de la web pasar por la implementación de los nuevos estándares en los navegadores.
A diferencia de las anteriores revisiones de HTML, la evolución que se va a publicar va a ser de gran importancia ya que el uso de la web hace 10 años no tiene nada que ver con el que se realiza hoy en día. Si pensamos para que usábamos un navegador hace 10 años y lo comparamos con el uso que le damos actualmente nos daremos cuenta que poco tiene que ver. Según que trabajo, es posible que la única aplicación que ejecutemos durante un día de trabajo sea un navegador.
Uno de los cambios más importantes que incorpora HTML5 es que expone una API que permite manipular directamente elementos de la página, por ejemplo, se ha incorporado el elemento canvas con el podrá pintar gráficos 2D de forma directa, sin tener que usar “trucos” de javascript o elementos externos como flash o applets java.
Derivado de las nuevas APIs, esta otro gran cambio, en HTML5 es la incorporación de elementos multimedia de forma nativa, mediante el uso del tag audio o video, podremos incrustar en nuestras webs videos sin tener que recurrir a ningún plugin, solo necesitaremos un navegador compatible.
Con esta nueva versión de HTML 5 también se ha incorporado la posibilidad de acceder a aplicaciones web estando offline, lo que ya nos proporcionaba Google Gears, va a estar incluido dentro del navegador. Como veíamos la penetración de las aplicaciones web en nuestro uso diario ha influido de forma determinante en la incorporación de estas necesidades.
Aparte de estos cambios, la nueva versión ha revisado numerosos elementos del lenguaje, por ejemplo han eliminado tags como <font> o <center> forzándolos a moverlos a la css con el fin de separar realmente la presentación del contenido.
Como comentábamos antes, la parte más importante del papel son los navegadores, y son los que tienen que materializar los cambios que impone el estándar, por ejemplo debido a la inclusión de los contenidos audiovisuales de forma nativa, los navegadores van a tener que incluir una gestión de contenidos multimedia  que antes no necesitaban incorporar, ya que se encargaban de ellos otros elementos como los plugins.
En el momento de escribir esta entrada hay varios navegadores con soporte preliminar de HTML 5. Firefox 3.5, Chrome v3, Safari 4 y Opera 10.
Un buen punto de entrada puede ser la versión de HTML 5 de youtube: http://www.youtube.com/html5 . Si entramos en esta web con uno de los navegadores anteriores podremos ver el video sin necesidad de instalar ningún plugin.

Safari HTML5

Estamos viendo nacer uno de los cambios más importantes de los últimos años, la próxima versión de uno de los lenguajes más usados en la actualidad, el HTML 5, está ultimando sus detalles finales.

El actual estándar (4.01) data de 1999 (aunque la última revisión fue en 2001), en estos casi 10 años, han pasado muchísimas cosas en lo que se refiere a las páginas web, la evolución del lenguaje que se responsabiliza de mostrar los contenidos al usuario necesitaba un cambio para adaptarse a estos nuevos tiempos.

Pese a que durante este tiempo el estándar HTML no se ha movido, lo cierto es que han surgido muchas tecnologías que ayudaban a paliar esta inmovilidad, como pueden ser los CSS, o incluso el mismo Flash.

Con cosas como Flash, se han cubierto las necesidades que las nuevas tecnologías demandaban.

Para entender la película al completo, falta incorporar a los actores principales, los navegadores, las aplicaciones que son los encargados de mostrar el HTML y todo su contenido adicional.

Aunque originalmente, los navegadores mostraban contenido bastante estático, hoy en día son plataformas lanzadoras de aplicaciones, como vemos, los movimientos de las grandes empresas se dirigen a encapsular cada vez mas aplicaciones en el navegador, ejemplos los hay en gran número, gmail, google docs, office online, flickr, solo son unos pocos casos.

El futuro de la web pasar por la implementación de los nuevos estándares en los navegadores.

A diferencia de las anteriores revisiones de HTML, la evolución que se va a publicar va a ser de gran importancia ya que el uso de la web hace 10 años no tiene nada que ver con el que se realiza hoy en día. Si pensamos para que usábamos un navegador hace 10 años y lo comparamos con el uso que le damos actualmente nos daremos cuenta que poco tiene que ver. Según que trabajo, es posible que la única aplicación que ejecutemos durante un día de trabajo sea un navegador.

Uno de los cambios más importantes que incorpora HTML5 es que expone una API que permite manipular directamente elementos de la página, por ejemplo, se ha incorporado el elemento canvas con el podrá pintar gráficos 2D de forma directa, sin tener que usar “trucos” de javascript o elementos externos como flash o applets java.

Derivado de las nuevas APIs, esta otro gran cambio, en HTML5 es la incorporación de elementos multimedia de forma nativa, mediante el uso del tag audio o video, podremos incrustar en nuestras webs videos sin tener que recurrir a ningún plugin, solo necesitaremos un navegador compatible.

Con esta nueva versión de HTML 5 también se ha incorporado la posibilidad de acceder a aplicaciones web estando offline, lo que ya nos proporcionaba Google Gears, va a estar incluido dentro del navegador. Como veíamos la penetración de las aplicaciones web en nuestro uso diario ha influido de forma determinante en la incorporación de estas necesidades.

Aparte de estos cambios, la nueva versión ha revisado numerosos elementos del lenguaje, por ejemplo han eliminado tags como <font> o <center> forzándolos a moverlos a la css con el fin de separar realmente la presentación del contenido.

Como comentábamos antes, la parte más importante del papel son los navegadores, y son los que tienen que materializar los cambios que impone el estándar, por ejemplo debido a la inclusión de los contenidos audiovisuales de forma nativa, los navegadores van a tener que incluir una gestión de contenidos multimedia que antes no necesitaban incorporar, ya que se encargaban de ellos otros elementos como los plugins.

En el momento de escribir esta entrada hay varios navegadores con soporte preliminar de HTML 5. Firefox 3.5, Chrome v3, Safari 4 y Opera 10.

Un buen punto de entrada puede ser la versión de HTML 5 de youtube: http://www.youtube.com/html5 . Si entramos en esta web con uno de los navegadores anteriores podremos ver el video sin necesidad de instalar ningún plugin.