Newsgroup: it.comp.lang.javascript
Titolo: Drag and drop di un clone

Salve ragazzi,
sono di nuovo nel gruppo per un dubbio che ho. Mi servirebbe utilizzare un
effetto di drag and drop (come se ne trovano tantissimi in rete) il
problema č che vorrei trascinare un clone dell'immagine e non l'immagine
reale. Lasciando cosě nella posizione originale l'immagine e trascinare il
clone.
Ho provato a smanettare un po' ma sono riuscito a trascinare l'immagine
reale e creare sotto un clone. Il problema č che tutta la parte di
documento che sta sotto l'immagine "si alza" per effetto del trascinamento
dell'immagine originale. Quando appare il clone, questo appare sopra il
resto della pagina (sono stato chiaro?!)
Come faccio invece a trascinare il clone, lasciando intoccata l'immagine
originale? Ho trovato questo online
http://www.walterzorn.com/dragdrop/commands_e.htm
 ma non riesco a capire
come facciano loro.
Potete aiutarmi?
Grazie a chi legge :o)
Luke S.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 reale. 
// globale
var drag = null;
// quando inizi il drag
drag = sender.cloneNode(false); // sender è l'oggetto che 
				// ha scatenato l'evento
drag.style.position="absolute";
drag.style.left=x+"px";
drag.style.top=y+"px";
document.body.appendChild(drag);
// quando termini il drag
if (drag!=null)
	document.body.removeChild(drag)
drag = null;
e poi sposti drag secondo le coordinate date dall'oggetto event, dentro
l'event-handler onmousemove del document.
Giusto per farti capire il procedimento.
-- 
~ Io non soffro di pazzia, ne godo ogni minuto.
(I don't suffer from insanity, I enjoy every minute of it)

 Giusto per farti capire il procedimento.
Credo di aver capito ciň che intendi, ma fatico ad applicarlo. Ti posto il
codice che ho in mano ora (l'ho scaricato e riadattato alla bene meglio).
Se avessi tempo e voglia di buttarci un occhio, te lo posterei volentieri,
eccolo:
<script language="JavaScript1.2">
<!--
var ie=document.all;
var nn6=document.getElementById&&!document.all;
var isdrag=false;
var x,y;
var dobj;
var mouseX=0, mouseY=0;
var shoppingCartDragOver=false;
function movemouse(e)
{
  if (isdrag)
  {
    dobj.style.left = nn6 ? tx + e.clientX - x : tx + event.clientX - x;
    dobj.style.top  = nn6 ? ty + e.clientY - y : ty + event.clientY - y;
 
    return false;
  }
}
function selectmouse(e) 
{
  var fobj       = nn6 ? e.target : event.srcElement;
  var topelement = nn6 ? "HTML" : "BODY";
  while (fobj.tagName != topelement && fobj.className != "dragme")
  {
    fobj = nn6 ? fobj.parentNode : fobj.parentElement;
  }
  if (fobj.className=="dragme")
  {
    isdrag = true;
    dobj = fobj;
 
	if (dobj.filters) {
		try {
			dobj.style.filter="alpha(opacity=70)";
		} catch (e) { }
	} else if (dobj.style.opacity) {
		dobj.style.opacity = .7;
	}
    tx = parseInt(dobj.style.left+0);
    ty = parseInt(dobj.style.top+0);
    x = nn6 ? e.clientX : event.clientX;
    y = nn6 ? e.clientY : event.clientY;
 
	/* Zer0 helped me from it.comp.lang.javascript */
	dobj=nn6?e.cloneNode(false):event.cloneNode(false); 
	document.body.appendChild(dobj);
    document.onmousemove=movemouse;
    return false;
  }
}
document.onmousedown=selectmouse;
document.onmouseup=function() {
	if (dobj.filters) {
		try {
			dobj.style.filter="alpha(opacity=100)";
		} catch (e) { }
	} else if (dobj.style.opacity) {
		dobj.style.opacity = 1;
	}
	document.body.removeChild(dobj);
	isdrag=false;
}
//-->
</script>
In cosa ho sbagliato? Ti ringrazio ancora :o)
-- 
Luke S.
- may the happiness be with you -


 document.onmouseup=function() {
Prima devi verificare se stai effettivamente draggando qualcosa:
if (dobj!=null){
	document.body.removeChild(dobj);
	dobj = null;
}
Mi raccomando, cerca di capire il codice che ti ho scritto, e non di fare
un semplice "cop'incolla" e vedere che succede. Quello eventualmente lo fai
dopo ;) Se hai dei dubbi, scrivi pure qua.
-- 
~ ..ma in effetti il concetto di WYSIWYG (quello che vedi è quello che
ottieni) si applica ai computer malissimo, così come si applica alle
donne... (The Real Programmer)

 dopo ;) Se hai dei dubbi, scrivi pure qua.
