Author Archives: admin

Eventos en jQuery Mobile

jQuery Mobile ofrece varios eventos personalizados que se han implementado sobre los eventos nativos para asi aumentar las posibilidades de los UI en las plataformas móviles. Nótese que estos eventos emplean varios eventos de tipo touch, mouse o de ventana, dependiendo de la existencia del evento, asi que puedes hacer bind a eventos tanto en plataforma móviles como en entornos desktop. Puedes engancharte a estos eventos como cualquier otro evento jQuery, utilizando los métodos live() o bind().

Eventos touch

tap

Toque de la pantalla rápido

taphold

Toque de la pantalla por al menos un segundo

swipe

Este evento ocurre cuando se realiza un arrastrado horizontal por la pantalla de 30px o más (y menos de 20px verticalmente) durante al menos un segundo.

swipeleft

El mismo evento que el anterior pero cuando la dirección es hacia la izquierda.

swiperight

El mismo evento que el anterior pero cuando la dirección es hacia la derecha

Evento de cambio de orientación

orientationchange

Este evento se dispara cuando la orientación del dispositivo cambia (girándolo verticalmente u horizontalmente). Cuando te enganchas a este eventos, la función de callback puede recibir un segundo argumento, que contiene la property ‘orientation’ cuyos valores posibles son “portrait” o “landscape”.Estos valores son también añadidos como clases al elemento HTML, permitiendo que se pueda seleccionar desde selectores CSS. Nótese que cuando este evento no está soportado por el dispositivo , la implementación actual de jQuery Mobile invoca el evento resize.

Eventos de Scroll

scrollstart

Se dispara cuando comienza el scroll. Nótese que los dispositivos con iOS congelan la manipulación del DOM mientras se hace el scroll, encolando eventos hasta que acaba el scroll. Actualmente se está investigando formas para permitir manipulaciones DOM que se apliquen antes de que comienze el scroll.

scrollstop

Cuando el scroll termina

Eventos de esconder/mostrar Page

Cuandoquiera que una página es mostrada o escondida con jQuery Mobile, se disparan dos eventos sobre esa página. Los eventos disparados dependen de si esa página está siendo mostrada o siendo escondida, asi que cuando una tiene lugar una transición de Page, se disparan 4 eventos: 2 por página

pagebeforeshow

Antes de que la página vaya a ser mostrada

pagebeforehide

Antes de que la página vaya a ser escondida

pageshow

Después de que la página ha sido mostrada

pagehide

Después de que la página ha sido escondida

Nota que estos 4 eventos pueden hacer referencia tanto a la siguiente pagina (nextPage) como a la página previa (prevPage),  dependiendo de si la página esta siendo mostrada o escondida, y de si existe o no la pagina siguiente o previa (la primera página de todas no tiene una página previa a referenciar, pero de todas formas hay un objeto jQuery vació para el caso). Puedes acceder a esta referencia a través del segundo argumento de la función callback. Por ejemplo:

$('div').live('pageshow',function(event, ui){

alert('This page was just hidden: '+ ui.prevPage);

});

$('div').live('pagehide',function(event, ui){

alert('This page was just shown: '+ ui.nextPage);

});

También , para que estos handlers sean invocados durante la carga de la página inicial, debes engancharlos antes de que se ejecute eljQuery Mobile. Esto por ejemplo, se puede hacer en el mobileInit handler, como se describió en el artículo sobre la autoinicializacion de configuraciones.

Eventos de inicialización de Page

Internamente, jQuery Mobile autoinicializa plugins basándose en las convenciones de maquetado encontradas en la “page” que esté. Por ejemplo, un elemento input de tipo rango automáticamente generará un slider control personalizado.

Esta auto-inicializacion se controla por el plugin “page”, que despacha eventos antes y después de que se ejecute, permitiendo manipular un page en la pre/post inicialización, o incluso proporcionarle un comportamiento de inicialización personalizado hasta prevenir de que se hagan autoinicializaciones. Nótese que estos eventos sólo se dispararán una vez por página, a diferencia de los eventos “show/hide”, que se disparan cada vez que una página es mostrada o escondida.

pagebeforecreate

Antes de que se haga la inicializacion

pagecreate

Después de que se haga la inicializacion

$('#aboutPage').live('pagebeforecreate',function(event){

alert('This page was just inserted into the dom!');

});

$('#aboutPage').live('pagecreate',function(event){

alert('This page was just enhanced by jQuery Mobile!');

});

Nótese que si hacemos un binding del eventos pagebeforecreate y hacemos retornar false , prevenimos que el plugin de la page haga sus manipulaciones:

$('#aboutPage').live('pagebeforecreate',function(event){

//run your own enhancement scripting here...

return false;

});

Nota sobre los Page IDs de la versión Alpha 2: En esta versión y anteriores, los elementos page utilizaban el atributo ID para almacenar la localización desde donde venían. Luego cuando colocamos un atributo ID en una page que es mostrada como una página simple dejQuery mobile a través de Ajax, jQuery Mobile envuelve esa página en otro elemento div “page”, conservando asi todas las referencias CSS al ID. Sin embargo , esto significa que el atributo ID ya no está en el elemento “page”, asi que debes acordarte de esto cuando se hagan binding de eventos page (pagebeforecreate, pagecreate, etc). Para evitar problemas , intenta utilizar una clase CSS si es posible.

Eventos de Animación

jQuery Mobile tiene un plugin llamada “animationComplete” , que se ejecuta después de añadir o borrar un class que aplica una transición CSS.

 

Anatomía de una página

[Fuente: web de jquery mobile]

La estructura “Page” de jQuery Mobile se optimiza para soportar tanto páginas sencillas, o también para enlaces internos locales “pages” dentro de una página.

El objetivo de seguir este modelo es permitir a los programadores crear webs utilizando las mejores prácticas – donde los enlaces normales funcionan sin ninguna configuración especial – ya que hacer interfaces de usuario ricos , como si fueran nativos no puede ser conseguido utilizando peticiones HTTP estandars.

La estructura Mobile page

Una web en jQuery Mobile debe comenzar con un ‘doctype’ de HTML5 para poder asi aprovechar todas las ventajas de todas las características del framework (Los dispositivos más antiguos con navegadores que no entienden HTML5 tan solo ignorarán el ‘doctype’ y algunos atributos de personalización). En el ‘head’ es donde ponemos las referencias a la librería de jQuery , jQuery Mobile y el mobiletheme CSS. Recomendamos referenciarlos CDN-Hosted para aumentar el rendimiento:

<!DOCTYPE html>
<html>
<head>
	<title>Page Title</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
	<script type="text/javascript" src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"></script>
</head>
<body>
	...content goes here...
</body>
</html>

 

La meta tag Viewport

Nótese que en el código anterior hay un metatag viewport, esto es para especificar como el browser debe pintar el nivel de zoom de la página y las dimensiones. Si no está configurada, muchos navegadores de móviles utilizarán una página “virtual” con una anchura de 900 pixeles para hacerla funcionar bien con los sites de los desktop y las pantallas pueden parecer con un zoom muy cerca y demasiado ancho. Configurando este metatag con content=”width=device-width, initial-scale=1”, la anchura será ajustada a la anchura de la pantalla del dispositivo.

<meta name="viewport" content="width=device-width, initial-scale=1">

Estos settings no deshabilitan la posibilidad que tiene el usuario para hacer zoom de las páginas lo cual es importante desde un punto de la accesibilidad. Hay un bug que ocurre en los iOS y es que a pesar de poner esta metatag cuando se cambia la orientación estas configuraciones no se respetan, esperamos que en futuras versiones sea corregido. Se pueden poner valores a este metatag para deshabilitar el zooming si es necesario.

Dentro del body: Pages

Dentro de la tag <body>, cada vista o “page” dentro de un dispositivo móvil se identifica con un elemento (normalmente un div) con el atributo “data-role” con el valor “page”.

<div  data-role="page">
...
</div>

Dentro de un contenedor “page”, se puede poner cualquier maquetación HTML, pero en las páginas típicas donde se utiliza jQueryMobile, el hijo inmediatamente seguido de un “page” son divs con los data-roles de “header”, “content” y “footer”:

<div data-role="page">
	<div data-role="header">...</div>
	<div data-role="content">...</div>
	<div data-role="footer">...</div>
</div>

 

Poniendolo todo junto: Template de una página básica simple

Poniendolo todo junto , este es un template que puede ser bueno para empezar un proyecto:

<!DOCTYPE html>
<html>
<head>
	<title>Page Title</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
	<script type="text/javascript" src="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.js"></script>
</head>

<body>
	<div data-role="page">
	
		<div data-role="header">
		<h1>Page Title</h1>
		</div><!-- /header -->
	
		<div data-role="content">
			<p>Page content goes here.</p>
		</div><!-- /content -->

		<div data-role="footer">
			<h4>Page Footer</h4>
		</div><!-- /footer -->

	</div><!-- /page -->
</body>
</html>

Queda algo como esto:

Template de estructura multi página

