30 de Julio de 2014

Notas Espacio Programación

galería de imágenesvideo
AUTOR: Andrés Fernández
FECHA: 8/3/2009
LECTURAS:10687
Buscar Notas
volver
Drag and Drop sin librerías

Drag and Drop Javascript

Veremos cómo implementar el famoso efecto drag and drop (arrastrar y soltar) en javascript, sin usar frameworks.
Realizar un efecto drag and drop como el del siguiente ejemplo, donde podemos controlar la ubicación de la capa gris arrastrando la imagen que ésta contiene, es bastante sencillo y no requiere uso de librerías externas ni conocimientos avanzados:



De lo que se trata es de realizar los siguientes pasos:

1) Registrar la posición del objeto a arrastrar (la capa gris en nuestro ejemplo) y una referencia a las coordenadas del mouse (event.clientX y event.clientY), en el momento en que se produce el evento onmousedown sobre el objeto que controlará el arrastre (la imagen en este caso).
2) Asignar, al evento onmousemove de ese mismo objeto (seguimos hablando de la imagen), una función que reposicione el objeto arrastrable (capa gris) a una nueva ubicación, que será igual a su posición inicial más la diferencia entre las coordenadas del mouse registradas al inicio del movimiento y las coordenadas del mouse actuales, las cuales se redefinen constantemente durante el proceso de arrastre.
3) Para que el objeto arrastrable no quede pegado ("imantado") al puntero del mouse cuando dejamos de presionarlo, debemos asignar, a los eventos onmouseup y onmouseout de nuestro controlador, una función que remueva el evento onmousemove que le habíamos asignado en el primer paso.

Para lograr todo eso, utilizamos este código:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style>
*{margin:0; padding:0}
</style>
<title>test</title>
<script>
function 
_$(x){return document.getElementById(x);}
function 
addEvent(obj,fun,type){
    if(
obj.addEventListener){
        
obj.addEventListener(type,fun,false);
    }else if(
obj.attachEvent){
        var 
f=function(){
            
fun.call(obj,window.event);
        }
        
obj.attachEvent('on'+type,f);
        
obj[fun.toString()+type]=f;
    }else{
        
obj['on'+type]=fun;
    }
}

function 
removeEvent(obj,fun,type){
    if(
obj.removeEventListener){
        
obj.removeEventListener(type,fun,false);
    }else if(
obj.detachEvent){
        
obj.detachEvent('on'+type,obj[fun.toString()+type]);
        
obj[fun.toString()+type]=null;
    }else{
        
obj['on'+type]=function(){}
    }
        
}
function 
cancelEv(e){
    
e=|| window.event;
    if(
e.preventDefault)
        
e.preventDefault();
    else
        
e.returnValue=false;
}
function 
stopEv(e){
    
e=|| window.event;
    if(
e.stopPropagation)
        
e.stopPropagation();
    else
        
e.cancelBubble=true;
}
function 
arrastrable(o){
    var 
o=|| this;
    
this.style.cursor='move';
    
o.style.cssFloat=o.style.styleFloat='none';
    
o.style.position='relative';
    
addEvent(this,function(e){
        
e=|| window.event;
        
cancelEv(e);
        
stopEv(e);
        
this.cx0=e.clientX;
        
this.cy0=e.clientY;
        
this.ox=parseInt(o.style.left) || 0;
        
this.oy=parseInt(o.style.top) || 0;
        
addEvent(this,this.arrastrar,'mousemove');
    },
'mousedown');
    
this.arrastrar=function(e){
        
e=|| window.event;
        
cancelEv(e);
        
stopEv(e);
        
o.style.left=this.ox-this.cx0+e.clientX+'px';
        
o.style.top=this.oy-this.cy0+e.clientY+'px';
    }
    
addEvent(this,function(e){
        
e=|| window.event;
        
cancelEv(e);
        
stopEv(e);
        
removeEvent(this,this.arrastrar,'mousemove');
    },
'mouseup');
    
addEvent(this,function(e){
        
e=|| window.event;
        
cancelEv(e);
        
stopEv(e);
        
removeEvent(this,this.arrastrar,'mousemove');
    },
'mouseout');
}
onload=function(){
    
arrastrable.call(_$('pp'),_$('pp').parentNode);
}
</
script>  
</head>
<body>
<div style="background-color:#000; padding:10px; width:400px;">
<div style=" width:200px; height:200px; background-color:#CCC;margin:auto; position:relative ">
<img id="pp" src="im.jpg" style="position:absolute; left:50%; top:50%; margin-left:-25px; margin-top:-25px;">
</div>
</div>
</body>
</html>



Podemos apreciar que el código que genera el efecto es bastante breve, pero se alarga con otras funciones que usamos para asignar o desasignar eventos, prevenir burbujeo y eliminar acciones por defecto (ciertos navegadores implementan acciones propias sobre el arrastre de imágenes y debemos deshabilitarlas para que no interfieran con nuestro efecto).

En nuestro ejemplo señalamos al objeto controlador del arrastre y al objeto arrastrable de la siguiente manera:

arrastrable.call(_$('pp'),_$('pp').parentNode);


Donde el primer argumento del método call (_$('pp')) representa al controlador del arrastre (la imagen, en nuestro caso) y el segundo argumento (_$('pp').parentNode)) representa al objeto que queremos arrastrar (en nuestro ejemplo, la capa gris).
Si no estuviera definido este segundo argumento, el objeto arrastrable sería el mismo objeto controlador.
Y, por cómo hemos definido la función arrastrable, es posible usar ese segundo argumento para subir en la jerarquía del DOM y mover más elementos: si quisiéramos arrastrar todo el árbol definido en nuestro ejemplo, bastaría con hacer la siguiente asignación:

arrastrable.call(_$('pp'),_$('pp').parentNode.parentNode);


Con eso, al mover la imagen moveríamos simultáneamente la capa gris y la capa negra que la contiene.

Por supuesto, hay muchas más posibilidades: podríamos mover elementos o estructuras completas a partir de un controlador ajeno a dicha estructura (no anidado en ella).

Lo importante es que, contrariamente a lo que muchos creen, no es un proceso complejo y, como hemos demostrado, no es obligatorio usar librerías para lograrlo.
Home - Quiénes Somos - Portfolio - Espacio Diseño - Espacio Programación - Capacitación - Contacto - RSS