Dunque, ci ho provato e ho ritoccato il codice cercando di seguire al
meglio i tuoi consigli, sono arrivato dove ti posto tra poco. C'è qualcosa
che non va (Firefox dice errore nell'assegnazione della proprietà left -
Explorer mi dice argomento non valido).
Sicuramente hanno ragione loro e altrettanto sicuramente il problema sta
tra la sedia e la tastiera, ma a che linea? :o)
<html>
<head>
<style>
<!--
dragme {
	position:relative;
}
-->
</style>
<script type="text/Javascript">
<!--
var tx,ty,x,y;
var dobj;
function movemouse(e) {
	if (dobj) {
		e=e||event;
 
		dobj.style.left = (tx + e.clientX - x)+"px";
		dobj.style.left = (ty + e.clientY - y)+"px";
 
		return false;
	}
}
function selectmouse(e) {
	e=e||event;
	var fobj = e.srcElement||e.target;
	while (fobj && fobj.tagName!="BODY" && fobj.className!="dragme"){
		fobj = fobj.parentNode;
	}
	if (!fobj) return true;
	if (fobj.className=="dragme") {
		dobj = fobj.cloneNode(false);
 
		dobj.style.position = "absolute";
		x = e.clientX;
		y = e.clientY;
		tx = (e.clientX - x)+"px";
		ty = (e.clientY - y)+"px";
		document.onmousemove=movemouse;
		return false;
	}
}
document.onmousedown=selectmouse;
document.onmouseup=function() {
	document.body.removeChild(dobj);
 
	if (dobj!=null){
		document.body.removeChild(dobj);
		dobj = null;
	}
}
//-->
</script>
</head>
<body>
<img src="1.gif" class="dragme" alt="prova1" />
<br />
<img src="2.gif" class="dragme" alt="prova2" />
</body>
</html>
-- 
Luke S.
- may the free time be with you -


 		dobj.style.left = (ty + e.clientY - y)+"px";
Questo invece è una distrazione mia: ho ricopiato la riga precedente e non
ho cambiato "left" in "top". :)
Ti consiglio comunque quanto detto in precedenza. Ovvero dimentica tutto
quello che hai fatto, perché da quanto posso vedere tu stai procedendo a
tentativi, senza capire realmente ciò che stai facendo.. i tuoi infatti
sono errori dovuti al non aver compreso la logica che sta dietro a questo
codice.
Puoi benissimo realizzare uno script per fare il drag&drop senza capire
necessariamente un'acca di javascript. Ma se il tuo fine è la comprensione,
ed una maggior conoscenza del linguaggio, non è ciò a cui devi mirare.
Se vuoi, posso aiutarti a ripartire da zero su questo script. Affrontando
prima l'analisi, e poi scrivendo il codice relativo.
-- 
~ Se il destino è contro di noi, peggio per lui!

 prima l'analisi, e poi scrivendo il codice relativo.
