Hola a todos, retomamos de nuevo los tutoriales de nuestro querido javascript, esta vez vamos a ver una nueva funcionalidad que nos trae HTML5. Veremos como hacer arrastables o contenedores a los cuales arrastrar cualquier tipo de elemento.

Autor:

Intentando mejorar cada día en este mundo tan cambiante de la programación. Sígueme en Twitter o en GitHub. Actualmente estoy disponible para contratar.
Descarga Demostración

Introducción

Una característica bastante utilizada en aplicaciones con una interfaz de usuario enriquezida es la de poder arrastrar los elementos. Ejemplos típicos son el de reorganizar los elementos de una web para personalizarla o mover un elemento a una determinada categoría.

Hasta ahora la forma más fácil de hacer esto era usar una librería de Javascript que nos facilitase el trabajo. La jQuery UI, que es la que más me conozco, estaba muy avanzada en este tema. Sin embargo, al ser una implementación totalmente basada en Javascript, tenía bastantes inconvenientes como:

  • Si mueves demasiado rápido los elementos, el elemento arrastrado se suele quedar atrás y se pierde en “dragging”.
  • Solo puedes mover elementos dentro de la misma web, no puedes arrastrar elementos de una ventana a otra ni aceptar elementos que no sean DOM.
  • Menos eficiencia al requerir más código.

Novedades en HTML 5

Los creadores del estándar HTML5, parece que han visto que esta característica es importante y que necesita ser mucho más exprimida para dar mucho más juego a las aplicaciones webs. A continuación os cito las principales novedades del estándard en este tema:

  • Nuevos eventos en el DOM: dragstart, drag, dragenter, dragover, dragleave, drop, dragend.
  • Nuevo atributo para los elementos DOM para hacerlo arrastrable: draggable=”true”.
  • Se permite adicionar información en el elemento arrastrable para que el contenedor pueda recibirla.
  • Posibilidad de establecer la imagen “ghost” mostrada mientras se arrastra.
  • Posibilidad de añadir efectos del estilo: copiar, mover, vínculo,  etc…

Además, esta característica va más allá de la propia web, dándonos la posiblidad de arrastrar elementos entre distintas webs e incluso aceptar elementos de otras aplicaciones como arrastrar un texto de un procesador de texto o un fichero del sistema.

Los nuevos eventos

Vamos a listar los nuevos eventos que nos trae HTML5 para drag & drop y luego veremos un ejemplo de implementación para que veáis lo fácil y rápido que se implementa.

dragstart

Comienza el arrastrado. El “target” del evento será el elemento que está siendo arrastrado.

drag

El elemento ha sido movido. El “target” del evento será el elemento arrastrado.

dragenter

Se dispara cuando un elemento que está siendo arrastrado entra en un contenedor. El “target” del evento será el elemento contenedor.

dragover

El elemento ha sido movido dentro del contenedor. El “target” del evento será el elemento contenedor. Como el comportamiento por defecto es denegar el “drop”, la función debe retornar el valor “false” o llamar a “preventDefault” para que indicar que se puede el soltar elemento.

dragleave

El elemento arrastrado ha salido del contenedor. El “target” del evento será el elemento contenedor.

drop

El elemento arrastrado has sido éxitosamente soltado en el elemento contenedor. El “target” del evento será el elemento contenedor.

dragend

Se ha dejado de arrastrar el elemento, con éxito o no. El “target” del evento será el elemento arrastrado.
Vamos a ver un ejemplo de como hacer un elemento arrastable usando jQuery.

$('#mydrag')
    .attr('draggable', 'true')
    .bind('dragstart', function(ev) {
        var dt = ev.originalEvent.dataTransfer;
        dt.setData("Text", "Información adicional");
        return true;
    })
    .bind('dragend', function(ev) {
        return false;
    });

Y ahora la otra parte, creamos un contenedor que esté a la espera de elementos arrastrables.

$('#mycontainer')
    .bind('dragenter', function(ev) {
        //Cambiamos color del contenedor para mostrar que acepta al elemento
        $(ev.target).css('background','#F00');
        return false;
    })
    .bind('dragleave', function(ev) {
       //Reestablecemos el color del contenedor
        $(ev.target).css('background','#FFF');
        return false;
    })
    .bind('dragover', function(ev) {
        //Importante como hemos dicho para que acepte al elemento, 
        //por defecto cancela el drop
        return false;
    })
    .bind('drop', function(ev) {
        var dt = ev.originalEvent.dataTransfer;
        alert(dt.getData('Text'));
        return false;
    });
});

