viernes, 12 de enero de 2007

Objeto XMLHttpRequest

Tal como comentaba en una entrada anterior, vamos ahora a destripar el código JavaScript básico para crear el objeto XMLHttpRequest.

Analicemos el siguiente código:

var pagina_requerida = false;
if (window.XMLHttpRequest)
{
// Si es Mozilla, Safari etc
pagina_requerida = new XMLHttpRequest ();
} else if (window.ActiveXObject)
{
// pero si es IE
try
{
pagina_requerida = new ActiveXObject ("Msxml2.XMLHTTP");
}
catch (e)
{
// en caso que sea una versión antigua
try
{
pagina_requerida = new ActiveXObject ("Microsoft.XMLHTTP");
}
catch (e)
{
}
}
}
else
return false;

En esta parte del código es donde se crea la instancia del objeto XMLHttpRequest.

Como siguen existiendo diferencias de integración del objeto a nivel de navegador ( en Mozilla, Safari, etc, es un objeto nativo, y en IE previo a la v.7 es un ActiveX ) se debe comprobar el navegador del cliente y crear la instancia de una forma o de otra.

La mejor forma de comprobar el navegador del cliente es ver si soporta el objeto, así si se puede crear el objeto window.XMLHttpRequest es que el navegador es Mozilla o Safari, si no probamos con el ActiveX.

En el caso de IE se prueba el ActiveXObjetc("Msxml2.XMLHTTP") y si no funciona es que es una versión más antigua que utiliza ActiveXObject("Microsoft.XMLHTTP").

En el peor de los casos el navegador cliente no soporta XMLHttpRequest y no podremos utilizar AJAX.

Pero bueno, hasta aquí lo que tenemos es una nueva instancia del objeto XMLHttpRequest en la variable pagina_requerida en este caso, y es la que utilizaremos para la comunicación asíncrona con nuestro servidor web.

He visto otras formas de comprobar el navegador cliente para crear la instancia del objeto XMLHttpRequest pero esta me ha parecido la mejor.

Hoy hasta aquí. En próximas entregas veremos más en detalle la comunicación asíncrona con el servidor, la forma de enviar, recibir y tratar los datos, y la forma de actualizar partes de nuestra página sin recargarla.

Somatocarta

Hace un tiempo surgió en el foro de Velneo un post titulado "Somatocarta" donde GAV quería saber si era posible hacer con Velneo un informe que representara una gráfica donde se plasmaran los ejes, la rejilla de coordenadas y una figura fija, y encima poder dibujar un punto por coordenadas X,Y que correspodían a una ficha de una tabla.

La ebullición típica del foro de Velneo hizo brotar un montón de ideas ingeniosas para plasmar dicho gráfico en un informe de Velneo; casilleros de 14x13, una tabla maestra con 182 dibujos, preposicionar puntos en las intersecciones y mostrarlos por condiciones de visibilidad, etc.

Yo propuse:
"Y si generas el informe en html? Así lo podrías montar como quieras y siempre se imprimirá. Un saludo, DomK "

Como de costumbre nadie me hizo caso ;-D hasta que alguien más juicioso que yo y con mucha más solera (gracias Adolfomont) volvió sobre mi propuesta.

Lo siguiente fue montar una demo-web de un gráfico por coordenadas x-y, e integrarlo dentro de un formulario Velneo. Veamos cómo.

Mi propuesta consistía en una página web con capas (layers). Una capa para mostrar el fondo de la gráfica, es decir, la rejilla, los ejes de coordenadas y demás adornos, y otra capa por cada punto a representar. En la capa del punto sólo se representaría un gif de un píxel por un píxel para el punto, que se situaría sobre la capa del fondo con la rejilla.

Veamos el código html de la página en cuestión.