Un solo documento HTML puede contener varios ‘pages’ que son cargados juntos , se hace apilando varios divs con el data-role de “page”. Cada bloque ‘page’ necesita un ID único (id=”foo”) que será utilizado para enlazar internamente entre ‘pages’ (href=”#foo”). Cuanod un link se pincha, el framework buscará un ‘page’ interno con el ID especificado y hará una transición hacia ella.

Veamos un ejemplo de un site de 2 ‘page’ programado con dos jQuery mobile divs. Observese que sólo hay que poner un atributo ID en los divs pages cuando queremos que sean enlazados internamente, si son páginas separadas en documentos HTML distintos entonces no es necesario:

<body>
	<!-- Start of first page -->
	<div data-role="page" id="foo">
		<div data-role="header">
			<h1>Foo</h1>
		</div><!-- /header -->
		
		<div data-role="content">
			<p>I'm first in the source order so I'm shown as the page.</p>
			<p>View internal page called <a href="#bar">bar</a></p>
		</div><!-- /content -->
		
		<div data-role="footer">
			<h4>Page Footer</h4>
		</div><!-- /footer -->
		
	</div><!-- /page -->
	
	<!-- Start of second page -->
	<div data-role="page" id="bar">
	
		<div data-role="header">
			<h1>Bar</h1>
		</div><!-- /header -->
	
		<div data-role="content">
			<p>I'm first in the source order so I'm shown as the page.</p>
			<p><a href="#foo">Back to foo</a></p>
		</div><!-- /content -->
	
		<div data-role="footer">
			<h4>Page Footer</h4>
		</div><!-- /footer -->
	
	</div><!-- /page -->
</body>

NOTA: Debido a qué estamos utilizando la hash para guardar el historial de navegación de todas las ‘pages’ Ajax, no es posible poner enlaces a un anchor del tipo index.html#foo para llegar a una page de jQuery Mobile, porque el framework buscará por una page con el ID de #foo en vez de hacer el comportamiento nativo de hacer scrolling al contenido con el ID.

Convenciones , no requerimientos

Aunque la estructura de ‘page’ subrayada arriba es una aproximación recomendada para una web app estándar desarrollada con jQueryMobile, el framework es muy flexible con la estructura del documento. Los elementos page, header, content y footer son opcionales y son útiles en el sentido de proporcionar una estructura básica de formato.

El envoltorio ‘page’ suele requerirse para que funcione la auto-inicializacion pero ahora también es opcional en documentos de una sola página.

Para una página con un custom layout , todos estos elementos pueden ser omitidos pero la navegación Ajax y todos los widgetsfuncionarán como hacen en el template que pusimos arriba. Por detrás, el framework inyectará el envoltorio ‘page’ si no está incluido en el maquetado HTML porque se necesita para manejar pages, pero el maquetado HTML de inicio puede ser extremadamente simple.

Observese que en un setup de múltiples páginas, se requiere tener page wrappers en el maquetado HTML para agrupar el contenido enmultiples pages.

 

Mejora el jQuery con 25 trucos

[Fuente: http://www.tvidesign.co.uk/blog/improve-your-jquery-25-excellent-tips.aspx]

Introduction

jQuery is awesome. I’ve been using it for about a year now and although I was impressed to begin with I’m liking it more and more the longer I use it and the more I find out about it’s inner workings.

I’m no jQuery expert. I don’t claim to be, so if there are mistakes in this article then feel free to correct me or make suggestions for improvements.

I’d call myself an “intermediate” jQuery user and I thought some others out there could benefit from all the little tips, tricks and techniques I’ve learned over the past year. The article also ended up being a lot longer than I thought it was going to be so I’ll start with a table of contents so you can skip to the bits you’re interested in.

1. Carga el framework jQuery desde el Google Code

Google have been hosting several JavaScript libraries for a while now on Google Code and there are several advantages to loading it from them instead of from your server. It saves on bandwidth, it’ll load very quickly from Google’s CDN and most importantly it’ll already be cached if the user has visited a site which delivers it from Google Code.

This makes a lot of sense. How many sites out there are serving up identical copies of jQuery that aren’t getting cached? It’s easy to do too…

<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
	// Load jQuery
	google.load("jquery", "1.2.6");
	google.setOnLoadCallback(function() {
		// Your code goes here.
	});
</script>

Or, you can just include a direct reference like this…

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
2. Utiliza una hoja de estilos

Not just a jQuery tip, there are some great cheat sheets out there for most languages. It’s handy having every function on a printable A4 sheet for reference and luckily these guys have produced a couple of nice ones..

http://www.gscottolson.com/weblog/2008/01/11/jquery-cheat-sheet/
http://colorcharge.com/jquery/

3. Combina todos tus scripts y minimizalos (empaquetándolos para que ocupen menos)

OK, a general JavaScript tip here. But any big project that uses lots of jQuery probably uses lots of plugins (this site uses easing, localScroll, lightbox and preload) so it’s usually applicable.

Browsers can’t load scripts concurrently (well, most can’t, yet), which means that if you’ve got several scripts downloading one at a time then you’re really slowing down the loading of your page. So, assuming the scrips are being loaded on every page then you should consider combining them into one long script before deploying.

Some of the plugins will already be minified, but you should consider packing your scripts and any that aren’t already. It only takes a few seconds. I’m personally a fan of Packer by Dean Edwards

4. Utiliza Firebug para mostrar mensajes de consola

If you haven’t already installed Firebug then you really should. Aside from many other useful features such as allowing you to inspect http traffic and find problems with your CSS it has excellent logging commands that allow you to easily debug your scripts.

Here’s a full explanation of all of it’s features

My favourite features are “console.info”, which you can use to just dump messages and variables to the screen without having to use alert boxes and “console.time” which allows you to easily set up a timer to wrap a bunch of code and see how long it takes. They’re all really easy to use too…

console.time('create list');
for (i = 0; i < 1000; i++) {
	var myList = $('.myList');
	myList.append('This is list item ' + i);
}
console.timeEnd('create list');

In this instance I’ve deliberately written some very inefficient code! In the next few tips I’ll show you how we can use the timer to show some improvements which can be made.

5. Manten las operaciones de selección al mínimo haciendo caché

jQuery selectors are awesome. They make selecting any element on the page incredibly simple, but internally they have to do a fair amount of work and if you go mad with them you might find things starting to get pretty slow.

If you’re selecting the same element time and time again (in a loop for example) then you can just select it once and keep it in memory while you manipulate it to your heart’s content. Take the following example where we add items to an unordered list using a loop.

for (i = 0; i < 1000; i++) {
	var myList = $('.myList');
	myList.append('This is list item ' + i);
}

That takes 1066 milliseconds on my PC in Firefox 3 (imagine how long it would IE6!), which is pretty slow in JavaScript terms. Now take a look at the following code where we use the selector just once.

var myList = $('.myList');
for (i = 0; i < 1000; i++) {
	myList.append('This is list item ' + i);
}

That only takes 224 milliseconds, more than 4x faster, just by moving one line of code.

6. Manten la manipulación del DOM al mínimo

We can make the code from the previous tip even faster by cutting down on the number of times we insert into the DOM. DOM insertion operations like .append() .prepend() .after() and .wrap() are relatively costly and performing lots of them can really slow things down.

All we need to do is use string concatenation to build the list and then use a single function to add them to your unordered list like .html() is much quicker. Take the following example…

var myList = $('#myList');
for (i=0; i<1000; i++){
	myList.append('This is list item ' + i);
}
On my PC that takes 216 milliseconds , just over a 1/5th of a second, but if we build the list items as a string first and use the HTML method to do the insert, like this….
var myList = $('.myList');
var myListItems = '';
for (i = 0; i < 1000; i++) {
	myListItems += '<li>This is list item ' + i + '</li>';
}
myList.html(myListItems);

That takes 185 milliseconds, not much quicker but that’s another 31 milliseconds off the time.

7. Envuelve todo en un solo elemento cuando se haga cualquier tipo de inserción en el DOM

OK, don’t ask me why this one works (I’m sure a more experienced coder will explain).

In our last example we inserted 1000 list items into an unordered list using the .html() method. If we had have wrapped them in the UL tag before doing the insert and inserted the completed UL into another tag (a DIV) then we’re effectively only inserting 1 tag, not 1000, which seems to be much quicker. Like this…

var myList = $('.myList');
var myListItems = '<ul>';
for (i = 0; i < 1000; i++) {
	myListItems += '<li>This is list item ' + i + '</li>';
}
myListItems += '</ul>';
myList.html(myListItems);

The time is now only 19 milliseconds, a massive improvement, 50x faster than our first example.

8. Utiliza IDs en vez de classes cuando sea posible

jQuery makes selecting DOM elements using classes as easy as selecting elements by ID used to be, so it’s tempting to use classes much more liberally than before. It’s still much better to select by ID though because jQuery uses the browser’s native method (getElementByID) to do this and doesn’t have to do any of it’s own DOM traversal, which is much faster. How much faster? Let’s find out.

I’ll use the previous example and adapt it so each LI we create has a unique class added to it. Then I’ll loop through and select each one once.

// Create our list
var myList = $('.myList');
var myListItems = '<ul>';
for (i = 0; i < 1000; i++) {
	myListItems += '<li class="listItem' + i + '">This is a list item</li>';
}
myListItems += '</ul>';
myList.html(myListItems);
// Select each item once
for (i = 0; i < 1000; i++) {
	var selectedItem = $('.listItem' + i);
}

Just as I thought my browser had hung, it finished, in 5066 milliseconds (over 5 seconds). So i modified the code to give each item an ID instead of a class and then selected them using the ID.

// Create our list
var myList = $('.myList');
var myListItems = '<ul>';
for (i = 0; i < 1000; i++) {
	myListItems += '<li id="listItem' + i + '">This is a list item</li>';
}
myListItems += '</ul>';
myList.html(myListItems);
// Select each item once
for (i = 0; i < 1000; i++) {
	var selectedItem = $('#listItem' + i);
}

This time it only took 61 milliseconds. Nearly 100x faster.

9. Dale a tus selectores un contexto

By default, when you use a selector such as $(‘.myDiv’) the whole of the DOM will be traversed, which depending on the page could be expensive.

The jQuery function takes a second parameter when performing a selection.

jQuery( expression, context )

By providing a context to the selector, you give it an element to start searching within so that it doesn’t have to traverse the whole of the DOM.

To demonstrate this, let’s take the first block of code from the tip above. It creates an unordered list with 1000 items, each with an individual class. It then loops through and selects each item once. You’ll remember that when selecting by class it took just over 5 seconds to select all 1000 of them using this selector.

  1. var selectedItem = $(‘#listItem’ + i);

I then added a context so that it was only running the selector inside the unordered list, like this…

  1. var selectedItem = $(‘#listItem’ + i, $(‘.myList’));

It still took 3818 milliseconds because it’s still horribly inefficient, but that’s more than a 25% speed increase by making a small modification to a selector.

10. Utiliza el encadenado de forma correcta

One of the coolest things about jQuery is it’s ability to chain method calls together. So, for example, if you want to switch the class on an element.

  1. $(‘myDiv’).removeClass(‘off’).addClass(‘on’);

If you’re anything like me then you probably learned that in your first 5 minutes of reading about jQuery but it goes further than that. Firstly, it still works across line breaks (because jQuery = JavaScript), which means you can write neat code like this…

  1. $(‘#mypanel’)
  2. .find(‘TABLE .firstCol’)
  3. .removeClass(‘.firstCol’)
  4. .css(‘background’ : ‘red’)
  5. .append(‘<span>This cell is now red</span>’);

Making a habit of using chaining automatically helps you to cut down on your selector use too.

But it goes further than that. Let’s say that you want to perform several functions on an element but one of the first functions changes the element in some way, like this…

  1. $(‘#myTable’).find(‘.firstColumn’).css(‘background’,’red’);

We’ve selected a table, drilled down to find cells with a class of “firstColumn” and coloured them in red.

Let’s say we now want to colour all the cells with a class of “lastColumn” blue. Because we’ve used the find() funciton we’ve filtered out all the cells that don’t have a class of “firstColumn” so we need to use the selector again to get the table element and we can’t continue chaining, right? Luckily jQuery has an end() function which actually reverts back to the previous unaltered selection so you can carry on chaining, like this…

  1. $(‘#myTable’)
  2. .find(‘.firstColumn’)
  3. .css(‘background’,’red’)
  4. .end()
  5. .find(‘.lastColumn’)
  6. .css(‘background’,’blue’);

It’s also easier than you might think to write your own jQuery function which can chain. All you have to do is write a function which modifies an element and returns it.

  1. $.fn.makeRed = function() {
  2. return $(this).css(‘background’, ‘red’);
  3. }
  4. $(‘#myTable’).find(‘.firstColumn’).makeRed().append(‘hello’);

How easy was that?

11. Aprende a utilizar “animate” de forma correcta

When I first started using jQuery I loved the fact that it was easy to use the pre-defined animations like slideDown() and fadeIn() to get some really cool effects incredibly easy. It’s easy to take things further though because jQuery’s animate() method is very easy to use and very powerful. In fact, is you look at the jQuery source code you’ll see that internally those methods are just shortcuts which use the animate() function.

  1. slideDown: function(speed,callback){
  2. return this.animate({height: “show”}, speed, callback);
  3. },
  4. fadeIn: function(speed, callback){
  5. return this.animate({opacity: “show”}, speed, callback);
  6. }

The animate() method simply takes any CSS style and smoothly transitions it from one value to another. So, you can change the width, height, opacity, background-color, top, left, margin, color, font-size, anything you want.

This is how easy it is to animate all your menu items grow to 100 pixels high when you roll over them.

  1. $(‘#myList li’).mouseover(function() {
  2. $(this).animate({“height”: 100}, “slow”);
  3. });

Unlike other jQuery functions, animations are automatically queued, so if you want to run a second animation once the first is finished then just call the animate method twice, no callback necessary.

  1. $(‘#myBox’).mouseover(function() {
  2. $(this).animate({ “width”: 200 }, “slow”);
  3. $(this).animate({“height”: 200}, “slow”);
  4. });

If you want the animations to happen concurrently then just put both styles in the params object of a single call, like this…

  1. $(‘#myBox’).mouseover(function() {
  2. $(this).animate({ “width”: 200, “height”: 200 }, “slow”);
  3. });

You can animate any property that’s numeric. You can also download plugins to help you animate properties that aren’t, likecolors and background colors

12. Aprende sobre delegación de eventos

jQuery makes it easier than ever to attach events to elements in the DOM unobtrusively, which is great, but adding too many events is inefficient. Event delegation allows you to add less events to achieve the same result in many situations. The best way to illustrate this is with an example…

  1. $(‘#myTable TD’).click(function(){
  2. $(this).css(‘background’, ‘red’);
  3. });

A simple function which turns cells in a table red when you click on them. Let’s say that you’ve got a grid with 10 columns and 50 rows though, that’s 500 events bound. Wouldn’t it be neater if we could just attach a single event to the table and when the table is clicked have the event handler work out which cell was clicked before turning it red?

Well that’s exactly what event delegation is and it’s easy to implement…

  1. $(‘#myTable’).click(function(e) {
  2. var clicked = $(e.target);
  3. clicked.css(‘background’, ‘red’);
  4. });

‘e’ contains information about the event, including the target element that actually received the click. All we have to do is inspect it to see which cell was actually clicked. Much neater.

Event delegation has another benefit. Normally, When you bind a handler to a collection of elements it gets attached to those elements and those elements only. If you add new elements to the DOM which would have been matched by the selector then they don’t have the event handler bound to them (are you following me?) then nothing will happen.

When using event delegation you can add as many matching elements to the DOM as you like after the event is bound and they work too.

13. Utiliza clases para almacenar el estado

This is the most basic way of storing information about a block of html. jQuery is great at manipulating elements based upon their classes, so if you need to store information about the state of an element then why not add an extra class to store it?

Here’s an example. We want to create an expanding menu. When you click the button we want the panel to slideDown() if it’s currently closed, or slideUp() if it’s currently open. We’ll start with the HTML

  1. <div class=”menuItem expanded”>
  2. <div class=”button”>
  3. click me
  4. </div>
  5. <div class=”panel”>
  6. <ul>
  7. <li>Menu item 1</li>
  8. <li>Menu item 2</li>
  9. <li>Menu item 3</li>
  10. </ul>
  11. </div>
  12. </div>

Very simple! We’ve just added an extra class to the wrapper div which serves no other purpose other than to tell us the state of the item. So all we need is a click event handler which performs slideUp() or slideDown() on the corresponding panel when the button is clicked.

  1. $(‘.button’).click(function() {
  2. var menuItem = $(this).parent();
  3. var panel = menuItem.find(‘.panel’);
  4. if (menuItem.hasClass(“expanded”)) {
  5. menuItem.removeClass(‘expanded’).addClass(‘collapsed’);
  6. panel.slideUp();
  7. }
  8. else if (menuItem.hasClass(“collapsed”)) {
  9. menuItem.removeClass(‘collapsed’).addClass(‘expanded’);
  10. panel.slideDown();
  11. }
  12. });

That’s a very simple example, but you can add extra classes for storing all sorts of information about an element or HTML fragment.

However, in all but simple cases it’s probably better to use the next tip.

14. Incluso mejor, utilizar el método interno data() de jQuery para almacenar el estado

It’s not very well documented for some reason but jQuery has an internal data() method which can be used to store information in key/value pairs against any DOM element. Storing a piece of data is as simple as this…

  1. $(‘#myDiv’).data(‘currentState’, ‘off’);

We can amend the example from the previous tip. We’ll use the same HTML (with the “expanded” class removed) and use the data() function instead.

  1. $(‘.button’).click(function() {
  2. var menuItem = $(this).parent();
  3. var panel = menuItem.find(‘.panel’);
  4. if (menuItem.data(‘collapsed’)) {
  5. menuItem.data(‘collapsed’, false);
  6. panel.slideDown();
  7. }
  8. else {
  9. menuItem.data(‘collapsed’, true);
  10. panel.slideUp();
  11. }
  12. });

I’m sure you’ll agree this is much neater. For more information about data() and removeData(), see this page…

jQuery internals

15. Escribe tus propios selectores

jQuery has loads of built-in selectors for selecting elements by ID, class, tag, attribute and many more. But what do you do when you need to select elements based upon something else and jQuery doesn’t have a selector?

Well, one answer would be to add classes to the elements from the start and use those to select them, but it turns out that it’s not hard to extend jQuery to add new selectors.

The best way to demonstrate is with an example.

  1. $.extend($.expr[‘:’], {
  2. over100pixels: function(a) {
  3. return $(a).height() > 100;
  4. }
  5. });
  6. $(‘.box:over100pixels’).click(function() {
  7. alert(‘The element you clicked is over 100 pixels high’);
  8. });

The first block of code creates a custom selector which finds any element that is more than 100 pixels tall. The second block just uses it to add a click handler to all those elements.

I won’t go into any more detail here but you can imagine how powerful this is and if you search google for “custom jquery selector” you’ll find loads of great examples.

16. Streamline tu HTML y modificalo una vez que la pagina ha cargado

The title might not make a lot of sense but this tip can potentially neaten up your code, reduce the weight and download time of your page and help your SEO. Take the following HTML for example…

  1. <div class=”fieldOuter”>
  2. <div class=”inner”>
  3. <div class=”field”>This is field number 1</div>
  4. </div>
  5. <div class=”errorBar”>
  6. <div class=”icon”><img src=”icon.png” alt=”icon” /></div>
  7. <div class=”message”><span>This is an error message</span></div>
  8. </div>
  9. </div>
  10. <div class=”fieldOuter”>
  11. <div class=”inner”>
  12. <div class=”field”>This is field number 2</div>
  13. </div>
  14. <div class=”errorBar”>
  15. <div class=”icon”><img src=”icon.png” alt=”icon” /></div>
  16. <div class=”message”><span>This is an error message</span></div>
  17. </div>
  18. </div>

That’s an example of how a form might be marked up, modified slightly for illustrative purposes. I’m sure you’ll agree it’s pretty ugly and if you had a long form you’d end up with a fairly long ugly page. It’s be nicer if you could just put this in your HTML.

  1. <div class=”field”>This is field 1</div>
  2. <div class=”field”>This is field 2</div>
  3. <div class=”field”>This is field 3</div>
  4. <div class=”field”>This is field 4</div>
  5. <div class=”field”>This is field 5</div>

All you have to do is a bit of jQuery manipulation to add all the ugly HTML back in. Like this…

  1. $(document).ready(function() {
  2. $(‘.field’).before(‘<div class=”fieldOuter”><div class=”inner”>’);
  3. $(‘.field’).after(‘</div><div class=”errorBar”><div class=”icon”>
  4. <img src=”icon.png” alt=”icon” /></div><div class=”message”>
  5. <span>This is an error message</span></div></div></div>’);
  6. });

It’s not always advisable to do this, you’ll get a bit of a flash as the page loads, but in certain situations where you’ve got a lot of repeated HTML it can really reduce your page weight and the SEO benefits of reducing all your repeated extraneous markup should be obvious.

17. Lazy load para el contenido para beneficios de velocidad y beneficios SEO

Another way to speed up your page loads and neaten up the HTML that search spiders see is to lazy load whole chunks of it using an AJAX request after the rest of the page has loaded. The user can get browsing right away and spiders only see the content you want them to index.

We’ve used this technique on our own site. Those purple buttons at the top of the page drop down 3 forms, directions and a google map, which was doubling the size of our pages. So, we just put all that HTML in a static page and use the load() function to load it in once the DOM was ready. Like this…

  1. $(‘#forms’).load(‘content/headerForms.html’, function() {
  2. // Code here runs once the content has loaded
  3. // Put all your event handlers etc. here.
  4. });

I wouldn’t use this everywhere. You have to consider the trade offs here. You’re making extra requests to the server and portions of your page might not be available to the user right away, but used correctly it can be a great optimization technique.

18. Utiliza funciones de utility de jQuery

jQuery isn’t just about flash effects. The creator has exposed some really useful methods which fill a few gaps in JavaScript’s repertoire.

http://docs.jquery.com/Utilities

In particular, browser support for certain common array functions is patchy (IE7 doesn’t even have an indexOf() method!). Jquery has methods for iterating, filtering, cloning, merging and removing duplicates from Arrays.

Other common functions that are difficult in Javascript include getting the selected item in a drop down list. In plain old JavaScript you’d have to get the <select> element using getElementByID, get the child elements as an array and iterate through them checking whether each one was selected or not. jQuery makes it easy…

  1. $(‘#selectList’).val();

It’s worth spending some time looking through the jQuery documentation on the main site and having a nose around some of the lesser known functions.

19. Utiliza noconflict para renombrar el objeto jquery cuando se usan otros frameworks

Most javascript frameworks make use of the $ symbol as a shorthand and this can cause clashes when trying to use more than one framework on the same page. Luckily there’s a simple solution. The .noconflict() function gives control of the $ back and allows you to set your own variable name, like this…

var $j = jQuery.noConflict();
$j('#myDiv').hide();

20. Como decir cuando las imágenes han terminado de cargarse

This is another one of those problems that doesn’t seem to be as well documented as it should be (not when I went looking anyway) and it’s a fairly common requirement when building photo galleries, carousels etc, but it’s fairly easy.

All you have to do is use the .load() method on an IMG element and put a callback function in it. The following example changes the “src” attribute of an image tag to load a new image and attaches a simple load function.

$('#myImage').attr('src', 'image.jpg').load(function() {
	alert('Image Loaded');
});

You should find that the alert is called as soon as the image is loaded.

21. Utiliza siempre la ultima version

jQuery is constantly improving and John Resig, it’s creator, always seems to be in search of ways to improve performance.

jQuery is currently on version 1.2.6 but John has already revealed that he’s working on a new selector engine called Sizzle, which may apparently improve selector speeds in Firefox by up to 4x. So, it pays to keep up to date.

22. Como comprobar si un elemento existe

You don’t need to check if an element exists on the page before you manipulate it because jQuery will will simply do nothing if you try to select something and it isn’t in the DOM. But when you do need to check if anything has been selected, or how many items have been selected you can use the length property.

if ($('#myDiv).length) {
	// your code
}

Simple, but not obvious.

23. Añade un clase JS a tu atributo HTML

I learned this tip from Karl Swedberg whose excellent books I used to learn jQuery.

He recently left a comment on one of my previous articles about this technique and the basics are as follows…

Firstly, as soon as jQuery has loaded you use it to add a “JS” class to your HTML tag.

  1. $(‘HTML’).addClass(‘JS’);

Because that only happens when javascript is enabled you can use it to add CSS styles which only work if the user has JavaScript switched on, like this…

  1. .JS #myDiv{display:none;}

So, what this means is that we can hide content when JavaScript is switched on and then use jQuery to show it when necessary (e.g. by collapsing some panels and expanding them when the user clicks on them), while those with JavaScript off (and search engine spiders) see all of the content as it’s not hidden. I’ll be using this one a lot in the future.

To read his full article click here.

24. Retorna ‘false’ para prevenir el comportamiento por defecto

This should be an obvious one but maybe not. if you have a habit of doing this…

  1. <a href=”#” class=”popup”>Click me!</a>

… and then attaching an event handler like this…

  1. $(‘popup’).click(function(){
  2. // Launch popup code
  3. });

… it’ll probably work fine until you use it on a long page, at which point you’ll notice that the # is causing it to jump to the top of the page when your click event is triggered.

All you have to do to prevent this default behaviour, or indeed any default behaviour on any event handler is to add “return false;” to your handler, like this…

  1. $(‘popup’).click(function(){
  2. // Launch popup code
  3. return false;
  4. });

25. Abreviatura para el evento ready

A small tip this one but you can save a few characters by using shorthand for the $(document).ready function.

Instead of this…

  1. $(document).ready(function (){
  2. // your code
  3. });

You can do this…

  1. $(function (){
  2. // your code
  3. });

Aplicación completa II : Utilizando el API de HTTP

(Fuente: http://www.javacodegeeks.com/2010/10/android-full-app-part-2-using-http-api.html)

En la primera parte de esta serie hemos creado el interfaz básico para la actividad principal de la aplicación. En esta parte vamos a ver cómo utilizar un API HTTP externo y cómo integrar las posibilidades de búsqueda dentro de nuestra aplicación.

El TMDb API

Para la búsqueda de actores y películas vamos a utilizar el TMDb API (http://api.themoviedb.org/2.1). Según la definición oficial:“El TMDbAPI es un recurso potente para todos los programadores que quieren integrar datos de películas junto con posters o chismes de películas. Todos los métodos API están disponibles en XML, YAML y JSON”.

Como la mayoría de los APIs disponibles, necesitas un valid key para poder utilizar el API. El primer paso para eso es crearse un cuenta gratuito en la página http://www.themoviedb.org/account/signup. Después de registrarte, haz logging en tu cuenta y encuentra el link para generar un API key. En mi caso me registro ,y después de rellenar un formulario me dicen que me la enviaran en 3 días laborables.

La lista de los métodos disponibles en el API los puedes encontrar en la documentación del TMDb aPI y los más importantes son las siguientes:

  • Movie.search: proporciona la forma más fácil y rápida de buscar una película.Para buscar info sobre la peli “Transformers” ejemplo de URL es el siguiente:

http://api.themoviedb.org/2.1/Movie.search/en/xml/APIKEY/Transformers

  • Person.search: se utiliza para buscar por un actor, actriz o miembro de producción, un ejemplo de búsqueda de actores:

http://api.themoviedb.org/2.1/Person.search/en/xml/APIKEY/Brad+Pitt

(donde APIKEY debe ser reemplazado por un API key válida)

Como puedes ver, el API es fácil de utilizar. Sólo hay que hacer la request HTTP con las URL especificadas y entonces recuperar las respuestas en un formato predefinido. Proximamente, vamos a ver las posibilidades de networking del Android para utilizar el API y recoger y presentar los datos proporcionados. Observese que utilizaremos el formato XML para las respuestas, aunque esto lo veremos en el siguiente artículo de la serie.

Haciendo peticiones HTTP

Para manipular las HTTP requests/responses en un entorno Android, las clases estándar del paquete java.net pueden ser utilizadas. Asi, clases como URL, URLConnection, HttpURLConnection etc todas pueden ser utilizadas de la forma ya conocida. Sin embargo, si queremos despreocuparnos por los detalles de bajo nivel podemos utilizar las Apache HTTP Client libraries. Estas librerías están basadas en el ya conocido Apache Commons HTTP Client frameworkhttp://hc.apache.org/

Empezemos con el código. Crearemos una clase llamada “HttpRetriever” que será responsable de realizar todas las HTTP requests y retornará las respuestas tanto en formato texto como en stream (para manipulación de imágenes). El código para esta clase es el siguiente:

package com.jes;

import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import com.jes.io.FlushedInputStream;
import com.jes.util.Utils;

public class HttpRetriever {

	private DefaultHttpClient client = new DefaultHttpClient();

	public String retrieve(String url) {
		HttpGet getRequest = new HttpGet(url);

		try {
			HttpResponse getResponse = client.execute(getRequest);
			final int statusCode = getResponse.getStatusLine().getStatusCode();

			if (statusCode != HttpStatus.SC_OK) {
				Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
				return null;
			}

			HttpEntity getResponseEntity = getResponse.getEntity();
			if (getResponseEntity != null) {
				return EntityUtils.toString(getResponseEntity);
			}
		} catch (IOException e) {
			getRequest.abort();
			Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
		}

		return null;

	}

	public InputStream retrieveStream(String url) {
		HttpGet getRequest = new HttpGet(url);
		try {
			HttpResponse getResponse = client.execute(getRequest);
			final int statusCode = getResponse.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
				return null;
			}

			HttpEntity getResponseEntity = getResponse.getEntity();
			return getResponseEntity.getContent();
		}catch (IOException e) {
			getRequest.abort();
			Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
		}

		return null;
	}

	public Bitmap retrieveBitmap(String url) throws Exception {
		InputStream inputStream = null;
		try {
			inputStream = this.retrieveStream(url);
			final Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
			return bitmap;
		}finally {
			Utils.closeStreamQuietly(inputStream);
		}	

	}

}

Para la ejecución de las peticiones HTTP, estamos utilizando una instancia de la clase DefaultHttpClient, la cual , como su nombre indica, es la implementación por defecto de un cliente HTTP, es decir, la implementación por defecto del interface HttpClient. El HTTP client ejecuta la request y proporciona un objeto HttpResponse que contiene la respuesta del servidor además de cualquier otra información.

Por ejemplo, podemos recuperar el response status code y compararlo el código con el código HttpStatus.SC_OK para ver si la petición ha ido bien. Cuando la petición ha ido bien, tomamos la referencia del objeto HttpEntity que está anidado desde el cual podemos tener acceso a los datos de la respuesta.

Para respuestas de texto convertimos la entity a String utilizando un método de la EntityUtils. Si deseamos recuperar los datos como un byte stream (por ejemplo para cuando nos bajemos un binario), utilizaremos el método getContent de la clase HttpEntity, que crea un nuevo objeto InputStream de la entity.

Observese que hay también un tercer método para retornar directamente objetos Bitmap. Esto puede ser útil en las últimos artículos de esta serie, donde descargaremos imágenes de internet. En ese método, ejecutaremos una GET request y recuperaremos un InputStream como siempre. Entonces, utilizaremos un método decodeStream de la clase BitmapFactory para crear un nuevo objeto Bitmap. Noteseque no proporcionamos directamente el InputStream descargado, sino que primero lo envolvemos en una clase FlushedInputStream. (En los foros de Android developers , se comenta que hay un bug en versiones previas del método decodeStream que puede causar problemas a la hora de descargar una imagen en una conexión lenta. Con la clase FlushedInputStream, que extiende FilterInputStream, se utiliza para saltarnos ese bug). El código de FlushedInputStream es el siguiente:

package com.javacodegeeks.android.apps.moviesearchapp.io;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FlushedInputStream extends FilterInputStream {
	public FlushedInputStream(InputStream inputStream) {
		super(inputStream);
	}

	@Override
	public long skip(long n) throws IOException {
			long totalBytesSkipped = 0L;
			while (totalBytesSkipped < n) {
				long bytesSkipped = in.skip(n - totalBytesSkipped);
				if (bytesSkipped == 0L) {
				int b = read();
				if (b < 0) {
					break;  // we reached EOF
				} else {
					bytesSkipped = 1; // we read one byte
				}
			}
			totalBytesSkipped += bytesSkipped;
		}
		return totalBytesSkipped;
	}

}

Con el método skip() sobrecargado nos aseguramos que de hecho se coge el número proporcionado de bytes, a menos que se llegue al final del fichero. Finalmente, utilizaremos el método closeStreamQuietly de la clase Utils para manejar las excepciones que pueden ocurrir cuando cerramos un InputStream. El código es el siguiente:

package com.javacodegeeks.android.apps.moviesearchapp.util;

import java.io.IOException;
import java.io.InputStream;

public class Utils {
	public static void closeStreamQuietly(InputStream inputStream) {
		try {
			if (inputStream != null) {
				inputStream.close();
			}
		} catch (IOException e) {
			// ignore exception
		}
	}
}

Dando permisos para realizar HTTP requests

Finalmente, para realizar las HTTP requests deben darse los permisos correspondientes. Asi , añadimos el android.permission.INTERNET al AndroidManifest.xml del proyecto, quedando el archivo como sigue:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
			package="com.javacodegeeks.android.apps.moviesearchapp"
			android:versionCode="1"
			android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">
	<activity android:name=".MovieSearchAppActivity" android:label="@string/app_name">
		<intent-filter>
			<action android:name="android.intent.action.MAIN" />
			<category android:name="android.intent.category.LAUNCHER" />
		</intent-filter>
	</activity>
</application>

<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

</manifest>

Asi , tenemos preparada la infraestructura para ejecutar HTTP GET requests, En los siguiente tutos, utilizaremos estas clases para recuperar datos XML e imágenes según las necesidades de nuestra aplicación.

Android Aplicación completa I : Interfaz gráfica

(Fuente: http://www.javacodegeeks.com/2010/10/android-full-app-part-1-main-activity.html)

Esta es la primera parte de una serie de artículos para construir una aplicación completa en Android. La aplicación que  se va a realizar  es un servicio de búsqueda fácil de actores y películas a través de internet. En esta primera parte vamos a configurar el proyecto Eclipse, prepararemos el interfaz de usuario para la principal actividad y finalmente lo probamos en un emulador de Android apropiado.

Configurando el proyecto Eclipse

Suponiendo que tenemos ya instalado todo para programar en Android , empecemos creando un nuevo proyecto Eclipse. Al proyecto lo llamaremos ‘AndroidSupermocoFinder y la aplicación se llamará “SupermocoFinderApp”. Observese que el Android 1.5 (API de nivel 3) se utiliza como la plataforma target, porque no utilizaremos ninguno de los últimos APIs.

Definiendo el interfaz de usuario

Nuestro interfaz de usuario será simple:

  • Una textbox donde el usuario  introduce la query de búsqueda
  • Dos radiobuttons indicando si es una búsqueda de peli o de actor
  • Una label para mostrar el tipo de búsqueda
  • Y un botón para realizar la búsqueda. Los resultados de la búsqueda serán presentados en otro activity (esto será discutido luego).

Como probablemente sabes, el interfaz se crea via un fichero XML para así tener independizados la vista de presentación de la lógica de la aplicación. El fichero correspondiente se llama “main.xml” y está en la carpeta “res/layout”. Lo abrimos e introducimos el siguiente contenido:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">

	<EditText android:id="@+id/search_edit_text"
		android:text="@string/search"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"	/>

	<RadioGroup
			android:id="@+id/search_radio_group"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:orientation="vertical">

			<RadioButton
			android:id="@+id/movie_search_radio_button"
			android:checked="true"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:text="@string/movies" />

			<RadioButton
			android:id="@+id/people_search_radio_button"
			android:checked="false"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:text="@string/people" />

	</RadioGroup>

	<TextView
		android:id="@+id/search_type_text_view"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:textColor="#ffffff"/>

	<Button
		android:id="@+id/search_button"
		android:text="@string/search"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"/>

</LinearLayout>

Observe que los elementos que muestran cadenas no están hard-coded, sino que sus valores son tomados de recursos externos y más específicamente de un fichero llamado “strings.xml” que reside en la carpeta “res/values”.Esta es una buena práctica para tener la internacionalización preparada para tu aplicación. El fichero es el siguiente:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<string name="hello">Hello World, MovieSearchAppActivity!</string>
	<string name="app_name">MovieSearchApp</string>
	<string name="search">Search</string>
	<string name="movies">Movies</string>
	<string name="people">People</string>
</resources>

Podemos arrancar ya la aplicación en un emulador apropiado para ver cómo va quedando:

Integrando el interfaz gráfico con el código

Localizar elementos del UI

El siguiente paso es enganchar estos elementos UI en nuestro código y manipularlos para que estén acordes con nuestra funcionalidad de búsqueda. Este enganche es posible a través del método findViewById , que recibe un parámetro integer que es un Id unívoco , ese Id se lo dimos en el main.xml.

Listeners de los UI

Un aspecto muy importante de los widgets UI de Android es que tiene listeners que permiten programarlos para que ser notificados cuando el usuario realiza alguna acción, tal como hacer click en un botón. Para manejar el evento de clicking, implementamos el interfaz OnClickListener, que define un callback que será invocado cuando una vista sea clicada. El interfaz contiene sólo un método llamado onClick, que es invocado cuando la vista es clicada.

Otro interfaz útil es el OnFocusChangeListener, que define un callback para ser invocado cuando el estado del foco de una view es cambiado. Su único método es onFocusChange, que es invocado cuando cambia el estado del foco del elemento o view.

Veamos cómo se aplican estos listeners en nuestro ejemplo. El código para nuestra clase main principal es la siguiente:

package com.jes;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

public class SMFinderActivity extends Activity {

	private static final String EMPTY_STRING = "";
	private EditText searchEditText;
	private RadioButton moviesSearchRadioButton;
	private RadioButton peopleSearchRadioButton;
	private RadioGroup searchRadioGroup;
	private TextView searchTypeTextView;
	private Button searchButton;

	@Override
	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		this.findAllViewsById(); 

		moviesSearchRadioButton.setOnClickListener(radioButtonListener);
		peopleSearchRadioButton.setOnClickListener(radioButtonListener);
		searchButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				String query = searchEditText.getText().toString();
				if (moviesSearchRadioButton.isChecked()) {
					longToast(moviesSearchRadioButton.getText() + " " + query);
				}
				else if (peopleSearchRadioButton.isChecked()) {
					longToast(peopleSearchRadioButton.getText() + " " + query);
				}
			}
		});

		searchEditText.setOnFocusChangeListener(new DftTextOnFocusListener(getString(R.string.search)));
		int id = searchRadioGroup.getCheckedRadioButtonId();
		RadioButton radioButton = (RadioButton) findViewById(id);

		searchTypeTextView.setText(radioButton.getText());
	}

	private void findAllViewsById() {
		searchEditText = (EditText) findViewById(R.id.search_edit_text);
		moviesSearchRadioButton = (RadioButton) findViewById(R.id.movie_search_radio_button);
		peopleSearchRadioButton = (RadioButton) findViewById(R.id.people_search_radio_button);
		searchRadioGroup = (RadioGroup) findViewById(R.id.search_radio_group);
		searchTypeTextView = (TextView) findViewById(R.id.search_type_text_view);
		searchButton = (Button) findViewById(R.id.search_button);
	}

	public void longToast(CharSequence message) {
		Toast.makeText(this, message, Toast.LENGTH_LONG).show();
	}

	private OnClickListener radioButtonListener = new OnClickListener() {
		public void onClick(View v) {
			RadioButton radioButton = (RadioButton) v;
			searchTypeTextView.setText(radioButton.getText());
		}

	};

	private class DftTextOnFocusListener implements OnFocusChangeListener {
		private String defaultText;
		public DftTextOnFocusListener(String defaultText) {
			this.defaultText = defaultText;
		}

		public void onFocusChange(View v, boolean hasFocus) {
			if (v instanceof EditText) {
				EditText focusedEditText = (EditText) v;
				// handle obtaining focus
				if (hasFocus) {
					if (focusedEditText.getText().toString().equals(defaultText)) {
						focusedEditText.setText(EMPTY_STRING);
					}
				}
				// handle losing focus
				else {
					if (focusedEditText.getText().toString().equals(EMPTY_STRING)) {
						focusedEditText.setText(defaultText);
					}
				}
			}
		}
	}
}

Empezamos configurando la View para nuestra actividad utilizando el método setContentView. El view usado es el definido por el main.xml.

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Entonces, tomamos referencia de todos los elementos UI asi que podamos manipularlos via código

private void findAllViewsById() {
	searchEditText = (EditText) findViewById(R.id.search_edit_text);
	moviesSearchRadioButton = (RadioButton) findViewById(R.id.movie_search_radio_button);
	peopleSearchRadioButton = (RadioButton) findViewById(R.id.people_search_radio_button);
	searchRadioGroup = (RadioGroup) findViewById(R.id.search_radio_group);
	searchTypeTextView = (TextView) findViewById(R.id.search_type_text_view);
	searchButton = (Button) findViewById(R.id.search_button);
}

Creamos dos OnclickListeners, uno para manejar los clicks de los radio buttons y otro para la ejecución de la búsqueda cuando se hace click sobre el botón. Los listeners son enganchados a los elementos UI utilizando el método setOnclickListener.

moviesSearchRadioButton.setOnClickListener(radioButtonListener);
peopleSearchRadioButton.setOnClickListener(radioButtonListener);

searchButton.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						String query = searchEditText.getText().toString();
						if (moviesSearchRadioButton.isChecked()) {
							longToast(moviesSearchRadioButton.getText() + " " + query);
						} else if (peopleSearchRadioButton.isChecked()) {
							longToast(peopleSearchRadioButton.getText() + " " + query);
						}
					}
});