Hai ragione, credo di avere chiaro solo il funzionamento di base:
onmousedown si rileva quale oggetto abbia scatenato l'evento (e.srcElement
o e.target), onmousemover l'oggetto segue il mouse e onmouseup si
interrompe tutto (se questo tutto ha avuto inizio) - nel mio caso
onmouseup cancello il clone.
Giusto?
Però la logica completa non ce l'ho in mente. Ora quando inizio a draggare
l'immagine, questa si "attacca" al mouse con il suo angolo superiore
sinistro, senza considerare a che punto (dell'immagine) ho iniziato a
trascinarla:
var dobj;
function movemouse(e) {
	if (dobj) {
		e=e||event;
		dobj.style.left = e.clientX+"px";
		dobj.style.top = e.clientY+"px";    		
		return false;
	}
}
function selectmouse(e) {
	e=e||event;
	var fobj = e.srcElement||e.target;
	while (fobj && fobj.tagName!="BODY" && fobj.className!="dragme"){
		fobj = fobj.parentNode;
	}
	if (!fobj) return true;
	if (fobj.className=="dragme") {
		dobj = fobj.cloneNode(false);
		document.body.appendChild(dobj);
		dobj.style.position = "absolute";
 
		document.onmousemove=movemouse;
		return false;
	}
}
document.onmousedown=selectmouse;
document.onmouseup=function() {
 
	if (dobj!=null){
		document.body.removeChild(dobj);
		dobj = null;
	}
}
-- 
Luke S.
- may the force be with you -


 trascinarla:
Ricorda che se sposti l'immagine esattamente nel punto in cui l'hai
cliccata, poi non gli eventi degli elementi che sottostanti non verranno
più scatenati.
Comunque sia: tu adesso vuoi che l'elemento non venga spostato a partire
dal suo angolo superiore sinistro, ma considerando il punto in cui esso
viene cliccato.
Ora, per quanto possa forse sembrarti banale, dovresti innanzitutto capire
come mai si sposta in quel modo; e successivamente, parlando in modo
astratto, dovresti capire di cosa hai bisogno per fare ciò che vorresti.
Ovvero cosa ti manca per poter spostare l'elemento nel modo da te
desiderato.
-- 
~ "Quando i morti camminano, signori, bisogna smettere di uccidere.
O si perde la guerra." (Zombie)

 viene cliccato.
Esatto, l'errore mio sta:
dobj.style.left = e.clientX+"px";
dobj.style.top = e.clientY+"px";
E quindi, ovviamente, l'immagine viene trascinata a partire dall'angolo
superiore sinistro. Evidentemente onmousedown devo risalire alle attuali
coordinate del mouse e poi (onmousemove) spostare l'immagine in base ai
movimenti del mouse, tenendo in considerazione anche le coordinate del
mouse ottenute onmousedown.
Giusto?
Luke S.
- may the dragging be with me -


 mouse ottenute onmousedown.
Appunto, ci sei quasi. Ma non sono le attuali coordinate del mouse in senso
assoluto che ti servono (clientX/clientY, per aprire una parentesi
javascript)... bensì?
-- 
~ "Non ci si uccide per amore, basta aspettare."
"Allora non mi uccido per amore, mi uccido per impazienza." (A.O. e M.T.)

 javascript)... bensì?
Bensì la posizione attuale dell'immagine. Se posso fare un passo avanti e
utilizzare già il codice js, onmousedown sarebbe:
xMouse = e.clientX;
yMouse = e.clientY;
dobj = fobj.cloneNode(false);
document.body.appendChild(dobj);
dobj.style.position = "absolute";
xImage=fobj.offsetLeft;
yImage=fobj.offsetTop;
dobj.style.left=xImage;
dobj.style.top=yImage;
e onmousemove:
dobj.style.left = xImage+e.clientX-(+xMouse)+"px";
dobj.style.top = yImage+e.clientY-(+yMouse)+"px";
"catturati" precedentemente, durante l'onmousedown.
-- 
Luke S.
- may the fantasy (for the signature) be with me -


 dobj.style.top = yImage+e.clientY-(+yMouse)+"px";
L'hai provato questo codice? Perché già così si dovrebbe vedere che non fa
quel che desideri. Se poi consideri che l'elemento da draggare potrebbe
essere contenuto in altri elementi posizionati diversamente, il problema
sarebbe ancora più evidente.
Ad esempio, inserendo l'immagine dentro un div posizionato a sua volta in
modo assoluto e con coordinate top/left di, chessò, 100px e 100px.
 
-- 
~ Se i miei cattivi pensieri non fossero caricati a salve,
ogni giorno sarebbe una strage.

 modo assoluto e con coordinate top/left di, chessò, 100px e 100px.
In effetti così non funziona - o meglio - il dragging parte dall'angolo
superiore sinistro, e l'effetto è inaccettabile.
Luke S.


 superiore sinistro, e l'effetto è inaccettabile.
Eggià. :)
-- 
Peace is a lie, there is only passion. Through passion, I gain strength.
Through strength, I gain power. Through power, I gain victory.
Through victory, my chains are broken. The Force shall free me. (Sith Code)

 e ricorda che il tuo indice punta sempre le coordinate zero e zero.
L'angolo superiore sinistro del foglio si troverà 5 colonne più a sinistra
e 7 righe più in alto rispetto al mio indice.


 e 7 righe più in alto rispetto al mio indice.