Creo que el código no require de mucha explicación pues simplemente establece las funciones para cada evento, aunque creo que es importante reseñar que gracias al objeto dataTransfer se puede compartir información entre el elemento arrastrado y el contenedor, lo veremos a fondo a continuación.

Transfiriendo información con dataTransfer

Como ya hemos dicho, una de las características más importantes de esta nueva implementación, es la posibilidad de cargar información en el elemento arrastrado para que el contenedor pueda recibirla. Pero, lo que todavía está mucho mejor, es que un contenedor pueda recibir los datos desde elementos arrastrados desde otros navegadores o aplicaciones.

Como ya he mostrado en el ejemplo anterior, esto se hace a través de los métodos setData y getData del objeto dateTransfer expuesto en el objecto del evento (Event Object).

La información se debe de almacenar usando los tipos recomendados para un uso estándard y adecuado. A continuación unos ejemplos:

var dt = ev.originalEvent.dataTransfer;    
dt.setData('text/plain', 'Hola mundo');
dt.setData('text/html', 'Hola mundo');
dt.setData('text/uri-list', 'http://web.ontuts.com');

Un ejemplo de uso de los tipos recomendados es seleccionar un texto en el navegador, arrastralo a un contenedor y esperar encontrar algo en en text/html, o arrastrar texto desde un procesador de texto y esperar encontrar algo en text/plain.

Uso de imágenes fantasma

Esta es una nueva característica que nos permite establecer lo que el usuario verá como imagen semitransparente mientras arrastra el elemento. Tenemos tres posibilidades:

  • Establecer un elemento del DOM.
  • Establecer una imagen (aunque se base en el punto anterior).
  • Establecer un elemento canvas.

Esto se hace a través del método setDragImage, incluído una vez más, en la propiedad dataTransfer. A continuación un ejemplo de los tres tipos:

var dt = ev.originalEvent.dataTransfer;    
 //Elemento DOM
dt.setDragImage( $('h2')[0], 0, 0);
 //Imagen (elemento DOM)
dt.setDragImage( $('#image')[0], 32, 32); 
 
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 50;
var ctx = canvas.getContext("2d");
ctx.lineWidth = 8;
ctx.moveTo(25,0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.stroke();
//Canvas
dt.setDragImage(canvas, 25, 25);

El método setDragImage acepta como primer parámetro el elemento que se desea mostrar como imagen. Los dos siguientes parámetros son el “offset” que se desea dar a la imagen respecto a la posición por defecto.

Usando efectos de arrastrado / tirado

El drag & drop del nuevo estándar ha sido creado para sobre todo para soportar acciones como copiar, mover y vincular. Por ello se han añadido los efectos de tirado para mostrar la acción que se va a ejecutar. Para que te hagas una idea, son los iconcitos pequeños que aparecen cuando arrastras un icono en el S.O. (una flechita, un signo más, etc…).

Estes efectos pueden establecerse a nivel del elemento arrastrado o a nivel del contenedor. Si se vinculan al contenedor, el efecto solamente aparece cuando se producen los eventos dragenter y dragover.

Para usar esta funcionalidad se establecen las propiedades effectAllowed y dropEffect para los elementos arrastrados y contenedores respectivamente. Como es de esperar, estas propiedades están incluídas en el objeto dataTransfer. A continuación un ejemplo de como añadir el efecto al elemento arrastrado:

var dt = ev.originalEvent.dataTransfer;
dt.effectAllowed = 'copy';

Los valores permitidos para esta propiedad son:

  • none: ninguna operación permitida
  • copy: solo copiar
  • move: solo mover
  • link: solo vínculo
  • copyMove: copiar o mover
  • copyLink: copiar o vincular
  • linkMove: vincular o mover
  • all: copiar, mover o vincular

Por otro lado, puedes especificar el efecto para el propio contenedor, para indicar la acción que se va a llevar a cabo al soltar el elemento:

var dt = ev.originalEvent.dataTransfer;
dt.dropEffect = 'none';

Conclusión

Hasta aquí el tutorial sobre el Drag & Drop en HTML 5, si has tenido la paciencia de leerlo todo, te habrás dado cuenta que tiene muchas novedades y mejoras que despilegan un nuevo abanico de posiblidades, además de mejorar el rendimiento.

Espero que os haya resultado útil la información y no dudéis en dejar un comentario para preguntar, criticar o valorar.

¡Nos vemos en el próximo!

Te sugerimos otras entradas relacionadas...

No hay entradas relacionadas para esta publicación.

¿Necesitas desarrollar un proyecto web o para móviles? ¡Estamos disponibles!

Visitar Cokidoo

Cokidoo, los creadores de Ontuts, desarrollamos proyectos tecnológicos centrados en redes sociales y aplicaciones web, aplicaciones móviles y consultoría web y bases de datos.

Somos jóvenes, inquietos, versátiles, apasionados por la innovación y enfocados en las nuevas tecnologías. Con Ontuts tratamos de compartir nuestro conocimiento adquirido en los distintos proyectos, ayudando a la comunidad y mostrando nuestra capacidad tecnológica.

Si necesitas un presupuesto sin compromiso, estamos disponibles, no dudes en contactar con nosotros.

Comentarios en esta publicación (11 comentarios)

¿Te ha gustado esta publicación? ¡Puedes compartir tu opinión con todos nosotros! Simplemente pincha aquí mismo.

Pedazo de aportación para variar Iván ;)