private OnClickListener radioButtonListener = new OnClickListener() {
						public void onClick(View v) {
							RadioButton radioButton = (RadioButton) v;
							searchTypeTextView.setText(radioButton.getText());
						}
};

Como los radiobuttons están definidos dentro de un componente RadioGroup, el framework de Android es el que se encarga de permitir que sólo esté seleccionado a la vez. En tiempo de ejecución , podemos encontrar qué radio button está seleccionado utilizando el método getCheckedRadioButtonId. Observese que este método retorna una ID único global de el radiobutton y puede ser utilizado como argumento del método findViewById para tener referencia del botón.

Finalmente, creemos un  OnFocusChangeListener y lo enganchamos al widget EditText utilizando el método setOnFocusChangeListener:

searchEditText.setOnFocusChangeListener(new DftTextOnFocusListener(getString(R.string.search)));

Con esta implementación , queremos algo como lo siguiente:

Cuando la text box tiene el foco y está vacía, estás preparado para teclear la query de búsqueda. La query permanece allí tanto si la caja de texto tiene el foco como si no lo tiene. Sin embargo, cuando la caja de texto está vacía y pierde el foco, aparece un mensaje predefinido (con un texto que sacamos del strings.xml).

Primera ejecución

Estamos ahora preparados para darle a nuestra aplicación una primera ejecución. Esto lo haremos utilizando un emulador apropiado delAndroid SDK. Lanzamos el AVD (Android Virtual Device) Manager desde el Eclipse y creamos un nuevo device. Le damos un nombre que sea distintivo, por ejemplo “Android1.5-SD” y elegimos la plataforma target, en nuestro caso Android 1.5. También hemos elegido soporte para la SD card, solo por si lo necesitamos.Así es como queda el setup:

Ahora creamos un nueva “Run configuration” de Eclipse, elige nuestro proyecto Android y la “SupermocoFinderAppActivity” para arrancar. Esto es lo que debería salirnos:

En la pestaña “Target” , elegimos el nuevo AVD creado , aplicamos y ejecutamos. Tarda un rato , desbloqueamos y la aplicación aparecerá. Juega un poco con la aplicación , en este momento no realiza nada avanzado, tan solo sale una ventana cuando se le da a buscar con los valores introducidos.

Archivos fuentes utilizados

JSON Introducción

JSON es el acrónimo de JavaScript Object Notation.JSON es un formato alternativo de envío y recepción de datos, es decir remplaza a XML o el envío de texto plano.Este formato de datos es más liviano que XML.Veremos que hace el código más sencillo ya que utiliza el código JavaScript como modelo de datos.

Repaso de arrays literales y objetos literales en Javascript

Tenemos que repasar un poco como se definen los array literales y objetos literales en JavaScript, ya que serán las estructuras para la transmisión de datos:

var usuario=['juan',26];

Como vemos los elementos de un array literal se encierran entre corchetes y los valores contenidos van separados por coma.Cuando definimos un array literal no le indicamos a cada elemento de que tipo se trata, podemos almacenar cadenas (entre comillas), números, valores lógicos (true,false) y el valor null.Paraacceder a los elementos de un array literal lo hacemos por su nombre y entre corchetes indicamos que elementos queremos acceder:

alert(usuario[0]); //Imprimimos el primer elemento del array
alert(usuario[1]); //Imprimimos el segundo elemento del array

Veamos como definimos los objetos literales en javascript:

var persona={
	'nombre':'juan',
	'clave':'xyz',
	'edad':26
};

Los objetos literales se definen por medio de pares “nombre”:”valor”.Todo objeto literal tiene un nombre, en el ejemplo le llamé persona. Un objeto literal contiene una serie de propiedades con sus respectivos valores. Todas las propiedades del objetos se encuentran encerradas entre llaves. Luego cada propiedad y valor se las separa por dos puntos. Y por último cada propiedad se las separa de las otras propiedades por medio de la coma.Para acceder a las propiedades del objeto literal lo podemos hacer de dos formas:

alert(persona.nombre); //Imprime el valor de la propiedad nombre del objeto persona.

La segunda forma es indicando la propiedad entre corchetes:

alert(persona['nombre']);

Luego se pueden combinar objetos literales y array literales:

var persona={
	'nombre':'juan',
	'edad':22,
	'estudios':['primario','secundario']
};

Como podemos ver podemos crear estructuras de datos complejas combinando objetos literales y array literales.Luego para acceder a los distintos elementos tenemos:

alert(persona.nombre);
alert(persona.estudios[0]);
alert(persona.estudios[1]);

Sintaxis JSON

La sintaxis de JSON difiere levemente de lo visto anteriormente:

{
	'nombre':'juan',
	'edad':22,
	'estudios':['primario','secundario']
}

Como podemos ver en la sintaxis JSON no aparecen variables, sino directamente indicamos entre llaves las propiedades y sus valores.Tambien hemos eliminado el punto y coma luego de la llave final. El resto es igual.

Diferencia entre JSON y XML

Ahora veamos la diferencia entre JSON y XML utilizando este ejemplo:

XML:

<persona>
	<nombre>juan</nombre>
	<edad>22</edad>
	<estudios>
		<estudio>primario</estudio>
		<estudio>secundario</estudio>
	</estudios>
</persona>

Y como vimos en JSON:

{
	“nombre”:”juan”,
	“edad”:22,
	“estudios”:[“primario”,”secundario”]
}

Podemos ver que es mucho más directa la definición de esta estructura (de todos modos cuando la estructura a representar es muy compleja XML sigue siendo la opción principal).Como podemos ver si tenemos que transmitir estas estructuras por internet la notación JSON es más liviana.

Leer datos JSON en Javascript

Otra ventaja es como recuperamos los datos en el navegador, como vimos si se trata de un archivo XML llamamos al método requestXML y luego accedemos por medio del DOM.En cambio con JSON al llegar el archivo procedemos a generar una variable en JavaScript que recree el objeto literal, esto mediante la función eval:

var persona=eval('(' + conexion1.responseText + ')');

Ya veremos en el próximo concepto como recuperar los datos del servidor mediante el objeto XMLHttpRequest.

Ejemplo

Para probar y generar un objeto a partir de una notación JSON haremos el siguiente problema: Confeccionar una página que contenga un botón. Al ser presionado evaluar un string que almacena un objeto literal con notación JSON. El objeto literal debe representar las características de una computadora (procesador, memoria ram, capacidad de cada disco duro)

Mostrar los datos mediante el método alert.Hay que tener bien en cuenta que en este problema no hay nada de AJAX ya que no nos comunicaremos con el servidor para el envío de datos.

pagina1.html

<html>
<head>
	<title>Problema</title>
	<script src="funciones.js" language="JavaScript"></script>
</head>
<body>
	<h1>Evaluar una variable que contiene notación JSON.</h1>
	<input type="button" id="boton1" value="Ver">
</body>
</html>

funciones.js

addEvent(window,'load',inicializarEventos,false);

function inicializarEventos()
{
	var ob=document.getElementById('boton1');
	addEvent(ob,'click',presionBoton,false);
}

function presionBoton(e)
{
	var cadena="{ 'microprocesador':'pentium'," +
							" 'memoria':1024," +
							" 'discos':[80,250]" +
							" }";

	var maquina=eval('(' + cadena + ')');
	alert('microprocesador:'+maquina.microprocesador);
	alert('Memoria ram:'+maquina.memoria);
	alert('Capacidad disco 1:'+maquina.discos[0]);
	alert('Capacidad disco 2:'+maquina.discos[1]);
}

//***************************************
//Funciones comunes a todos los problemas
//***************************************
function addEvent(elemento,nomevento,funcion,captura)
{
	if (elemento.attachEvent)	{
		elemento.attachEvent('on'+nomevento,funcion);
		return true;
	} else if (elemento.addEventListener) {
		elemento.addEventListener(nomevento,funcion,captura);
		return true;
	}	else
		return false;
}

Cuando se presiona el botón se ejecuta la función presionBoton. En esta lo primero que hacemos definimos un string que contiene un objeto con notación JSON:

var cadena="{ 'microprocesador':'pentium'," +
							" 'memoria':1024," +
							" 'discos':[80,250]" +
							" }";

Seguidamente pasamos a evaluar este string:

var maquina=eval('(' + cadena + ')');