[!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"]
[html]
[head]
[title]Grafico html[/title]
[meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"]
[/head]
[body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0"]
[div id="Rejilla" style="position:absolute; width:600px; height:480px; z-index:1; left: 0px; top: 0px;"]
[img src="img/Rejilla.gif" width="600" height="480"]
[/div]
[div id="Punto" style="position:absolute; width:1px; height:1px; z-index:2; left: 150px; top: 340px;"]
[img src="img/Punto.gif" width="1" height="1"]
[/div]
[/body]
[/html]

En esta página tenemos dos div's (layers o capas); uno llamado Rejilla que contiene la imagen de la rejilla y está situado en z=1 (orden de apilamiento de las capas), y otro para el punto a representar, llamado Punto que contiene la imagen del punto y está situado en z=2 para que se muestre por encima de la rejilla.

El truco para utilizar esto como una representación gráfica por coordenadas es el uso que hacemos de las coordenadas de las capas. Estamos definiendo la posición de los layers como absoluta, esto quiere decir que sus coordenadas (posición de la esquina superior izquierda de la capa) se mide respecto del origen (esquina superior izquierda) de la ventana que contiene al layer.

Hemos de tener en cuenta el sentido de los ejes; la coordenada X aumenta hacia la derecha y la coordenada Y aumenta hacia abajo. Lo normal es que en nuestro gráfico la coordenada X vaya en el mismo sentido, pero la Y va en sentido inverso. Esto implica hacer una inversión del eje Y para pasar nuestras coordenadas-gráfico a píxeles-pantalla en nuestra representación gráfica.

Supongamos que la imagen de la rejilla es como esta por ejemplo



donde tenemos un margen superior de 40 píxeles, un margen izquierdo de 50 píxeles y un paso de rejilla de 50 píxeles en X y 50 píxeles en Y. El origen de coordenadas lo tenemos en la esquina inferior izquierda de nuestra rejilla.

Veamos en principio la traslación del origen de coordenadas necesaria para llevar un punto de coordenadas-gráfico (0,0) a las coordenadas píxeles-pantalla.

El (0,0) de las coordenadas píxeles-pantalla se encuentra en la esquina superior izquierda, y para llevar este punto al (0,0) de nuestro gráfico deberíamos aumentar la coordenada X en 50 píxeles (margen izquierdo de la rejilla) y la coordenada Y en 440 píxeles (40 del margen superior de la rejilla + (50*8) píxeles de rejilla).

Supongamos que queremos representar ahora el punto (2,2) en nuestro gráfico. La coordenada x=2 se tranformará en 50 de margen izquierdo más 2 veces el paso de la rejilla, es decir, 50+(2*50)=150, y la coordenada y=2 se transformará en los 440 píxeles anteriormente calculados menos 2 veces el paso de la rejilla, es decir, 440-(2*50)=340.

Así pues nuestra transformación de coordenadas quedará así

X = 50 + ( x * 50 )
Y = 440 - ( y * 50 )


Este es el más sencillo de los casos ya que la escala para los ejes x e y (valor del paso de la rejilla) es igual para ambos ejes. Si no fuese así bastaría con aplicar el factor de escala correspondiente a cada eje y ya está.

Ya tenemos la fórmula a aplicar a las coordenadas del punto que queramos representar en nuestro gráfico-web.

Supongamos que tenemos una tabla PUNTOS con los campos CODIGO, COORD-X y COORD-Y, y que queremos representar gráficamente el punto en el formulario de edición de un punto.

Para ello generaremos tres componentes html; uno para el inicio del html y la rejilla de fondo, otro para el div del punto, y otro para finalizar el html.

El código del componente html INI-HTML perteneciente a ninguna tabla sería:

[!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"]
[html]
[head][title]Grafico html[/title]
[meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"]
[/head]
[body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0"]
[div id="Rejilla" style="position:absolute; width:600px; height:480px; z-index:1; left: 0px; top: 0px;"]
[img src="img/Rejilla.gif" width="600" height="480"]
[/div]

El código del componente html PUNTO-HTML perteneciente a la tabla de PUNTOS sería:

[div id="Punto#AVP%CODIGO%" style="position:absolute; width:1px; height:1px; z-index:2; left: #AVP'X'px; top: #AVP'Y'px;"] [img src="img/Punto.gif" width="1" height="1"]
[/div]

donde utilizamos id="Punto#AVP%CODIGO%" para generar un identificador único para el layer del punto, y los parámetros #AVP'X' y #AVP'Y' para suministrar las coordenadas transformadas según la transformación de coordenadas antes calculada.

Y el código del componente html FIN-HTML perteneciente a ninguna tabla sería:

[/body]
[/html]

Ahora necesitamos un proceso GRAFICO.PRO que reciba el parámetro $PUNTO$ (variable global accesible web) que contendrá el CODIGO del punto a representar, y que monte la página web que representa ese punto. El proceso sería algo así como:

Rem-]Inicializo página
Set-]pagina,""
Set-]tramo,""
Rem-]Recibo parámetro
Set-]punto,$PUNTO$
Rem-]Compongo la página
Html, ejecutar componente-]tramo,INI-HTML
Set-]pagina,'pagina' + 'tramo'
Carga lista-]PUNTOS,CODIGO,'punto'
Seleccionar ficha por posición-]1
Leer ficha seleccionada
Set-]X,50 + ( %COORD-X% * 50 )
Set-]Y,440 - ( %COORD-Y% * 50 )
Html, ejecutar componente-]tramo,PUNTO-HTML,'X','Y'
Set-]pagina,'pagina' + 'tramo'
Html, ejecutar componente-]tramo,FIN-HTML
Set-]pagina,'pagina' + 'tramo'
Rem-]Devuelvo la página
Añadir retorno texto-]'pagina'

El proceso recibe en la variable global accesible web $PUNTO$ el CODIGO del punto a representar, ejecuta el componente INI-HTML, carga la lista de PUNTOS por el índice CODIGO resolviendolo con el código del punto a representar, hace la transformación de coordenadas y ejecuta el PUNTO-HTML pasandole en los parámetros 'X' e 'Y' con las coordenadas ya transformadas, finaliza el html y devuleve la página construida.

