Arrastre ('Drag') Genérico
Ver la página demo para la versión final del código.El Proceso de Arrastre
El proceso básico de arrastre consta de tres etapas: Inicialización del arrastre cuando el botón del mouse es presionado por primera vez, moviendo el elemento blanco ('target') cuando el mouse se ha movido y, finalmente, deteniendo el arrastre cuando el botón del mouse se suelta.
Inicializando el Arrastre
La función dragStart() es llamada por el manejador
del evento onmousedown de algún elemento, tal como se
ha descrito anteriormente. Dicha función determina primero el elemento
'target' para el arrastre.
function dragStart(event, id) {
var el;
var x, y;
// If an element id was given, find it. Otherwise use the element being
// clicked on.
if (id)
dragObj.elNode = document.getElementById(id);
else {
if (browser.isIE)
dragObj.elNode = window.event.srcElement;
if (browser.isNS)
dragObj.elNode = event.target;
// If this is a text node, use its parent element.
if (dragObj.elNode.nodeType == 3)
dragObj.elNode = dragObj.elNode.parentNode;
}
Si se le pasa un id , el script utiliza document.getElementById()
para localizar el elemento. De cualquier otro modo utiliza el objeto
event para determinar sobre qué elemento está
el mouse y lo utiliza por defecto. En cualquier caso, el elemento 'target'
es asignado a dragObj.elNode.
Una situación especial debe ser revisada. Si el mouse está
sobre texto, el blanco ('target') del evento mousedown será
un nodo de texto, en lugar de un nodo elemento. Los nodos de texto contienen
justamente eso, datos textuales, y no tienen propiedades de estilo, como
posición. En su lugar, la apariencia y posición del texto está
determinada por las propiedades de estilo del elemento al que pertenezcan.
Por tanto, si sucede que el nodeType del blanco ('target')
del evento es un nodo de texto TEXT_NODE (= 3), el script toma
su parentNode en su lugar. El padre de un nodo de texto es siempre
el elemento que contiene dicho texto.
document.ELEMENT_NODE devolvería un valor de 1. Internet
Explorer no nos las proporciona, por lo que el valor numérico actual
es utilizada en su lugar en el script. El siguiente paso es encontrar la posición actual del puntero del mouse. Estas coordenadas iniciales en pixels serán utilizadas después para compararlas con la posición del mouse durante el arrastre.
// Get cursor position with respect to the page.
if (browser.isIE) {
x = window.event.clientX + document.documentElement.scrollLeft
+ document.body.scrollLeft;
y = window.event.clientY + document.documentElement.scrollTop
+ document.body.scrollTop;
}
if (browser.isNS) {
x = event.clientX + window.scrollX;
y = event.clientY + window.scrollY;
}
Nótese que los valores del objeto evento clientX y
clientY son relativos al área de visión ('viewport')
de la ventana del navegador, no a la página. Podría darse el
caso en que se hubiese hecho scroll sobre la ventana durante el arrastre,
y quisiésemos obtener la posición del cursor relativa a la
página en si misma. Por lo tanto, le agregaremos los valores actuales
de 'scroll offsets'.
Puedes ver la diferencia por tí mismo haciendo scroll en esta página
y click en cualquier parte de ella. Los valores clientX y
clientY se muestran en la barra de estado de la ventana del navegador
acompañados por los valores calculados de 'page offset'.
document.body como para el objeto document.documentElement
. Pero IE 5 sólo actualiza el par en document.body mientras
que el par en document.documentElement siempre devuelve cero.
IE 6 hace justamente lo contrario.
El código siguiente añade los valores de scroll offset
para ambos objetos, por lo que devolverá los valores correctos independientemente
de la versión.
Netscape almacena los valores de scroll offset de la página como
propiedades del objeto window. A continuación, la función encuentra la posición
del elemento blanco ('target'), usando la parte numérica de sus valores
de estilo left y top. Estos valores se guardan
en dragObj acompañados por las coordenadas del mouse.
// Save starting positions of cursor and element.
dragObj.cursorStartX = x;
dragObj.cursorStartY = y;
dragObj.elStartLeft = parseInt(dragObj.elNode.style.left, 10);
dragObj.elStartTop = parseInt(dragObj.elNode.style.top, 10);
if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0;
if (isNaN(dragObj.elStartTop)) dragObj.elStartTop = 0;
Nótese aquí que si left o top
no se han fijado usando estilos 'inline' en el elemento, el código
asumes que su valor es cero.
Para llevar al elemento a la parte más alta del orden de apilamiento,
el script actualiza su propiedad de estilo zIndex, después
de haber aumentado el valor de dragObj.zIndex.
// Update element's z-index.
dragObj.elNode.style.zIndex = ++dragObj.zIndex;
El último paso es configurar la captura de los eventos mousemove
y mouseup en toda la página, asignándoles los
manejadores dragGo() y dragStop() respectivamente.
// Capture mousemove and mouseup events on the page.
if (browser.isIE) {
document.attachEvent("onmousemove", dragGo);
document.attachEvent("onmouseup", dragStop);
window.event.cancelBubble = true;
window.event.returnValue = false;
}
if (browser.isNS) {
document.addEventListener("mousemove", dragGo, true);
document.addEventListener("mouseup", dragStop, true);
event.preventDefault();
}
El script cancela entonces el burbujeo de eventos actual y cualquier acción por defecto. Normalmente, si arrastras el mouse sobre una página el navegador resaltará una sección de texto o cualquier otro contenido. Deteniendo el evento como hemos hecho prevendremos dicha acción durante el arrastre.