Ahora si tenemos un objeto JavaScript. Esto se logra utilizando la función eval de JavaScript. Es importante que siempre al string que contiene la notación JSON le debemos anteceder el paréntesis de apertura y finalizarlo con el paréntesis de cerrado (esto para que JavaScript no tenga problemas con las llaves de apertura y cierre de la notación JSON.Una vez que tenemos el objeto en JavaScript procedemos a acceder a sus atributos:

alert('microprocesador:'+maquina.microprocesador);
alert('Memoria ram:'+maquina.memoria);
alert('Capacidad disco 1:'+maquina.discos[0]);
alert('Capacidad disco 2:'+maquina.discos[1]);

 

Llaves, corchetes, dos puntos y comas

Las llaves actuan de ‘contenedores’.Los corchetes almacenan arrays ,es decir delimitan arrays.Names y values son separados por dos puntos.Los elementos de un array son separados por comas

Piensa en JSON como un ‘XML con Anorexia’

O también se pueden ver como ‘ficheros INI con jerarquia’.

JSON es similar a XML por lo siguiente:

  • Ambos tienen significado ‘autodescriptivo’, es decir los valores están nombrados, y eso lo hace muy legible
  • Ambos tienen una estructura jerárquica (es decir puedes tener valores dentro de valores)
  • Ambos pueden ser parseados y utilizados en la mayoría de los lenguajes de programación
  • Ambos pueden ser pasados por AJAX (es decir HttpWebRequest)

JSON es distinto de XML por lo siguiente:

  • XML utiliza ‘<‘ y ‘>’ ,con un nombre de tag al comienzo y al final del elemento. JSON utiliza llaves con el nombre sólo al principio del elemento.
  • JSON es mas simple, luego es más rápido de escribir a los humanos, y también más fácil de leer.
  • JSON puede ser parseado trivialmente utilizando el procedimiento ‘eval()’ de Javascript
  • JSON puede incluir arrays (donde los elementos no tienen que tener unname cada uno)
  • En XML puedes utilizar cualquier nombre que quieras para un elemento, en JSON no pueden utilizar palabras reservadas de Javascript.

Por qué es bueno utilizar JSON?

Cuando estamos escribiendo código JSON, si utilizamos JSON eliminamos el tener que escribir a mano XML, lo cual es más rápido. JSON parece más fácil de utilizar:

Aproximación XML Aproximación JSON
Recupera un documento XML 

Navega por el documento, recuperando valores que necesites

Haz algo con estos valores

Recupera una cadena JSON 

‘eval’ el JSON

 

Es JSON orientado a objetos?

No estrictamente. JSON proporciona una buena técnica de encapsulamiento, que puedes utilizar para separar valores y funciones, pero no hay nada de herencia, polimorfismo, interfaces, etc.

Se utiliza solo JSON en el lado del cliente?

Si y no. En el lado de servidor se puede serializar / deserializar objetos a/desde JSON. Los programadores .net pueden utilizar librerias como Json.net que hace esto automáticamente.

(Other side note: Jason and Ajax were both mythical greek heroes. Prediction: other forthcoming technology jargon will include: Heracles, Perseus, Deucalion, Theseus and Bellerophon.)

Dojo: Hola Mundo

[Fuente: http://dojotoolkit.org/documentation/tutorials/1.6/hello_dojo/]

En este tuto cargaremos DOJO en una pagina HTML simple, poniendo algunas de las funciones básicas de DOJO a funcionar. Tocaremos la estructura modular de DOJO y discutiremos como cargar dependencias para tener un experiencia de usuario más rica.

  • Dificultad: principiante
  • Dojo Version: 1.6

Introducción

Nuestro punto de comienzo es una pagina HTML simple. Queremos cargar DOJO en esa pagina y añadir algun codigo que muestre que está bien cargado.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tutorial: Hello Dojo!</title>
<!-- load Dojo -->
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>
</head>
<body>
<h1 id="greeting">Hello</h1>
</body>
</html>

View Demo

Vemos como hemos enganchado la libreria dojo.js via CDN. Ahora necesitamos algón código para que Dojo este preparado para funcionar y podamos hacer algo con él.

dojo.ready

Si jquery tiene el document.ready , pues Dojo tiene el dojo.ready. Es decir es el método para saber cuando el DOM del HTML  se ha cargado y todas las librerias (incluida Dojo) han sido cargadas. Al dojo.ready le pasamos una función y la función se ejecutará cuando llegue el momento ready:

 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tutorial: Hello Dojo!</title>
<!-- load Dojo -->
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>
<script>
dojo.ready(function(){
alert("Dojo version " + dojo.version + " is loaded");
});
</script>
</head>
<body>
<h1 id="greeting">Hello</h1>
</body>
</html>

 

View Demo

En vez del alert utilicemos una función de Dojo para ir cogiendo el gustillo.

 

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tutorial: Hello Dojo!</title>
<!-- load Dojo -->
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>
<script>
dojo.ready(function(){
dojo.byId("greeting").innerHTML += ", from " + dojo.version;
});
</script>
</head>
<body>
<h1 id="greeting">Hello</h1>
</body>
</html>

 

View Demo

Si tenemos más de una linea  en el dojo.ready es común utilizar una función init:

 

function init() {
alert("Dojo ready, version:" + dojo.version);
// More initialization here
}
dojo.ready(init);

 

NOTA: observar que al dojo.ready le pasamos el objeto función en si , sin comillas.

Módulos

Dojo es un toolkit modular, con un sistema de paquetes que te prmite cargar solo el código que necesites dentro de tu página y hacer que la gestión de dependencias sea más fácil. Para ello Dojo introduce el dojo.require para indicar la dependencia del módulo indicado.

De momento, apuntemos que cuando cargamos dojo.js, no estamos cargando el Dojo Toolkit entero, sólo los módulos básicos tales como el sistema de paquetes , el sistema de eventos, Ajax, DOM helpers y otras funcionalidades comunmente utilizadas.

Carga de módulos

Los básico de Dojo incluye un framework de animación para efectos visuales y un par de los efectos más comunes (el dojo.fadeOut y el dojo.fadeIn). Eso esta bien, pero nosotro queremos algo que haga que el saludo de nuestra pagina de ejemplo se deslice por la  pantalla. Para eso utilizaremos dojo.fx.slideTo. El módulo dojo.fx no está incluido en el dojo.js asi que necesitaremos cargarlo:

 

// New: Require in the dojo.fx module
dojo.require("dojo.fx");
// Remember, dojo.ready waits for both the DOM and all dependencies
dojo.ready(function(){
// The piece we had before - change our innerHTML
dojo.byId("greeting").innerHTML += ", from " + dojo.version;
// Now, slide the greeting
dojo.fx.slideTo({
top: 100,
left: 200,
node: dojo.byId("greeting")
}).play();
});

 

The slideTo effect we want is a part of the dojo.fx module. The dojo.require line states the dependency, and asks the loader to load the file if it is not already available. There’s no new script tag to fiddle with, and crucially, the rest of our initialization needn’t change — we still use dojo.readyand our code will only run once the DOM is ready and all dependencies are loaded.

The next part is to put what we loaded to use. Like all property animations in Dojo, we pass in an object with a node reference, and any other properties to configure the animation. We’ll be looking closer at animations in Dojo in a future tutorial.

View Demo

Conclusion

Getting started with the Dojo Toolkit is as simple as adding a script tag, but the broad scope of the toolkit is placed at your fingertips, as and when you need it. In this tutorial we’ve taken the first step towards putting Dojo to work in your web sites and applications. In future tutorials in this series we’ll visit each of the major groups of functionality — from DOM helpers to Ajax, effects, events and more — exploring and explaining each step of the way.

Dojo: gráficas

The dojox.charting permite a los programadores crear gráfics funcionales, únicas y dinámicas desde varios conjuntos de datos. Además, dojox.charting proporciona varios themes y chart types que permite a los programadores mostrar sus datos de caulquier forman que gusten. En este tuto mostraremos como crear basic charts con variedad de datos, plots , ejes y themes.

  • Dificultad: principiante
  • Dojo Version: 1.6

Introducción

La libreria de gráficas de Dojo vive dentro del recurso “dojox.charting“. La colección dojox.charting único en lo siguiente:

  • Permite crear charts con HTML (declarativamente) o con Javascript (programamaticamente)
  • Funciona en todos los dispositivos
  • Puede renderizar en SVG, VML, Silverlight y Canvas. Para que soporte SVGWeb se esta haciendo.
  • Permite a los programadores decidir qué tipo utilizar
  • Evalua el cliente y utiliza el render apropiado basandose en lo que el navegador del cliente soporta
  • Crea gráficas con dojox.gfx, una libreria de gráficas vectoriales potente capaz de hacer que tus gráficas tengan animación en una amplia variedad de formas.
  • Viene con una amplia variedad de themes atractivos
  • Permite utilizar gradientes radiales y lineales dentro de los chart themes (que incluso funcionan en IE!!)

Antes de crear estas gráficas, es importante hacer los recursos que utilizará la gráfica disponible dentro de la página.

Configurar dojox.charting

Como para utilizar cualquier recurso de Dojo Toolkit, es importante que utilicemos “dojo.require” para cargar todas las dependencias. Dos dependencias que siempre son necesarias son el recurso de gráfica y el theme deseado:

// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.widget.Chart2D");
// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.Claro");
// Any plugins we choose to use would be required here as well...

Si tenemos una prioridad específica de renderizado preferida, es posible añadir un dojoConfig object que sea creado antes de cargar el Dojo:

<script>
dojoConfig = {
parseOnLoad: true, //enables declarative chart creation
gfxRenderer: "svg,silverlight,vml" // svg is first priority
};
</script>
<script src="/path/to/dojo/dojo/dojo.js"></script>

Con estas minimas dependencias cargadas ahora nuestra aplicacion web está lista para crear gráficas.

Creando un gráfica básica

De forma declarativa

Hay dos formas de crear un gráfica básica: declarativamente o programaticamente. Antes de crear la gráfica, sin embargo, es importante primero crear o acceder a los datos que la formarán. Los siguientes son unos datos de ejemplo que vamos a utilizar para crear nuestro ejemplo básico:

// x and y coordinates used for easy understanding of where they should display
// Data represents website visits over a week period
chartData = [
{ x: "1", y: "19021" },
{ x: "1", y: "12837" },
{ x: "1", y: "12378" },
{ x: "1", y: "21882" },
{ x: "1", y: "17654" },
{ x: "1", y: "15833" },
{ x: "1", y: "16122" }
];

Con los datos formateados apropiadamente y disponibles , una gráfica creada declarativamente se parece a algo como esto:

<!-- create the chart -->
<div dojoType="dojox.charting.widget.Chart2D" theme="dojox.charting.themes.Claro" id="viewsChart" style="width: 550px; height: 550px;">
<!-- Pie Chart: add the plot -->
<div class="plot" name="default" type="Pie" radius="200" fontColor="#000" labelOffset="-20"></div>
<!-- pieData is the data source -->
<div class="series" name="Last Week's Visits" array="chartData"></div>
</div>

View Demo

Dojo Pie Chart

A pie chart usingthe Claro theme

El código entero del ejemplo anterior:

<html>
<head>
	<script>
		djConfig = {
			isDebug: true,
			parseOnLoad: true
		};
	</script>

	<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>
	<script>
		// Grab the parser
		dojo.require("dojo.parser");

		// Require the basic 2d chart resource: Chart2D
		dojo.require("dojox.charting.widget.Chart2D");

		// Require the theme of our choosing
		//"Claro", new in Dojo 1.6, will be used
		dojo.require("dojox.charting.themes.Claro");
		// Any plugins we choose to use would be required here as well...

		// x and y coordinates used for easy understanding of where they should display
		// Data represents website visits over a week period
		chartData = [
			{ x: "1", y: "19021" },
			{ x: "1", y: "12837" },
			{ x: "1", y: "12378" },
			{ x: "1", y: "21882" },
			{ x: "1", y: "17654" },
			{ x: "1", y: "15833" },
			{ x: "1", y: "16122" }
		];

	</script>

</head>
<body>
	<h1>Prueba de Dojo Charting</h1>	

	<!-- create the chart -->
	<div dojoType="dojox.charting.widget.Chart2D" theme="dojox.charting.themes.Claro" id="viewsChart" style="width: 550px; height: 550px;">
		<!-- Pie Chart: add the plot -->
		<div class="plot" name="default" type="Pie" radius="200" fontColor="#000" labelOffset="-20"></div>

		<!-- pieData is the data source -->
		<div class="series" name="Last Week's Visits" array="chartData"></div>
	</div>

</body>
</html>

Cuando creamos la gráfica de forma declarativa, los settings principales de la gráfica están dentro del nodo contenedor. Plots y series consiguen sus propios nodos con atributos de personalizacion conteniendo chart settings, como por ejemplo plugins y trozos de gráficas.

Nota importante: Aunque es ciertamente posible crear gráficas declarativamente, es altamente recomendado que los programadores los creen programaticamente. Todavia dojox.charting no soporta completamente los atributos “data-dojo” de Dojo 1.6

Programaticamente

Programaticamente la creación de gráficas requiere un poco de más código pero proporciona más estabilidad y control. La misma gráfica puede ser creada programaticamente con el código siguiente:

<script>
// When the DOM is ready and resources are loaded...
dojo.ready(function() {
	// Create the chart within it's "holding" node
	var pieChart = new dojox.charting.Chart2D("chartNode");
	// Set the theme
	pieChart.setTheme(dojox.charting.themes.Claro);
	// Add the only/default plot
	pieChart.addPlot("default", {
		type: "Pie",
		radius: 200,
		fontColor: "black",
		labelOffset: "-20"
	});
	// Add the series of data
	pieChart.addSeries("January",chartData);
	// Render the chart!
	pieChart.render();
});
</script>
<!-- chart will go here -->
<div id="chartNode" style="width: 550px; height: 550px;"></div>
View Demo

El código completo del ejemplo anterior es :

<html>
<head>
	<script>
		djConfig = {
			isDebug: true,
			parseOnLoad: true
		};
	</script>

	<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>

	<script>
		// Grab the parser
		dojo.require("dojo.parser");

		// Require the basic 2d chart resource: Chart2D
		dojo.require("dojox.charting.widget.Chart2D");

		// Require the theme of our choosing
		//"Claro", new in Dojo 1.6, will be used
		dojo.require("dojox.charting.themes.Claro");
		// Any plugins we choose to use would be required here as well...

		// x and y coordinates used for easy understanding of where they should display
		// Data represents website visits over a week period
		chartData = [
			{ x: "1", y: "19021" },
			{ x: "1", y: "12837" },
			{ x: "1", y: "12378" },
			{ x: "1", y: "21882" },
			{ x: "1", y: "17654" },
			{ x: "1", y: "15833" },
			{ x: "1", y: "16122" }
		];

		// When the DOM is ready and resources are loaded...
		dojo.ready(function() {
		    // Create the chart within it's "holding" node
		    var pieChart = new dojox.charting.Chart2D("chartNode");
		    // Set the theme
		    pieChart.setTheme(dojox.charting.themes.Claro);
		    // Add the only/default plot
		    pieChart.addPlot("default", {
		        type: "Pie",
		        radius: 200,
		        fontColor: "black",
		        labelOffset: "-20"
		    });
		    // Add the series of data
		    pieChart.addSeries("January",chartData);
		    // Render the chart!
		    pieChart.render();
		});
	</script>
</head>

<body>
	<!-- chart will go here -->
	<div id="chartNode" style="width: 550px; height: 550px;"></div>
</body>
</html>

Asignando colores a la gráfica sin utilizar Themes

Se hace pasandole colores como atributos en el metodo addSeries:

chart.addSeries("Monthly Sales - 2009",chartData2,{ stroke: "red", fill: "pink" });

Themes de gráficas

La Libreria de Dojo charting proporciona varios themes para que elijan los programadores.Los Themes varian en complejidad visual: algunos themes utilizan colores hexadecimales mientras otros más complejos utilizan lógica avanzada para calcular gradientes radiales o lineales para asi mejorar el look.

Todos los Themes pueden ser encontrados dentro del recurso dojox.charting.themes. Los Themes son ficheros javascript con datos especificos del Theme que representan. Lo siguiente es el código que crea el Theme “Miami Nice”:

// “Provide” the resource

dojo.provide("dojox.charting.themes.MiamiNice");
// Require the Theme class which is used by all themes
dojo.require("dojox.charting.Theme");
// Create a basic new theme with a list of solid colors
(function(){
	var dxc=dojox.charting;
	dxc.themes.MiamiNice=new dxc.Theme({
		colors: [
			"#7f9599",
			"#45b8cc",
			"#8ecfb0",
			"#f8acac",
			"#cc4482"
		]
	});
})();

Hay temas más complejos disponibles.Un ejemplo sería el theme “Claro” que utiliza gradientes y fuentes customizadas:

dojo.require("dojox.gfx.gradutils");
dojo.require("dojox.charting.Theme");

// created by Tom Trenka
(function(){
	
	var dc = dojox.charting, themes = dc.themes, Theme = dc.Theme, g = Theme.generateGradient,
	
	defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 100};
	
	themes.Claro = new dc.Theme({
		chart: {
			fill: {
					type: "linear",
					x1: 0, x2: 0, y1: 0, y2: 100,
					colors: [
						{ offset: 0, color: "#dbdbdb" },
						{ offset: 1, color: "#efefef" }
					]
			},
			
			stroke:    {color: "#b5bcc7"}
		},
		
		plotarea: {
			fill:{
					type: "linear",
					x1: 0, x2: 0, y1: 0, y2: 100,
					colors: [
						{ offset: 0, color: "#dbdbdb" },
						{ offset: 1, color: "#efefef" }
					]
			}
		},
		
		
		axis:{
			stroke: { // the axis itself
							color: "#888c76",
							width: 1
			},
		
			tick: { // used as a foundation for all ticks
				color: "#888c76",
				position: "center",
				font: "normal normal normal 7pt Verdana, Arial, sans-serif", // labels on axis
				fontColor: "#888c76" // color of labels
			}
		},
		
		series: {
			stroke:  {width: 2.5, color: "#fff"},
			outline: null,
			font: "normal normal normal 7pt Verdana, Arial, sans-serif",
			fontColor: "#131313"
		},
		
		marker: {
			stroke:  {width: 1.25, color: "#131313"},
			outline: {width: 1.25, color: "#131313"},
			font: "normal normal normal 8pt Verdana, Arial, sans-serif",
			fontColor: "#131313"
		},
		
		seriesThemes: [
			{fill: g(defaultFill, "#2a6ead", "#3a99f2")},
			{fill: g(defaultFill, "#613e04", "#996106")},
			{fill: g(defaultFill, "#0e3961", "#155896")},
			{fill: g(defaultFill, "#55aafa", "#3f7fba")},
			{fill: g(defaultFill, "#ad7b2a", "#db9b35")}
		],
		
		markerThemes: [
			{fill: "#2a6ead", stroke: {color: "#fff"}},
			{fill: "#613e04", stroke: {color: "#fff"}},
			{fill: "#0e3961", stroke: {color: "#fff"}},
			{fill: "#55aafa", stroke: {color: "#fff"}},
			{fill: "#ad7b2a", stroke: {color: "#fff"}}
		]
	});
	
		themes.Claro.next = function(elementType, mixin, doPost){
													var isLine = elementType == "line";
													if(isLine || elementType == "area"){
															// custom processing for lines: substitute colors
															var s = this.seriesThemes[this._current % this.seriesThemes.length],
															m = this.markerThemes[this._current % this.markerThemes.length];
															s.fill.space = "plot";
															if(isLine){
																s.stroke  = { width: 4, color: s.fill.colors[0].color};
															}
															m.outline = { width: 1.25, color: m.fill };
															var theme = Theme.prototype.next.apply(this, arguments);
															// cleanup
															delete s.outline;
															delete s.stroke;
															s.fill.space = "shape";
															return theme;
													} else if(elementType == "candlestick"){
														var s = this.seriesThemes[this._current % this.seriesThemes.length];
														s.fill.space = "plot";
														s.stroke  = { width: 1, color: s.fill.colors[0].color};
														var theme = Theme.prototype.next.apply(this, arguments);
														return theme;
													}
													return Theme.prototype.next.apply(this, arguments);
		};
		
		themes.Claro.post = function(theme, elementType){
													theme = Theme.prototype.post.apply(this, arguments);
													if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){
													theme.series.fill = dojox.gfx.gradutils.reverse(theme.series.fill);
													}
													return theme;
		};
})();

Whether the theme you implement (or create) is basic or complex, implementing the theme within your chart couldn’t be easier. Simply require the resource and call “setTheme” on the chart:

// Require the theme of our choosing
dojo.require("dojox.charting.themes.Claro");
// Create a chart
var chart = new dojox.charting.Chart2D("chartNode");
// Set the theme
chart.setTheme(dojox.charting.themes.Claro);

You may use any number of themes on a given page. Want to learn how to create a custom chart theme for your web application? Read Dive Into Dojo Chart Theming.

Componentes de gráficas: Plots , Ejes y Series

Definir una gráfica básica e implementar su theme es bastante simple. El trabajo real viene cuando tenemos que definir plots, ejes y series. Cada componente tiene si proposito especial.

Los Plots

Uno de los principales objetivos de los plots dentro del dojox.charting es definir el tipo de gráfica que debe ser añadida y proporcionar los valores para ese tipo especifico de chart. Los tipos por defecto que incluye dojox.charting en gráficas 2D son los siguientes:

  • Default – Universal line chart capable of rendering lines, fill areas under those lines, and placing markers at data points. This plot type is used if no plot type was specified when adding it to a chart.
  • Lines – Basic line chart. Uses Default.
  • Areas – Area under data line(s) will be filled. Uses Default.
  • Markers – Lines with markers. Uses Default.
  • MarkersOnly – Markers, sans lines. Uses Default.
  • Stacked – Data sets charted in relation to the previous data set. Extension of Default.
  • StackedLines – Stacked data sets using lines. Uses Stacked.
  • StackedAreas – Stacked data sets with filled areas under chart lines. Uses Stacked.
  • Bars – Horizontal bars.
  • ClusteredBars – Horizontal bars with clustered data sets. Uses Bars.
  • StackedBars – Stacked data sets with horizontal bars. Uses Bars.
  • Columns – Vertical bars.
  • ClusteredColumns – Vertical bars with clustered data sets. Uses Columns.
  • StackedColumns – Stacked data sets with vertical bars. Uses Columns.
  • Pie – The traditional pie chart.
  • Scatter – Similar to MarkerOnly, yet capable of charting using gradient fields.
  • Grid – For adding a grid layer to your chart.

You can see each chart type in action by visiting Dojo’s nightly charting tests.

Los Plots se añaden a las gráficas con el método addPlot, pasándole el nombre de la gráfica (generalmente “default” ) y opciones especificas del plot:

chart.addPlot("default",{
       // Add the chart type
	type: "Pie"
});

Algunas de las opciones de Plot estandars son:

  • type – The chart type (Pie, Bars, Scatter, etc.)
  • lines – Represents if lines should be added within the chart
  • markers – Represents if markers should be added to data points within the chart
  • areas – Represents if areas within the chart should be shaded
  • shadows – Represents if shadows should be added to lines within the plot (ex: {dx:4, dy:4})
  • tension – Adds curves to lines within plots for added smoothness. Values can be:
    • X – Cubic bezier lines
    • x – Similar to “X” but assumes that the point set is closed (a loop). It can be used when plotting true XY data.
    • S – Quadratic bezier lines.
  • gap – Represents the number of pixels between bars

Después cada tipo de chart puede tener sus propias opciones. El tipo Pie , por ejemplo, tiene una propiedad radius que define el tamaño del radio del chart:

// Add the default plot
chart.addPlot("default",{
	// Add the chart type
	type: "Pie",
	// Add the radius size because it's a pie chart
	radius: 200 //pixels
});

Antes de crear la gráfica, es mejor tomarse un tiempo visitando la dojox.charting Reference Guide para ver que settings especiales y customizaciones están disponibles para la gráfica que tú necesitas.

Los Ejes

La mayoría de las gráficas personalizan sus ejes x e y. Un eje puede ser horizontal (por defecto) o vertical. Los ejes son añadidos a las gráficas con el método addAxis. El siguiente trozo de código añade los ejes x  e y a una chart:

// Add the X axis
chart.addAxis("x");
// Ad the Y axis
chart.addAxis("y",{
	vertical: true // y is vertical!
});
Se pueden customizar los ejes:

// Add a custom "dw" axis
chart.addAxis("dw",{
	vertical: true,
	leftBottom: false
});

Algunas de las opciones de personalizacion de ejes mas usuales son:

  • fixUpper – Aligns chart ticks (can be “major”, “minor”, “micro”, and “none”)
  • fixLower – Aligns chart ticks (can be “major”, “minor”, “micro”, and “none”)
  • leftBottom – Determines the side of the chart the axis is placed (default is true)
  • min – The minimum number an axis can start at
  • max – The maximum number an axis can end at

You can learn more about an axis’ settings including customization of colors, fonts, stepping, and precision here.

Las Series

Este elemento es simplemente una serie de datos a ser referenciados por la chart. Las series se añaden a la chart con el método addSeries. Este método acepta estos argumentos:

  • name – The name of the series. Also represents the series label when the Legend plugin is used.
  • data – The array of data
  • options An object containing series options, which may include:
    • stroke – Color and width of lines (ex: { color:"red", width: 2 })
    • fill – Fill color of bar / line / pie piece

Añadir una serie es tan fácil como esto:

// Add a simple axis to the chart
chart.addSeries("Visits",[10,20,30,40,50],{
	stroke: {
		color: "blue",
		width: 3
	},
	fill: "#123456"
});
Series de datos con múltiples ejes sería como esto:

// Add a multi-axes data series to the chart
chart.addSeries("Visits",[
	{ x: 1, y: 200 },
	{ x: 2, y: 185 },
	// and so on...
	],{
		stroke: {
			color: "blue",
			width: 3
		},
		fill: "#123456"
	}
);

Una chart puede tener cualquier numero de series solapantes.

Eventos de Chart 

Los eventos de Chart te permiten enganchar un comportamiento a varias características de la chart, tales como las marcas en respuesta a acciones de usuarios.

Los eventos soportados son los siguientes: onclick, onmouseover, and onmouseout.

Los manejadores de eventos pueden ser enganchados a plots individuales de una chart:

chart.connectToPlot(
    plotName,    // el nombre del plot (el que se le dio cuando se creo)
    object,      // Tanto los parametros de object como el de methos son los mismos que los que se utilizan en el metodo dojo.connect()
    method       // Se puede poner una function sin object
);
El manejador del evento recibe un argumento que tiene las siguientes atributos:
Attribute Expected Value Description Since
type “onclick”, “onmouseover”, “onmouseout” differentiate between different types of events. 1.0
element “marker”,”bar”,”column”,”circle”,”slice” Indicates what kind of element has sent the event. Can be used to define highlighting or animation strategies. 1.0
x number The “x” value of the point. Can be derived from the index (depends on a chart). 1.0
y number The “y” value of the point. Can be derived from the index (depends on a chart). 1.0
index number The index of a data point that caused the event. 1.0
run object The data run object that represents a data series. Example: o.run.data[o.index] returns the original data point value for the event (o is an event handler’s argument). 1.0
plot object The plot object that hosts the event’s data point. 1.0
hAxis object The axis object that is used as a horizontal axis by the plot. 1.0
vAxis object The axis object that is used as a vertical axis by the plot. 1.0
event object The original mouse event that started the event processing. 1.0
shape object The gfx shape object that represents a data point. 1.0
outline object The gfx shape object that represents an outline (a cosmetic shape). Can be null or undefined. 1.0
shadow object The gfx shape object that represents a shadow (cosmetic shape). Can be null or undefined. 1.0
cx number The “x” component of the visual center of a shape in pixels. Supplied only for “marker”, “circle”, and “slice” elements. Undefined for all other elements 1.0
cy number The “y” component of the visual center of a shape in pixels. Supplied only for “marker”, “circle”, and “slice” elements. Undefined for all other elements 1.0
cr number The radius in pixels of a “circle”, or a “slice” element. Undefined for all other elements 1.0

Ejemplos

Line Chart: Ventas mensuales

The Monthly Sales chart is a lines chart which features multiple axes and the “Tom” theme.

<script>
// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");

// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.Tom");

// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];

// When the DOM is ready and resources are loaded...
dojo.ready(function() {

// Create the chart within it's "holding" node
var chart = new dojox.charting.Chart2D("chartNode");

// Set the theme
chart.setTheme(dojox.charting.themes.Tom);

// Add the only/default plot
chart.addPlot("default", {
type: "Lines",
markers: true
});

// Add axes
chart.addAxis("x");
chart.addAxis("y", { min: 5000, max: 15000, vertical: true, fixLower: "major", fixUpper: "major" });

// Add the series of data
chart.addSeries("SalesThisDecade",chartData);

// Render the chart!
chart.render();
});
</script>

<!-- create the DOM node for the chart -->
<div id="chartNode" style="width:800px;height:400px;"></div>

View Demo

Dojo Line Chart

A line chart using the Tom theme

Stacked Areas Chart: Ventas Mensuales

Este ejemplo es una amplicación del primero pero añade un segundo eje para mostrar varios conjuntos de datos. Utiliza además el thme Dollar:

// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");

// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.Dollar");

// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];
var chartData2 = [3000,12000,17733,9876,12783,12899,13888,13277,14299,12345,12345,15763];

// When the DOM is ready and resources are loaded...
dojo.ready(function() {
	// Create the chart within it's "holding" node
	var chart = new dojox.charting.Chart2D("chartNode");

	// Set the theme
	chart.setTheme(dojox.charting.themes.Dollar);

	// Add the only/default plot
	chart.addPlot("default", {
		type: "StackedAreas",
		markers: true
	});

	// Add axes
	chart.addAxis("x");
	chart.addAxis("y", { min: 5000, max: 30000, vertical: true, fixLower: "major", fixUpper: "major" });

	// Add the series of data
	chart.addSeries("Monthly Sales - 2010",chartData);
	chart.addSeries("Monthly Sales - 2009",chartData2);

	// Render the chart!
	chart.render();
});

View Demo

Dojo StackedAreas Chart

A stacked areas chart using the Dollar theme

Columns Chart: Monthly Sales

This chart builds on the original Line chart but instead uses columns. A 5-pixel gap is placed between columns; the MiamiNice theme is used.

// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");

// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.MiamiNice");

// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];

// When the DOM is ready and resources are loaded...
dojo.ready(function() {
	// Create the chart within it's "holding" node
	var chart = new dojox.charting.Chart2D("chartNode");

	// Set the theme
	chart.setTheme(dojox.charting.themes.MiamiNice);

	// Add the only/default plot
	chart.addPlot("default", {
		type: "Columns",
		markers: true,
		gap: 5
	});

	// Add axes
	chart.addAxis("x");
	chart.addAxis("y", { vertical: true, fixLower: "major", fixUpper: "major" });

	// Add the series of data
	chart.addSeries("Monthly Sales",chartData);

	// Render the chart!
	chart.render();
});

View Demo

Dojo Column Chart

A column chart using the MiamiNice theme

Charting Plugins

The dojox.charting library provides functional and aesthetically pleasing plugins to enhance your forms.

Legend

Charts often include legends to further clarify the data provided within the chart. Using the dojox.charting.widget.Legend is easy: require the resource and create an instance, assigning it a chart:

<script>
	//this legend is created within an element with a "legend1" ID.
	var legend1 = new dojox.charting.widget.Legend({ chart: chart }, "legend");
</script>

<!-- create the DOM node for the chart -->
<div id="chartNode" style="width:800px;height:400px;"></div>

<!-- create the DOM node for the legend -->
<div id="legend"></div>

Tooltip

The Tooltip plugin pone luz sobre los valores que están por encima de las marcas, dependiendo del tipo de chart. Utilizando este plugin es tan facil como importar el plugin con require y crear una instancia enganchada a tu chart:

var tip = new dojox.charting.action2d.Tooltip(chart1, "default");

IMPORTANTE: Esto debe ser hecho antes de la llamada al render y después de añadir las series de datos.