Esatto. Quindi, se stessimo ragionando matematicamente su un asse cartesiana?
Quale sarebbe il loro segno?
E, una volta che ha risposto a questo, per fare già un passo in avanti, se
supponiamo che il foglio sia a sua volta poggiato su un altro foglio molto più
grande suddiviso anch'esso in quadretti, e che l'angolo superiore sinistro di
questo "foglione" siano le coordinate zero/zero, e ti dicessi di spostare
l'indice sul quadretto relativo alla quindicesima colonna e dodicesima riga, e
poi di spostare anche il "foglietto" (quello con il segno) di conseguenza,
mantenendo il tuo indice sul segno che hai fatto in precedenza?
Il tuo dito si troverebbe quindi sulla quindicesima colonna e dodicesima riga,
mentre l'angolo superiore del foglietto, relativamente al "foglione", dove si
troverebbe?
Una volta risposto anche a questo, la domanda seguente è: come hai fatto a
capire dove spostare il foglietto, sopra il foglione, in modo tale che
l'indice fosse sempre sul punto segnato a matita?


 l'indice fosse sempre sul punto segnato a matita?
So le coordinate del mio indice sul foglietto (5,7) e so le coordinate 0,0
del foglio piccolo (che corrispondono a 10,5 del grande) e sommandoli so
dove mi trovo e come spostarmi.


 dove mi trovo e come spostarmi.
Argh, ti sei rovinato alla fine. Hai fatto l'inverso di quello che ti ho
chiesto.
Tu sai già dove spostarti. Le coordinate te l'ho date io.
Io ti chiesto come hai fatto a capire dove spostare il foglietto, non
l'indice.
Ovvero ciò che mi hai risposto prima (10,5).
Ergo, quest'informazione non la sai, è ciò che ricavi.
Ciò che sai sono le coordinate del tuo indice sul foglietto (5,7), sai le
coordinate dove devi porre l'indice (15,12). Ti rifaccio quindi la domanda.
Come hai fatto a capire, in base alle coordinate che io ti ho dato (15,12) a
capire DOVE porre il foglietto?
Hai già fatto tutti i conti del caso, hai solo invertito i conti alla fine. :)


 capire DOVE porre il foglietto?
Ho sottratto.


 Ho sottratto.
Hai visto che per l'analisi, non c'era alcun bisogno di utilizzare nessun tipo
di linguaggio?
Ora trasliamo ciò che abbiamo fatto fin'ora, in termini "computerecci".
Il "foglione", ovviamente, è la pagina.
Il "foglietto", ciò che devi spostare.
Il "dito indice", il puntatore del mouse.
I "quadretti", i pixel.
Le coordinate 15,12 sono le coordinate in pixel in cui si trova attualmente il
puntatore.
A te l'onere di definirmi le altre due coppie di coordinate a cosa si
riferiscono. :)
Adesso dovresti aver ben chiaro cosa ti manca per portare il tutto in JS.
-- 
~ "Viviamo nei vuoti lasciati da qualcun'altro."

 Ho sottratto.
Hai visto che per l'analisi, non c'era alcun bisogno di utilizzare nessun tipo


 Ho sottratto.
Hai visto che per l'analisi, non c'era alcun bisogno di utilizzare nessun tipo


 riferiscono. :)
Spero di aver fatto correttamente
-- 
Luke S.
- may the xmas be with you -


 Spero di aver fatto correttamente
No, hai perseverato nell'errore che già avevi fatto :P
Riprova :)
-- 
.ZER0//sign
"When you have eliminated the impossible, whatever remains,
however improbable, must be the truth." (S.H.)
on air ~ "Oliver Onions - Sheriff"

 ottenere, e cosa ti manca.
Il problema è che mi manca avere le coordinate del mio indice sul
foglietto, ovvero le coordinate del mouse rispetto all'immagine.
Cioè io sono a 15,12 del foglio grande (e quindi della pagina) e
contemporaneamente sono a 5,7 del piccolo (ovvero dell'immagine). Ma come
faccio ad ottenere questo dato (5,7) in javascript?
Con questo dato alla mano, mi basta sottrarre i due valori per sapere le
coordinate dell'immagine (10,5).
Il mio errore era partire dalle coordinate dell'immagine (che invece è il
risultato di tutto, non uno degli operandi). Ma come faccio in JS ad
ottenere quel 5,7?
Ottenute queste, basterebbe appunto sottrarre. Ci sono?
-- 
Luke S.
- may the force be with you -


 Ottenute queste, basterebbe appunto sottrarre. Ci sono?
Si, ci sei :)
Adesso devi quindi cercare nelle reference se c'è qualcosa che ti
restituisce tali informazioni.
Ovviamente, in quanto sono coordinate relative all'evento, ti suggerisco di
cercarle nell'oggetto "event" ;)


 cercarle nell'oggetto "event" ;)
Dunque, per explorer ho trovato: offsetY e offsetX. Per Firefox invece mi
sono bloccato: ho seguito il tuo consiglio e sulla reference ho trovato
http://developer.mozilla.org/en/docs/DOM:event
 ed esistono alcune
