Arrastrar y soltar con HTML5

Introducción.

En este artículo se revisarán los pasos necesarios para implementar la facilidad de arrastrar y soltar (drag and drop) en una página web aprovechando las funcionalidades provistas por HTML5.  Para este desarrollo se utilizará jQuery para facilitar la implementación, sin embargo esto no es estrictamente necesario.

Establecer los elementos “arrastrables”.

El primer paso consiste en establecer cuales elementos podrán ser arrastrados, para hacer esto se les deberá agregar el atributo draggable=’true’.  En el caso del ejemplo, los elementos arrastrables son imágenes de la siguiente manera.

<img id="tool0" draggable="true" title="tool" src="img/tool0.png" alt="tool" />
<img id="tool1" draggable="true" title="tool" src="img/tool1.png" alt="tool" />
<img id="tool2" draggable="true" title="tool" src="img/tool2.png" alt="tool" />

Definir el comportamiento de los elementos “arrastrables”.

El siguiente paso es establecer que se debe hacer cuando los objetos arrastrables son manipulados, es decir, manejar sus eventos.  Estos eventos corresponden con los siguientes y su implementación se debe definir cuando la estructura de la página se encuentra completamente cargada.

 dragstart  El elemento se empieza a arrastrar.
 drag  El elemento está siendo arrastrado.
 dragend  El elemento ha dejado de ser arrastado.

Durante el manejo del evento dragstart se realizan las siguientes tareas.

  1. Almacenar la información del elemento arrastrable (su id en este caso) necesaria para ser procesado en caso de ser soltado exitosamente.
  2. Agregar una nueva clase CSS (itemSelected) para modificar su apariencia mientras es arrastrado.
  3. Modificar la imagen del elemento arrastrado la cual por defecto es la del mismo elemento.
$('.page #main #items .item').bind('dragstart', function(event) {

    // Store information about the item dragged.

    event.originalEvent.dataTransfer.setData("text/plain", event.target.getAttribute('id'));

    // Add a CSS class to highlight the dragged item.

    $(event.target).addClass('itemSelected');

    // Set an image as drag icon.  The image was preloaded.

    var dragIcon = document.createElement('img');
    dragIcon.src = 'img/hand.png';

    event.originalEvent.dataTransfer.setDragImage(dragIcon, 139, 43);
});

Durante el manejo del evento drag no se realizan tareas especiales en este caso.

$('.page #main #items .item').bind('drag', function(event) {
    // The item is being dragged!
});

Durante el manejo del evento dragend se realiza una única tarea y corresponde con retirar la clase CSS añadida durante dragstart para indicar que el elemento ya no está siendo arrastrado actualmente.

$('.page #main #items .item').bind('dragend', function(event) {

    // Remove the CSS class that highlights it while beign dragged.

    $(event.target).removeClass('itemSelected');
});

Definir el comportamiento de las “zonas de descarga”.

El paso final consiste en establecer que se debe hacer cuando los objetos arrastrables interactúan con las zonas de descarga (drop zones), es decir, manejar sus eventos.  Estos eventos corresponden con los siguientes y su implementación también se debe definir cuando la estructura de la página se encuentra completamente cargada.

 dragenter  El elemento arrastrable ha entrado a una zona de descarga.
 dragleave  El elemento arrastrable ha salido de una zona de descarga.
 dragover  El elemento arrastrable está siendo arrastrado sobre una zona de descarga.
 drop  El elemento arrastrable ha sido soltado sobre una zona de descarga.

Durante el manejo del evento dragenter se agrega una nueva clase CSS (itemOnDropArea) para modificar la apariencia de la zona de descarga mientras un elemento es arrastrado sobre ella.

$('.page #main #boxes .box').bind('dragenter', function(event) {

    // Add a CSS class to highlight the drop zone used.

    $(event.target).addClass('itemOnDropArea');

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento dragleave se realiza la tarea contraria, se remueve la clase CSS agregada durante el suceso del evento anterior para mostrar que ningún elemento es arrastrado ahora sobre la zona de descarga.

$('.page #main #boxes .box').bind('dragleave', function(event) {

    // Remove the CSS class that highlights the used drop zone.

    $(event.target).removeClass('itemOnDropArea');

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento dragover no se realiza en este caso ninguna tarea interesante además de indicarle al navegador que evite su comportamiento por defecto el cual es impedir que se realice.

$('.page #main #boxes .box').bind('dragover', function(event) {

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento drop, que sucede cuando el elemento arrastrable se suelta sobre la zona de descarga, se realizan las siguientes tareas en la aplicación de demostración.

  1. Obtener la información almacenada en el objeto dataTransfer definida durante el manejo del evento dragstart.
  2. Obtener la información del objeto arrastrable.
  3. Obtener la información de la zona de descarga.
  4. Determinar si la descarga del objeto es válida o no en la zona de descarga específica.
  5. Realizar una acción según se determine en la tarea anterior: remover el elemento o mostrar un mensaje de error.
  6. Evitar que se efectúe el comportamiento por defecto relacionado con el evento.
$('.page #main #boxes .box').bind('drop', function(event) {

	// Get the stored information about the draggable item,
	// the element ID in this case.

	var itemId = event.originalEvent.dataTransfer.getData("text/plain");

	// Get the type of the draggable item, stored in the
	// ALT attribute in this case.

	var itemType = $("#" + itemId).attr('alt');

	// Get the drop zone's ID to difference the type of it.

	var dropboxType = $(event.target).attr('id');

	// Check if the draggable item can be or not dropped
	// into the current drop zone.

	if(dropboxType == 'toolbox')
	{
		if(itemType == 'tool')
			$("#" + itemId).remove();
		else
			alert("That is a FRUIT, put it on the Fruit's Basket!");
	}

	if(dropboxType == 'fruitbasket')
	{
		if(itemType == 'fruit')
			$("#" + itemId).remove();
		else
			alert("That is a TOOL, put it on the Toolbox!");
	}

	// Remove the CSS class that highlights the used drop zone.

	$(event.target).removeClass('itemOnDropArea');

	// Prevents the default event that denies the DnD
	// behaviour.  Acts as "event.preventDefault()" in
	// vanilla Javascript.

	return false;
});

El prototipo.

En este prototipo se utilizan los fragmentos de código mostrados en este artículo, en él se muestran en la parte inferior dos series de objetos arrastrables (herramientas y frutas) y en la parte superior dos zonas de descarga (una caja de herramientas y una canasta de frutas).  La página web permitirá que el usuario arrastre los elementos a cualquiera de de las zonas de descarga, sin embargo sólo aceptará que se almacenen en la zona correcta.  En caso de intentarse hacer lo contrario se obtendrá un mensaje de error.

Prototipo de demostración de arrastrar y soltar con HTML5
Prototipo de demostración de arrastrar y soltar con HTML5

Enlaces.

One thought on “Arrastrar y soltar con HTML5”

  1. Una pregunta, porque no funciona sobre chrome y si sobre firefox?

    Que hay que hacer para que funcione sobre ambos y sobre internet 9? Gracias.

Leave a Reply

Your email address will not be published. Required fields are marked *