NOTA: Veremos que se genera un div con estilos del tipo dijit_tooltip (http://dojotoolkit.org/reference-guide/dijit/Tooltip.html#dijit-tooltip)

MoveSlice and Magnify

Los plugins de MoveSlice y Magnify utilizan una animación para reaccionar al evento mouseover

The MoveSlice and Magnify plugins use a touch of animation to react to the mouse’s mouseover event. MoveSlice moves a pie chart piece and Magnify slightly enlarges chart markers. Both are implemented by creating a new instance and passing the chart and plot to it:

1
2
3
4
5
// Moves a pie slice: use the "pieChart" chart, and "default" plot
var slice = new dojox.charting.action2d.MoveSlice(pieChart, "default");
// Magnifies a marker: use the "chart" chart, and "default" plot
var magnify = new dojox.charting.action2d.Magnify(chart, "default");

Like the Tooltip plugin, the MoveSlice and Magnify plugins must be assigned to the chart before the render method is called on the chart.

Highlight

The Highlight plugin changes the color of an area when the mouse enters the area:

1
2
// Highlights an area: use the "chart" chart, and "default" plot
var magnify = new dojox.charting.action2d.Highlight(chart, "default");

Monthly Sales with Legend, Tooltips, and Magnify

Let’s add the Legend, Tooltip, and Magnify plugin to a line chart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");
// Retrieve the Legend, Tooltip, and Magnify classes
dojo.require("dojox.charting.widget.Legend");
dojo.require("dojox.charting.action2d.Tooltip");
dojo.require("dojox.charting.action2d.Magnify");
// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.Claro");
// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];
var chartData2 = [3000,12000,17733,9876,12783,12899,13888,13277,14299,12345,12345,15763];
var chartData3 = [3000,12000,17733,9876,12783,12899,13888,13277,14299,12345,12345,15763].reverse();
// When the DOM is ready and resources are loaded...
dojo.ready(function() {
// Create the chart within it's "holding" node
var chart = new dojox.charting.Chart2D("chartNode");
// Set the theme
chart.setTheme(dojox.charting.themes.Claro);
// Add the only/default plot
chart.addPlot("default", {
type: "Lines",
markers: true
});
// Add axes
chart.addAxis("x");
chart.addAxis("y", { min: 5000, max: 30000, vertical: true, fixLower: "major", fixUpper: "major" });
// Add the series of data
chart.addSeries("Monthly Sales - 2010",chartData);
chart.addSeries("Monthly Sales - 2009",chartData2);
chart.addSeries("Monthly Sales - 2008",chartData3);
// Create the tooltip
var tip = new dojox.charting.action2d.Tooltip(chart,"default");
// Create the magnifier
var mag = new dojox.charting.action2d.Magnify(chart,"default");
// Render the chart!
chart.render();
// Create the legend
var legend = new dojox.charting.widget.Legend({ chart: chart }, "legend");
});

View Demo

Dojo Chart with Legend, Tooltips, and MagnifyA line chart with a legend, tooltips, and magify enabled, using the Claro theme

Monthly Sales Pie Chart with MoveSlice

Add a bit of dynamism to your Pie Chart with MoveSlice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");
// Retrieve the Legend, Tooltip, and MoveSlice classes
dojo.require("dojox.charting.action2d.Tooltip");
dojo.require("dojox.charting.action2d.MoveSlice");
// Require the theme of our choosing
//"Claro", new in Dojo 1.6, will be used
dojo.require("dojox.charting.themes.Claro");
// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];
// When the DOM is ready and resources are loaded...
dojo.ready(function() {
// Create the chart within it's "holding" node
var chart = new dojox.charting.Chart2D("chartNode");
// Set the theme
chart.setTheme(dojox.charting.themes.Claro);
// Add the only/default plot
chart.addPlot("default", {
type: "Pie",
markers: true
});
// Add axes
chart.addAxis("x");
chart.addAxis("y", { min: 5000, max: 30000, vertical: true, fixLower: "major", fixUpper: "major" });
// Add the series of data
chart.addSeries("Monthly Sales - 2010",chartData);
// Create the tooltip
var tip = new dojox.charting.action2d.Tooltip(chart,"default");
// Create the slice mover
var mag = new dojox.charting.action2d.MoveSlice(chart,"default");
// Render the chart!
chart.render();
});

View Demo

Dojo Pie Chart with MoveSliceA pie chart with MoveSlice, using the Claro theme

Monthly Sales with Highlights

The Highlight plugin would look great with the Columns chart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Require the basic 2d chart resource: Chart2D
dojo.require("dojox.charting.Chart2D");
// Require the highlighter
dojo.require("dojox.charting.action2d.Highlight");
// Require the theme of our choosing
dojo.require("dojox.charting.themes.MiamiNice");
// Define the data
var chartData = [10000,9200,11811,12000,7662,13887,14200,12222,12000,10009,11288,12099];
// When the DOM is ready and resources are loaded...
dojo.ready(function() {
// Create the chart within it's "holding" node
var chart = new dojox.charting.Chart2D("chartNode");
// Set the theme
chart.setTheme(dojox.charting.themes.MiamiNice);
// Add the only/default plot
chart.addPlot("default", {
type: "Columns",
markers: true,
gap: 5
});
// Add axes
chart.addAxis("x");
chart.addAxis("y", { vertical: true, fixLower: "major", fixUpper: "major" });
// Add the series of data
chart.addSeries("Monthly Sales",chartData);
// Highlight!
new dojox.charting.action2d.Highlight(chart,"default");
// Render the chart!
chart.render();
});

View Demo

Dojo column chart with highlightA column chart with highlight, using the MiamiNice theme

Conclusion

The Dojo Toolkit provides a complete charting library capable of creating elegant, eye-catching, and dynamic charts of various types. dojox.charting is unmatched by other charting libraries in flexibility, functionality, and extendability. Don’t serve your data to users in a boring way — dress up your data with dojox.charting!

dojox.charting Resources

Looking for more detail about Dojo’s charting library? Check out these great resources:

Capitulo 2: Tu primera aplicación en Java para Android

Después de finalizar todos los pasos de la primera parte de este tutorial, referentes a la instalación de todos los elementos necesarios para el desarrollo de aplicaciones para nuestro dispositivo Android, vamos a pasar a hacer la primera. Va a ser un ejemplo muy sencillo.Los programadores tienen la manía, desde tiempos inmemoriales, de que la primera aplicación que hacen para un nuevo lenguaje de programación que están aprendiendo, sea un “Hola mundo”.

Creación de un nuevo proyecto en Eclipse

En primer lugar tendremos que abrir nuestro Eclipse, que como ya habíamos dicho va a ser el entorno de desarrollo que vamos a utilizar para nuestras aplicaciones Android. Una vez aquí, creamos un proyecto nuevo de la siguiente manera:

  • Nosotros queremos crear un nuevo proyecto Android, así que vamos a “otros”. Nos aparecerá el siguiente diálogo, donde veremos una carpeta llamada “Android”, y seleccionaremos nuevo proyecto android.
  • Cuando le damos a siguiente, nos aparecerá un nuevo diálogo donde tendremos que fijar algunas de las propiedades de nuestro proyecto. Vamos a verlo:
    • Project Name: El nombre que le vamos a dar a nuestro proyecto, y por el que podremos reconocerlo dentro de Eclipse. En este caso lo llamaremos HolaMundo
    • Contents: Aquí querrá que le digamos si vamos a crear un proyecto desde cero, o queremos usar algún tipo de código que ya tengamos escrito de antemano, y donde almacenarlo. En default location os pondrá la ruta de vuestro workspaceindicado durante el primer inicio de Eclipse, y no es más que la ruta en vuestro disco duro donde se va a almacenar el proyecto
    • Build Target: Aquí seleccionaremos la versión de sistema operativo que vamos a utilizar. Hay cosas, como por ejemplo Text-To-Speech, que solo están disponibles a partir de la 1.6, cosa a tener en cuenta en el futuro. Tampoco es “paseis” por arriba, ya que entonces no funcionará en dispositivos con versión menor
    • Application name: El nombre que va a tener nuestra aplicación, que será visible, por ejemplo, en el menú de aplicaciones de Android entre otros sitios
    • Package name: El código va a estar ordenado en paquetes, cosa que de momento nos va a dar bastante igual, y os basta con saber que por convenio, suelen empezar por letra minúscula
    • Create Activity: Vamos a marcar esta opción para que nos cree la primera clase, donde nosotros vamos a escribir nuestro código
  • Ya estamos listos para finalizar con este asistente y darle a finish. En este momento, eclipse nos crea toda la estructura necesaria de ficheros y directorios para nuestra aplicación, y vemos lo siguiente:
    • A la izquierda, en “Package explorer”, podemos ver la estructura de nuestro proyecto Android. Nos basta con saber dos de las carpetas:
      • src: Aquí es donde van a ir las SouRCesfuentes de nuestros programas, es decir, el código que nosotros vamos a escribir
      • res: Aquí es donde van los RESources o recursos de nuestros programas, tales como imágenes, sonidos, y las pantallas.
    • A la derecha podemos ver que he abierto la clase HolaMundoActivity.java, que es la activity que le dijimos que crease cuando creamos nuestro proyecto.Esta es la actividad que va a ser llamada cuando arranque nuestro programa, es decir, este es el trozo de código que se va a ejecutar primero en nuestra aplicación. Se va a crear un objeto, en este caso no es un microondas, si no un “HolaMundo” que de momento, va a tener definida una única funcionalidad, onCreate, que lo que va a hacer es definir lo que tiene que hacer cuando se crea, es decir, cuando lo arrancamos.

HolaMundoActivity.java

package com.jes;

import android.app.Activity;
import android.os.Bundle;

public class HolaMundoActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

Programando código de nuestra cosecha

Vamos a añadirle un par de propiedades a nuestra clase, unos atributos, que en este caso van a ser el texto que va a mostrar, y el color, por ejemplo.

De esta manera es como le diremos a nuestro programa, que interfaz, que vamos a crear ahora, tiene que utilizar para, en nuestro caso, mostrar nuestro hola mundo.Y a ese método le estamos pasando R.layout.main refiriéndonos a:

  • R: La forma de referirnos a los recursos (res) que tiene nuestro programa
  • layout: Se trata de una interfaz de usuario, que como veremos ahora, están dentro de /res/layout
  • main: Este va a ser el nombre del fichero que vamos a crear para nuestra interfaz.
  • <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello" />
    
    </LinearLayout>

Como veréis, Eclipse ya nos lo crea inicialmente

  1. Abrimos nuestro main.xml que como dijimos está en /res/layout (donde, recordemos, vamos a guardar las interfaces gráficas) y nos sale esto en la pantalla
  2. Hay una pestañita llamada main.xml, al lado de Graphical Layout. Le damos ahí, y vemos lo siguiente:
    1. Este textview va a ser un objeto, con sus atributos y métodos que nosotros vamos a utilizar para mostrar un texto.Vamos a darle un identificador, para poder referirnos a el desde nuestro programa: Lo haremos simplemente añadiendo esa línea, de la cual ya explicaremos la sintaxis en capítulos posteriores.
    2. <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:orientation="vertical" >
      
          <TextView
              android:id="@+id/cajatexto"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello" />
      
      </LinearLayout>
  3. Vámonos ahora de nuevo a nuestro programa principal, y vamos a realizar lo siguiente: Pedir la caja de texto, fijarle el texto, y fijarle el color.Para ello lo haremos así:
    1. Vamos a ver que son estas dos líneas que he añadido:
      1. TextView tv : Creamos la referencia a un objeto de la clase TextView, que es el elemento que tenemos en nuestra interfaz para mostrar nuestro texto.
      2. (TextView) findViewById(): findViewById es, de nuevo, un método que heredamos de activity, y que lo que hace es encontrar una “view” dándole nosotros su identificador (el que acabamos de fijar en el XML).
      3. R.id.cajatexto: Como ya dijimos antes, R (res), id (buscamos un identificador), cajatexto (el nombre que le hemos dado al identificador de nuestro TextView en el XML)
  4. Hacemos los import necesarios y ya tenemos un objeto TextView, llamado tv, que se refiere al TextView de nuestra interfaz. Vamos a decirle que y como queremos mostrar
  5. package com.jes;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class HolaMundoActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            TextView tv = (TextView)findViewById(R.id.cajatexto);
        }
    }
  6. Nuestro TextView iba a tener unas funcionalidades para fijarle el texto que queremos mostrar, así como el color del mismo (entre otros muchos, por si queréis investigar).Pues así lo hacemos, pasándole nuestras variables definidas anteriormente, llamadas textoMostrar y colorTexto
  7. package com.jes;
    
    import android.app.Activity;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class HolaMundoActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            TextView tv = (TextView)findViewById(R.id.cajatexto);
    
            tv.setText("Hola Caracola!!!!");
    
            tv.setTextColor(Color.YELLOW);
    
        }
    }
  8. Ya estamos listos para ejecutar nuestra aplicación. Vamos a ello:Le damos ahí, en la barra superior a ese “Play” verde.La primera vez que ejecutemos nuestra aplicación, nos preguntará como queremos ejecutarla. Le decimos que se trata de una aplicaciónAndroid, y le damos a OK.Si no habíais guardado los ficheros que habíamos modificado, os preguntará si guardarlos, le decís quesi, y os va a arrancar el emulador del teléfono móvil android. Como dijimos en el primer capítulo, tardará un poco más o menos, en función del ordenador que estéis utilizando. Tened paciencia.Esperamos unos segundos y…

NOTA: Es posible que tengáis que primero desploquear el emulador para que salga la ejecución de la aplicación, en mi caso tengo que desplazar un candado hacia la derecha

Ahí está. Vuestra primera aplicación Android funcionando!

Cómo empezar a desarrollar para dispositivos móviles con Android

(Fuente: http://www.paratuandroid.com/Desarrollo/como-empezar-a-desarrollar-aplicaciones-para-dispositivos-moviles-con-sistema-operativo-android-capitulo-1-introduccion-y-requisitos.html)

Capítulo 1. Introducción y requisitos

En este capítulo dejaremos nuestro equipo preparado con todo lo necesario para adentrarnos en el gratificante mundo del desarrollo.

Una de las grandes cualidades, a veces poco destacada, de los dispositivos móviles con sistema operativo Android, tales como smartphones y tablets, es la libertad y facilidades que sus creadores han dado al usuario medio-avanzado para el desarrollo de aplicaciones propias.

Si bien esto requiere de ciertas habilidades de programación, muchas de las funcionalidades ya nos las dan programadas, y solo hay que hacer llamadas a sus funciones. Te preguntarás, ¿puedo yo desarrollar una aplicación para android? La respuesta es sí. Ahora solo queda saber cuánto puedes abarcar.

1.1.Requisitos

Para desarrollar una aplicación básica para android, como veremos, vamos a necesitar lo siguiente:

Sin conocimientos en absoluto de programación, esta tarea puede hacerse más tediosa, pero cuando consigáis hacer funcionar vuestras aplicaciones, será mucho más gratificante.

1.2.Integración

Ya podemos proceder a la integración de Android con nuestro entorno de desarrollo. Para ello, abrimos nuestro Eclipse, y seguiremos los siguientes pasos:

  • Pulsamos arriba, en ayuda, y ahí en Instalar nuevo software
  • En la nueva ventana de dialogo que se abre, pulsamos en la parte superior, en Añadir
  • Se abre un formulario que nos pide, nombre y dirección. Como nombre le daremos ADT Plugin y en la dirección le pondremos los repositorios de google: https://dl-ssl.google.com/android/eclipse/
  • Le damos a OK, y cuando acabe de pensar, marcamos en el cuadro de software disponible el checkbox de Developer Tools
  • Cuando le damos a siguiente nos dirá todo lo que va a bajar, seleccionamos todo, le damos a siguiente, aceptando todas las licencias, y al cabo de un rato de espera, ya tendremos todo instalado
  • Una vez ha terminado de instalarlo, reiniciamos nuestro Eclipse.

Ya solo nos queda decirle donde hemos instalado nuestro SDK de Android:

  • Seleccionamos arriba Ventana –> Preferencias
  • En la barra izquierda seleccionamos Android
  • Donde nos pregunta por el SDK Location buscamos la carpeta donde lo hemos descomprimido / instalado
  • Aplicamos los cambios, y hemos terminado.

1.3.Creación de dispositivos virtuales

En este punto, ya tenemos un entorno de desarrollo funcional para nuestras aplicaciones Android. Podemos pasar a crear un nuevo dispositivo virtual en el que probaremos nuestros programas. Esto será un teléfono Android perfectamente funcional ejecutándose en nuestro ordenador.

Vamos a la carpeta de nuestro SDK de Android, en tools, y arrancamos el ejecutable android.exe.

La primera vez que lo arrancamos, no tenemos ninguna versión de Android instalada, por lo que seguiremos los pasos que nos indica para actualizarlo y descargar los sistemas operativos. Aunque solo queráis programar para una versión, yo os recomendaría decirle que baje todas, ya que nos es mucho problema el tamaño que ocupan, y luego podemos elegir. Habiendo actualizado, ya podemos crear un nuevo dispositivo.

Aquí depende mucho de lo que queramos hacer con nuestras aplicaciones, aunque no es problema si dejáis algo atrás, ya que posteriormente se le puede añadir todas las funcionalidades que se desee.

  • Nos ponemos en Virtual Devices y le decimos que queremos crear uno nuevo
  • Le podéis dar el nombre que os venga en gana, no es más que un identificador
  • En Target es donde vamos a seleccionar el sistema operativo que va a tener nuestro dispositivo. Aquí hay que tener unas cuantas cosas en cuenta, como por ejemplo, que algunas de las funcionalidades de 2.3, por ejemplo, no se encuentran disponibles en 1.5. Otra cosa a tener en cuenta es si vamos a querer utilizar Google Maps en nuestra aplicación. Si es así, tendremos que seleccionar la versión que corresponda, pero la línea que pone Google API
  • Si vuestras aplicaciones van a utilizar la tarjeta SD del teléfono, podéis marcarle ahí el tamaño que le vais a dar para utilizar en vuestro dispositivo virtual
  • En Skin vamos a decirle que tipo de pantalla tiene nuestro teléfono, pudiendo escoger entre las más utilizadas sin necesidad de darle nosotros la resolución
  • Y en Hardware le vamos a decir que funcionalidades va a tener nuestro dispositivo, tales como GPS, acelerómetros, etc. etc. Como ya hemos dicho, añadid las que creáis que necesitáis, sin preocuparos si dejáis alguna, ya que posteriormente se puede editar y añadir a vuestro antojo
  • Le damos a Crear y ya tenemos nuestro móvil virtual sobre el que probar las aplicaciones. Podéis probarlo dándole a Start. Tened en cuenta, que en función del ordenador que tengáis, puede llegar a tardar 3-4 minutos en arrancar.

Ya tenemos todo listo. Un entorno de desarrollo perfectamente funcional para programar nuestras propias aplicaciones Android de manera 100% gratuita y libre. En el próximo capítulo veremos cómo empezamos a programar una sencilla aplicación y la ejecutamos tanto en el emulador, como en un teléfono móvil.