proprietà che mi stuzzicano. A parte clientX e clientY che rilevano le
coordinate del mouse (in questo caso), ho davanti:
event.layerX 
event.layerY
Che però parla di layer (purtroppo la reference non fa esempi per queste
due proprietà), dicendo solo "Returns the horizontal/vertical coordinate
of the event relative to the current layer". Con "layer corrente" cosa
intende?
Poi ci sono:
event.pageX
event.pageY
La reference (anche qui purtroppo senza esempio) riporta: "Returns the
horizontal/vertical coordinate of the event relative to the visible page."
Con "relativo alla pagina visibile" penso intenda la schermata visibile
durante lo scrolling e anche con una pagina "scrollata" (come si dice in
italiano? scrollata non mi sembra corretto) l'angolo superiore sinistro
sarà 0,0 (proprio perché relativo alla parte di pagina visibile, senza
sommare lo scrolling).
Poi però per curiosità ho provato questo pageX/Y e ritorna le coordinate
considerando lo scrolling, quindi l'opposto di ciò che pensavo di aver
capito dalla reference. Sbaglio io o la reference non è chiara qui?
Comunque, continuando nelle proprietà di event, ci sono:
event.screenX
event.screenY
Che però fanno riferimento all'intero schermo e quindi non fanno per me.
Fatta tutta questa analisi, come mi muovo? Ho pensato: "guardiamo un po'
se qualcuno ha trovato una soluzione prima di me"... e ho trovato la
soluzione con layerX/Y, qualcosa tipo:
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
A me però e.layerX/Y non mi da le coordinate relative all'immagine come
fanno offsetX/Y su explorer.
Cosa sbaglio (ancora)?
-- 
Luke S.
- may the coords be with you -


 Cosa sbaglio (ancora)?
L'immagine in questione deve avere position absolute o relative. 
-- 
~ "Viviamo dei vuoti lasciati da qualcun'altro."

 Un "layer" è un elemento che ha position absolute o relative.
Ah ecco... non lo sapevo. Posto il codice finale, magari a qualcun altro
può servire (e magari mi dici se va bene o c'è ancora da sistemare):
var mouseXobj,mouseYobj;
var objTarget;
document.onmouseup=function() {
	if (objTarget.className=="dragme") {
		document.body.removeChild(objTarget);
		objTarget=undefined;
	}
 
}
document.onmousemove=function(e) {
 
	var e=e||event;
 
	if (objTarget!=undefined) {
		objTarget.style.position="absolute";
		objTarget.style.left=e.clientX-mouseXobj+"px";
		objTarget.style.top=e.clientY-mouseYobj+"px";
		return false;
	} else {
		return true;
	}
}
document.onmousedown=function(e) {
 
	var e=e||event;
 
	objTarget=e.srcElement||e.target;
 
	if (objTarget.className=="dragme") {
		mouseXobj=e.offsetX||e.layerX||0;
		mouseYobj=e.offsetY||e.layerY||0;
		objTarget=objTarget.cloneNode(false);
		objTarget.style.position="absolute";
		objTarget.style.left=e.clientX-mouseXobj+"px";
		objTarget.style.top=e.clientY-mouseYobj+"px";
		document.body.appendChild(objTarget);
 
		return false;
 
	}
}
-- 
Luke S.


 		objTarget.style.left=e.clientX-mouseXobj+"px";
In questo tipo di operazioni ti conviene separare la parte numerica dalla
stringa. Primo, per un discorso di leggibilità. Secondo, perché altrimenti
rischi di prenderla come abitudine, e di utilizzarla anche per la somma e in
quel caso avresti un errore di proporzioni apocalittiche. Per spiegarmi, se tu
avessi avuto:
objTarget.style.left=e.clientX+mouseXobj+"px";
con e.clientX uguale a 300 e mouseXobj uguale a 10, avresti assegnato a left
il valore di 30010px.
Per questo, ti conviene sempre - come ti avevo già mostrato - fare qualcosa
del tipo:
	objTarget.style.left=( e.clientX - mouseXobj ) + "px";
Anche nel caso di somme, avresti il valore corretto.



per implementare il drag&drop nella loro home page
-- 
Le aquile non volano a stormi

 per implementare il drag&drop nella loro home page
In modo del tutto similare, ti assicuro. Il procedimento è lo stesso, a
prescindere da quante variazioni sul tema si possa fare.
-- 
~ Se il destino è contro di noi, peggio per lui!