Estoy deseando que esto sea ya una constante y habitual en muchas aplicaciones… y navegadores :P

¡Gracias Adrián!

Esto es algo que abre muchísimas puertas en las aplicaciones web, pronto saldrán ideas buenísimas en torno a esto seguro! :)

asdf

q navegadores soportan esta caracteristica?

Puedes ver una tabla completa en esta web: http://caniuse.com/

Busca Drag & Drop y lo encontrarás más fácil :)

venechat

Excelente aporte, dentro de poco esto va ser algo normal como HTML 4, así que hay que tomar la ola y no bajarse.

Tania Maria

Estoy programando una web para niños con autismo(Mi Tesis), y dentro de las aplicaciones que habrán, estará la de “formar oraciones”, usando drag & drop, espero me resulte no tan complicado tengo 2 semanas para realizar el sitio web COMPLETO xD
Y HTML5 es algo totalmente nuevo para mi.

Gracias por tu aporte, presiento que me será muy útil :D

Saludos
Arica – Chile

Tania María

Hola Iván, gracias por tus saludos =)

En la aplicación que estoy desarrollando, Los niños deben formar las oraciones, para esto, les aparecerá en pantalla, la oración “ordenada” como el ejemplo que deben hacer, y además la misma oración, pero desordenada, con la cual arrastrarán y soltarán las palabras que componen la oración, en el “casillero”(cuadro o caja) donde corresponda, para “Formar Oración”…

Quería consultarte algo, para hacer lo que te menciono, necesito extraer de la BD atributos de la tabla oracion ej: sujeto, predicado, verbo, articulo…etc.
Es posible que al recibirlos de la BD, y dentro del código que tú explicas, pueda darle un ID a algún campo ? … la verdad es que no me imagino como hacerlo… en el fondo lo que necesito es recibir estos campos de la BD y así poder ocuparlos, asignandolos a un set data, o algo así, para poder “ordenar” esos campos… ahahahahah!! no entiendo cómo hacerlo xD
Me está saliendo humito de la cabeza jaja…

Bueno, espero no complicarte mucho con mi pregunta… y ojalá haya sabido explicarte bien mi duda..
Desde ya agradezco tu tiempo.

Saludos.

Arica – Chile

Espero haberme explicado bien :P

Genial chabo ahora si te lusiste

lis

Hola, esta excelente el articulo. Tengo una pregunta, cree una seria de div con una imagen y los estoy moviendo de un div a otro y sale perfecto pero ocurre que puedo hacer un drop dentro mi div draggable(el que contiene la imagen), no se si me explico, es decir puedo copiar un div dentro de otro(me salen las 2 imagenes o se solapan). Como puedo hacer para que mi div draggable no posea las mismas propiedades del drop. Espero puedan ayudarme, gracias.

Muy buen tutorial. Gracias por compartirlo!