Ya tenemos todo lo necesario.

Ahora veamos cómo representar esto en el formulario de edición de PUNTOS.

Para ello vamos a necesitar un control html en el formulario con la siguiente fórmula para su contenido:

fGetWebAplicacion() + "GRAFICO.PRO?PUNTO=" + %CODIGO%

fGetWebAplicacion() devuelve la ruta web de nuestra aplicación, el típico http://ip_servidor/cgi-vel/alias_aplicacion/, y a esto le añadimos el proceso que genera nuestra representación gráfica pasandole a través de la variable global accesible web PUNTO el CODIGO del punto a representar.

Y ya está!!!


No lo había dicho antes pero esto sólo funciona en C/S, ya que al ser una página web compuesta por proceso desde componentes html, debe ser servida por el servidor web de Velneo.

Partiendo de esta base se pueden realizar todo tipo de representaciones gráficas-web a partir de datos en registros de tablas, sorteando así las limitaciones de los objetos específicos de Velneo para tal fin.

Veremos cómo a partir de este principio podemos generar gráficos de barras u otros más elaborados, pero eso será tema de un próximo post.

Hasta la próxima!

jueves, 4 de enero de 2007

Descubriendo AJAX

Hace un tiempo uno de mis compañeros de trabajo me invitó a crear una cuenta de correo en Gmail y gustoso acepté la invitación y empecé a usar la cuenta.

Al principio me pareció fantástico disponer de 2GB de almacenamiento, "Ya nunca tendré que borrar mensajes!" pensé, pero no me daba cuenta de lo que tenía entre manos. Al poco tiempo de usarlo me di cuenta de que no hacía falta darle al botón de refrescar para recibir los nuevos mensajes, llegaban solos!

Por otra parte descubrí el maravilloso GoogleMaps, pero no me dí cuenta de lo que estaba pasando; mover el mapa arrastrando el ratón (estaba acostumbrado al zoom-pan dinámico de AutoCad y me pareció lo más natural del mundo), incluir mis propios tags en sus mapas...

Y a través de un contacto externo a mi empresa me llegó la noticia de que dos chavales catalanes habían hecho un escritorio virtual en internet donde podías tener tus aplicaciones y datos, y trabajar con ellos.

Poco a poco la web iba cambiando.

Un día, en uno de mis desarrollos web, necesité que la página del navegador de un cliente se actualizase automáticamente, sin su intervención. Es decir, la página debía consultar al servidor, preguntar si debía recargarse, y en caso afirmativo hacerlo.

Lo hice utilizando un truco bastante "sucio": un frame oculto que preguntaba histérico al servidor si el frame visible debía actualizarse, y cuando recibía la respuesta afirmativa, recargaba el frame visible. Pero no me gustó.

Casualmente llegó a mis manos el código html de una web donde ocurría algo raro con los links; el destino de todos los links era el mismo, sólo cambiaban los parámetros mandados a la url destino, y además, o el Firefox 2 era muy, pero que muy rápido, o sólo se recargaban ciertas partes de la página al pulsar un link, y no usaba frames.

Aún no lo sabía pero en todos y cada uno de los casos anteriores me encontraba ante lo mismo: AJAX.

Busqué en Google cómo actualizar sólo ciertas partes de una página html y enseguida aparecieron cientos de páginas y blogs hablando de AJAX.

AJAX es el acrónimo de Asynchronous JavaScript And XML.

En sí no es una nueva tecnología, sino una agrupación de tecnologías que trababjan juntas: XHTML o HTML y CSS, DOM y JavaScript. XHTML o HTML semántico para las páginas, CSS para su representación, Document Object Model para acceder a la estructura de las páginas y JavaScript para interactuar con el servidor y con la página cliente. Genial.

Todo esto ya hacía mucho tiempo que estaba inventado, no era nada nuevo. Lo nuevo era verlo todo junto y funcionando. El punto fuerte de AJAX consiste en intercambiar datos asíncronamente con el servidor web a través del objeto XMLHttpRequest.

Si estais interesados en el tema os puedo recomendar la siguiente página:
www.javapassion.com/ajaxcodecamp . Es de Sang Shin, de Sun Microsystems, y aclara bastantes conceptos básicos. A mí me sirvió de mucho.

Mi interés principal en ese momento de descubrimiento de AJAX fue, por supuesto, ver si esto funcionaba en el servidor Velneo, y funciona. Funciona, y como todo en Velneo, rapidito, rapidito.

Hoy hasta aquí. En próximas entregas, destriparemos el JavaScript básico para la creación del objeto HttpRequest, la comunicación asíncrona con el servidor, la recepción de datos y la actualización de partes específicas de la página.

Hasta la próxima.